Commit 302b7a7d by Tobias Munk

Merge commit '1ccad3d9' into feature/composer-docs

parents 36b41bad 1ccad3d9
...@@ -149,7 +149,7 @@ $email = $customer->email; ...@@ -149,7 +149,7 @@ $email = $customer->email;
To change the value of a column, assign a new value to the associated property and save the object: To change the value of a column, assign a new value to the associated property and save the object:
``` ```php
$customer->email = 'jane@example.com'; $customer->email = 'jane@example.com';
$customer->save(); $customer->save();
``` ```
......
...@@ -114,9 +114,11 @@ There are several classes provided by framework: ...@@ -114,9 +114,11 @@ There are several classes provided by framework:
- FileHelper - FileHelper
- Html - Html
- HtmlPurifier - HtmlPurifier
- Image
- Inflector - Inflector
- Json - Json
- Markdown - Markdown
- Security - Security
- StringHelper - StringHelper
- Url
- VarDumper - VarDumper
...@@ -120,7 +120,7 @@ adjust directory permissions so that your webserver is able to write to the dire ...@@ -120,7 +120,7 @@ adjust directory permissions so that your webserver is able to write to the dire
> Note: The code generated by gii is only a template that has to be adjusted to your needs. It is there > Note: The code generated by gii is only a template that has to be adjusted to your needs. It is there
to help you create new things quickly but it is not something that creates ready to use code. to help you create new things quickly but it is not something that creates ready to use code.
We often see people using the models generated by gii without change and just extend them to adjust We often see people using the models generated by gii without change and just extend them to adjust
some parts of it. This is not how it is ment to be used. Code generated by gii may be incomplete or incorrect some parts of it. This is not how it is meant to be used. Code generated by gii may be incomplete or incorrect
and has to be changed to fit your needs before you can use it. and has to be changed to fit your needs before you can use it.
......
...@@ -657,8 +657,7 @@ After a user is authenticated, you probably want to check if he has the permissi ...@@ -657,8 +657,7 @@ After a user is authenticated, you probably want to check if he has the permissi
action for the requested resource. This process is called *authorization* which is covered in detail in action for the requested resource. This process is called *authorization* which is covered in detail in
the [Authorization chapter](authorization.md). the [Authorization chapter](authorization.md).
You may use the [[yii\web\AccessControl]] filter and/or the Role-Based Access Control (RBAC) component You may use the Role-Based Access Control (RBAC) component to implementation authorization.
to implementation authorization.
To simplify the authorization check, you may also override the [[yii\rest\Controller::checkAccess()]] method To simplify the authorization check, you may also override the [[yii\rest\Controller::checkAccess()]] method
and then call this method in places where authorization is needed. By default, the built-in actions provided and then call this method in places where authorization is needed. By default, the built-in actions provided
......
...@@ -19,7 +19,7 @@ Creating URLs ...@@ -19,7 +19,7 @@ Creating URLs
------------- -------------
The most important rule for creating URLs in your site is to always do so using the URL manager. The URL manager is a built-in application component named `urlManager`. This component is accessible from both web and console applications via The most important rule for creating URLs in your site is to always do so using the URL manager. The URL manager is a built-in application component named `urlManager`. This component is accessible from both web and console applications via
`\Yii::$app->urlManager`. The component makes availabe the two following URL creation methods: `\Yii::$app->urlManager`. The component makes available the two following URL creation methods:
- `createUrl($params)` - `createUrl($params)`
- `createAbsoluteUrl($params, $schema = null)` - `createAbsoluteUrl($params, $schema = null)`
......
Yii2 Core framework code style Yii2 Core framework code style
============================== ==============================
The following code style is used for Yii 2.x core and official extensions development. If you want to pull-request code into the core, consider using it. We aren't forcing you to use this code style for your application. Feel free to choose what suits you better. The following code style is used for Yii 2.x core and official extensions development. If you want to pull-request code
into the core, consider using it. We aren't forcing you to use this code style for your application. Feel free to choose
what suits you better.
You can get a config for CodeSniffer here: https://github.com/yiisoft/yii2-coding-standards You can get a config for CodeSniffer here: https://github.com/yiisoft/yii2-coding-standards
1. Overview 1. Overview
----------- -----------
Overall we're using [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
compatible style so everything that applies to
[PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) is applied to our code
style as well.
- Files MUST use either `<?php` or `<?=` tags. - Files MUST use either `<?php` or `<?=` tags.
- There should be a newline at the end of file. - There should be a newline at the end of file.
- Files MUST use only UTF-8 without BOM for PHP code. - Files MUST use only UTF-8 without BOM for PHP code.
- Code MUST use tabs for indenting, not spaces. - Code MUST use 4 spaces for indenting, not tabs.
- Class names MUST be declared in `StudlyCaps`. - Class names MUST be declared in `StudlyCaps`.
- Class constants MUST be declared in all upper case with underscore separators. - Class constants MUST be declared in all upper case with underscore separators.
- Method names MUST be declared in `camelCase`. - Method names MUST be declared in `camelCase`.
......
(function() { (function () {
var ajax = function(url, settings) { var ajax = function (url, settings) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP'); var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
settings = settings || {}; settings = settings || {};
xhr.open(settings.method || 'GET', url, true); xhr.open(settings.method || 'GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(state) { xhr.onreadystatechange = function (state) {
if (xhr.readyState == 4) { if (xhr.readyState == 4) {
if (xhr.status == 200 && settings.success) { if (xhr.status == 200 && settings.success) {
settings.success(xhr); settings.success(xhr);
} else if (xhr.status != 200 && settings.error) { } else if (xhr.status != 200 && settings.error) {
settings.error(xhr); settings.error(xhr);
} }
} }
}; };
xhr.send(settings.data || ''); xhr.send(settings.data || '');
}; };
var e = document.getElementById('yii-debug-toolbar'); var e = document.getElementById('yii-debug-toolbar');
if (e) { if (e) {
e.style.display = 'block'; e.style.display = 'block';
var url = e.getAttribute('data-url'); var url = e.getAttribute('data-url');
ajax(url, { ajax(url, {
success: function(xhr) { success: function (xhr) {
var div = document.createElement('div'); var div = document.createElement('div');
div.innerHTML = xhr.responseText; div.innerHTML = xhr.responseText;
e.parentNode.replaceChild(div, e); e.parentNode.replaceChild(div, e);
if (window.localStorage) { if (window.localStorage) {
var pref = localStorage.getItem('yii-debug-toolbar'); var pref = localStorage.getItem('yii-debug-toolbar');
if (pref == 'minimized') { if (pref == 'minimized') {
document.getElementById('yii-debug-toolbar').style.display = 'none'; document.getElementById('yii-debug-toolbar').style.display = 'none';
document.getElementById('yii-debug-toolbar-min').style.display = 'block'; document.getElementById('yii-debug-toolbar-min').style.display = 'block';
} }
} }
}, },
error: function(xhr) { error: function (xhr) {
e.innerHTML = xhr.responseText; e.innerHTML = xhr.responseText;
} }
}); });
} }
})(); })();
...@@ -13,16 +13,16 @@ echo DetailView::widget([ ...@@ -13,16 +13,16 @@ echo DetailView::widget([
'to', 'to',
'charset', 'charset',
[ [
'name' => 'time', 'attribute' => 'time',
'value' => $timeFormatter->asDateTime($model['time'], 'short'), 'value' => $timeFormatter->asDateTime($model['time'], 'short'),
], ],
'subject', 'subject',
[ [
'name' => 'body', 'attribute' => 'body',
'label' => 'Text body', 'label' => 'Text body',
], ],
[ [
'name' => 'isSuccessful', 'attribute' => 'isSuccessful',
'label' => 'Successfully sent', 'label' => 'Successfully sent',
'value' => $model['isSuccessful'] ? 'Yes' : 'No' 'value' => $model['isSuccessful'] ? 'Yes' : 'No'
], ],
...@@ -30,7 +30,7 @@ echo DetailView::widget([ ...@@ -30,7 +30,7 @@ echo DetailView::widget([
'bcc', 'bcc',
'cc', 'cc',
[ [
'name' => 'file', 'attribute' => 'file',
'format' => 'html', 'format' => 'html',
'value' => Html::a('Download eml', ['download-mail', 'file' => $model['file']]), 'value' => Html::a('Download eml', ['download-mail', 'file' => $model['file']]),
], ],
......
yii.gii = (function ($) { yii.gii = (function ($) {
var isActive = $('.default-view').length > 0; var isActive = $('.default-view').length > 0;
var initHintBlocks = function () { var initHintBlocks = function () {
$('.hint-block').each(function () { $('.hint-block').each(function () {
var $hint = $(this); var $hint = $(this);
$hint.parent().find('label').addClass('help').popover({ $hint.parent().find('label').addClass('help').popover({
html: true, html: true,
trigger: 'hover', trigger: 'hover',
placement: 'right', placement: 'right',
content: $hint.html() content: $hint.html()
}); });
}); });
}; };
var initStickyInputs = function () { var initStickyInputs = function () {
$('.sticky:not(.error)').find('input[type="text"],select,textarea').each(function () { $('.sticky:not(.error)').find('input[type="text"],select,textarea').each(function () {
var value; var value;
if (this.tagName === 'SELECT') { if (this.tagName === 'SELECT') {
value = this.options[this.selectedIndex].text; value = this.options[this.selectedIndex].text;
} else if (this.tagName === 'TEXTAREA') { } else if (this.tagName === 'TEXTAREA') {
value = $(this).html(); value = $(this).html();
} else { } else {
value = $(this).val(); value = $(this).val();
} }
if (value === '') { if (value === '') {
value = '[empty]'; value = '[empty]';
} }
$(this).before('<div class="sticky-value">' + value + '</div>').hide(); $(this).before('<div class="sticky-value">' + value + '</div>').hide();
}); });
$('.sticky-value').on('click', function () { $('.sticky-value').on('click', function () {
$(this).hide(); $(this).hide();
$(this).next().show().get(0).focus(); $(this).next().show().get(0).focus();
}); });
}; };
var initPreviewDiffLinks = function () { var initPreviewDiffLinks = function () {
$('.preview-code, .diff-code, .modal-refresh, .modal-previous, .modal-next').on('click', function () { $('.preview-code, .diff-code, .modal-refresh, .modal-previous, .modal-next').on('click', function () {
var $modal = $('#preview-modal'); var $modal = $('#preview-modal');
var $link = $(this); var $link = $(this);
$modal.find('.modal-refresh').attr('href', $link.attr('href')); $modal.find('.modal-refresh').attr('href', $link.attr('href'));
if ($link.hasClass('preview-code') || $link.hasClass('diff-code')) { if ($link.hasClass('preview-code') || $link.hasClass('diff-code')) {
$modal.data('action', ($link.hasClass('preview-code') ? 'preview-code' : 'diff-code')) $modal.data('action', ($link.hasClass('preview-code') ? 'preview-code' : 'diff-code'))
} }
$modal.find('.modal-title').text($link.data('title')); $modal.find('.modal-title').text($link.data('title'));
$modal.find('.modal-body').html('Loading ...'); $modal.find('.modal-body').html('Loading ...');
$modal.modal('show'); $modal.modal('show');
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
cache: false, cache: false,
url: $link.prop('href'), url: $link.prop('href'),
data: $('.default-view form').serializeArray(), data: $('.default-view form').serializeArray(),
success: function (data) { success: function (data) {
if (!$link.hasClass('modal-refresh')) { if (!$link.hasClass('modal-refresh')) {
var filesSelector = 'a.' + $modal.data('action'); var filesSelector = 'a.' + $modal.data('action');
var $files = $(filesSelector); var $files = $(filesSelector);
var index = $files.filter('[href="' + $link.attr('href') + '"]').index(filesSelector); var index = $files.filter('[href="' + $link.attr('href') + '"]').index(filesSelector);
var $prev = $files.eq(index-1); var $prev = $files.eq(index - 1);
var $next = $files.eq((index+1 == $files.length ? 0 : index+1)); var $next = $files.eq((index + 1 == $files.length ? 0 : index + 1));
$modal.find('.modal-previous').attr('href', $prev.attr('href')).data('title', $prev.data('title')); $modal.find('.modal-previous').attr('href', $prev.attr('href')).data('title', $prev.data('title'));
$modal.find('.modal-next').attr('href', $next.attr('href')).data('title', $next.data('title')); $modal.find('.modal-next').attr('href', $next.attr('href')).data('title', $next.data('title'));
} }
$modal.find('.modal-body').html(data); $modal.find('.modal-body').html(data);
$modal.find('.content').css('max-height', ($(window).height() - 200) + 'px'); $modal.find('.content').css('max-height', ($(window).height() - 200) + 'px');
}, },
error: function (XMLHttpRequest, textStatus, errorThrown) { error: function (XMLHttpRequest, textStatus, errorThrown) {
$modal.find('.modal-body').html('<div class="error">' + XMLHttpRequest.responseText + '</div>'); $modal.find('.modal-body').html('<div class="error">' + XMLHttpRequest.responseText + '</div>');
} }
}); });
return false; return false;
}); });
$('#preview-modal').on('keydown', function(e) { $('#preview-modal').on('keydown', function (e) {
if (e.keyCode === 37) { if (e.keyCode === 37) {
$('.modal-previous').trigger('click'); $('.modal-previous').trigger('click');
} else if(e.keyCode === 39) { } else if (e.keyCode === 39) {
$('.modal-next').trigger('click'); $('.modal-next').trigger('click');
} else if(e.keyCode === 82) { } else if (e.keyCode === 82) {
$('.modal-refresh').trigger('click'); $('.modal-refresh').trigger('click');
} }
}); });
}; };
var initConfirmationCheckboxes = function () { var initConfirmationCheckboxes = function () {
var $checkAll = $('#check-all'); var $checkAll = $('#check-all');
$checkAll.click(function () { $checkAll.click(function () {
$('.default-view-files table .check input').prop('checked', this.checked); $('.default-view-files table .check input').prop('checked', this.checked);
}); });
$('.default-view-files table .check input').click(function () { $('.default-view-files table .check input').click(function () {
$checkAll.prop('checked', !$('.default-view-files table .check input:not(:checked)').length); $checkAll.prop('checked', !$('.default-view-files table .check input:not(:checked)').length);
}); });
$checkAll.prop('checked', !$('.default-view-files table .check input:not(:checked)').length); $checkAll.prop('checked', !$('.default-view-files table .check input:not(:checked)').length);
}; };
return { return {
autocomplete: function (counter, data) { autocomplete: function (counter, data) {
var datum = new Bloodhound({ var datum = new Bloodhound({
datumTokenizer: function(d){return Bloodhound.tokenizers.whitespace(d.word);}, datumTokenizer: function (d) {
queryTokenizer: Bloodhound.tokenizers.whitespace, return Bloodhound.tokenizers.whitespace(d.word);
local: data },
}); queryTokenizer: Bloodhound.tokenizers.whitespace,
datum.initialize(); local: data
jQuery('.typeahead-'+counter).typeahead(null,{displayKey: 'word', source: datum.ttAdapter()}); });
}, datum.initialize();
init: function () { jQuery('.typeahead-' + counter).typeahead(null, {displayKey: 'word', source: datum.ttAdapter()});
initHintBlocks(); },
initStickyInputs(); init: function () {
initPreviewDiffLinks(); initHintBlocks();
initConfirmationCheckboxes(); initStickyInputs();
initPreviewDiffLinks();
initConfirmationCheckboxes();
// model generator: hide class name input when table name input contains * // model generator: hide class name input when table name input contains *
$('#model-generator #generator-tablename').on('change', function () { $('#model-generator #generator-tablename').on('change',function () {
$('#model-generator .field-generator-modelclass').toggle($(this).val().indexOf('*') == -1); $('#model-generator .field-generator-modelclass').toggle($(this).val().indexOf('*') == -1);
}).change(); }).change();
// hide Generate button if any input is changed // hide Generate button if any input is changed
$('.default-view .form-group input,select,textarea').change(function () { $('.default-view .form-group input,select,textarea').change(function () {
$('.default-view-results,.default-view-files').hide(); $('.default-view-results,.default-view-files').hide();
$('.default-view button[name="generate"]').hide(); $('.default-view button[name="generate"]').hide();
}); });
$('.module-form #generator-moduleclass').change(function () { $('.module-form #generator-moduleclass').change(function () {
var value = $(this).val().match(/(\w+)\\\w+$/); var value = $(this).val().match(/(\w+)\\\w+$/);
var $idInput = $('#generator-moduleid'); var $idInput = $('#generator-moduleid');
if (value && value[1] && $idInput.val() == '') { if (value && value[1] && $idInput.val() == '') {
$idInput.val(value[1]); $idInput.val(value[1]);
} }
}); });
} }
}; };
})(jQuery); })(jQuery);
...@@ -70,7 +70,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas ...@@ -70,7 +70,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/** /**
* Displays a single <?= $modelClass ?> model. * Displays a single <?= $modelClass ?> model.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?> * <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed * @return mixed
*/ */
public function actionView(<?= $actionParams ?>) public function actionView(<?= $actionParams ?>)
...@@ -101,7 +101,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas ...@@ -101,7 +101,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/** /**
* Updates an existing <?= $modelClass ?> model. * Updates an existing <?= $modelClass ?> model.
* If update is successful, the browser will be redirected to the 'view' page. * If update is successful, the browser will be redirected to the 'view' page.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?> * <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed * @return mixed
*/ */
public function actionUpdate(<?= $actionParams ?>) public function actionUpdate(<?= $actionParams ?>)
...@@ -120,7 +120,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas ...@@ -120,7 +120,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/** /**
* Deletes an existing <?= $modelClass ?> model. * Deletes an existing <?= $modelClass ?> model.
* If deletion is successful, the browser will be redirected to the 'index' page. * If deletion is successful, the browser will be redirected to the 'index' page.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?> * <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed * @return mixed
*/ */
public function actionDelete(<?= $actionParams ?>) public function actionDelete(<?= $actionParams ?>)
...@@ -133,7 +133,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas ...@@ -133,7 +133,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/** /**
* Finds the <?= $modelClass ?> model based on its primary key value. * Finds the <?= $modelClass ?> model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown. * If the model is not found, a 404 HTTP exception will be thrown.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?> * <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return <?= $modelClass ?> the loaded model * @return <?= $modelClass ?> the loaded model
* @throws NotFoundHttpException if the model cannot be found * @throws NotFoundHttpException if the model cannot be found
*/ */
......
...@@ -33,12 +33,12 @@ use <?= ltrim($generator->modelClass, '\\') . (isset($modelAlias) ? " as $modelA ...@@ -33,12 +33,12 @@ use <?= ltrim($generator->modelClass, '\\') . (isset($modelAlias) ? " as $modelA
*/ */
class <?= $searchModelClass ?> extends Model class <?= $searchModelClass ?> extends Model
{ {
public $<?= implode(";\n\tpublic $", $searchAttributes) ?>; public $<?= implode(";\n public $", $searchAttributes) ?>;
public function rules() public function rules()
{ {
return [ return [
<?= implode(",\n\t\t\t", $rules) ?>, <?= implode(",\n ", $rules) ?>,
]; ];
} }
...@@ -65,7 +65,7 @@ class <?= $searchModelClass ?> extends Model ...@@ -65,7 +65,7 @@ class <?= $searchModelClass ?> extends Model
return $dataProvider; return $dataProvider;
} }
<?= implode("\n\t\t", $searchConditions) ?> <?= implode("\n ", $searchConditions) ?>
return $dataProvider; return $dataProvider;
} }
......
...@@ -33,11 +33,11 @@ use yii\widgets\ActiveForm; ...@@ -33,11 +33,11 @@ use yii\widgets\ActiveForm;
<?= "<?php " ?>$form = ActiveForm::begin(); ?> <?= "<?php " ?>$form = ActiveForm::begin(); ?>
<?php foreach ($safeAttributes as $attribute) { <?php foreach ($safeAttributes as $attribute) {
echo "\t\t<?= " . $generator->generateActiveField($attribute) . " ?>\n\n"; echo " <?= " . $generator->generateActiveField($attribute) . " ?>\n\n";
} ?> } ?>
<div class="form-group"> <div class="form-group">
<?= "<?= " ?>Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> <?= "<?= " ?>Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div> </div>
<?= "<?php " ?>ActiveForm::end(); ?> <?= "<?php " ?>ActiveForm::end(); ?>
......
...@@ -32,16 +32,16 @@ use yii\widgets\ActiveForm; ...@@ -32,16 +32,16 @@ use yii\widgets\ActiveForm;
$count = 0; $count = 0;
foreach ($generator->getColumnNames() as $attribute) { foreach ($generator->getColumnNames() as $attribute) {
if (++$count < 6) { if (++$count < 6) {
echo "\t\t<?= " . $generator->generateActiveSearchField($attribute) . " ?>\n\n"; echo " <?= " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
} else { } else {
echo "\t\t<?php // echo " . $generator->generateActiveSearchField($attribute) . " ?>\n\n"; echo " <?php // echo " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
} }
} }
?> ?>
<div class="form-group"> <div class="form-group">
<?= "<?= " ?>Html::submitButton('Search', ['class' => 'btn btn-primary']) ?> <?= "<?= " ?>Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= "<?= " ?>Html::resetButton('Reset', ['class' => 'btn btn-default']) ?> <?= "<?= " ?>Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div> </div>
<?= "<?php " ?>ActiveForm::end(); ?> <?= "<?php " ?>ActiveForm::end(); ?>
......
...@@ -48,18 +48,18 @@ $count = 0; ...@@ -48,18 +48,18 @@ $count = 0;
if (($tableSchema = $generator->getTableSchema()) === false) { if (($tableSchema = $generator->getTableSchema()) === false) {
foreach ($generator->getColumnNames() as $name) { foreach ($generator->getColumnNames() as $name) {
if (++$count < 6) { if (++$count < 6) {
echo "\t\t\t'" . $name . "',\n"; echo " '" . $name . "',\n";
} else { } else {
echo "\t\t\t// '" . $name . "',\n"; echo " // '" . $name . "',\n";
} }
} }
} else { } else {
foreach ($tableSchema->columns as $column) { foreach ($tableSchema->columns as $column) {
$format = $generator->generateColumnFormat($column); $format = $generator->generateColumnFormat($column);
if (++$count < 6) { if (++$count < 6) {
echo "\t\t\t'" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n"; echo " '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
} else { } else {
echo "\t\t\t// '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n"; echo " // '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
} }
} }
} }
......
...@@ -46,12 +46,12 @@ $this->params['breadcrumbs'][] = $this->title; ...@@ -46,12 +46,12 @@ $this->params['breadcrumbs'][] = $this->title;
<?php <?php
if (($tableSchema = $generator->getTableSchema()) === false) { if (($tableSchema = $generator->getTableSchema()) === false) {
foreach ($generator->getColumnNames() as $name) { foreach ($generator->getColumnNames() as $name) {
echo "\t\t\t'" . $name . "',\n"; echo " '" . $name . "',\n";
} }
} else { } else {
foreach ($generator->getTableSchema()->columns as $column) { foreach ($generator->getTableSchema()->columns as $column) {
$format = $generator->generateColumnFormat($column); $format = $generator->generateColumnFormat($column);
echo "\t\t\t'" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n"; echo " '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
} }
} }
?> ?>
......
...@@ -45,7 +45,7 @@ class <?= $className ?> extends <?= '\\' . ltrim($generator->baseClass, '\\') . ...@@ -45,7 +45,7 @@ class <?= $className ?> extends <?= '\\' . ltrim($generator->baseClass, '\\') .
*/ */
public function rules() public function rules()
{ {
return [<?= "\n\t\t\t" . implode(",\n\t\t\t", $rules) . "\n\t\t" ?>]; return [<?= "\n " . implode(",\n ", $rules) . "\n " ?>];
} }
/** /**
......
...@@ -59,6 +59,7 @@ Yii Framework 2 Change Log ...@@ -59,6 +59,7 @@ Yii Framework 2 Change Log
- Bug #2695: Fixed the issue that `FileValidator::isEmpty()` always returns true for validate multiple files (ZhandosKz) - Bug #2695: Fixed the issue that `FileValidator::isEmpty()` always returns true for validate multiple files (ZhandosKz)
- Bug #2739: Fixed the issue that `CreateAction::run()` was using obsolete `Controller::createAbsoluteUrl()` method (tonydspaniard) - Bug #2739: Fixed the issue that `CreateAction::run()` was using obsolete `Controller::createAbsoluteUrl()` method (tonydspaniard)
- Bug #2740: Fixed the issue that `CaptchaAction::run()` was using obsolete `Controller::createUrl()` method (tonydspaniard) - Bug #2740: Fixed the issue that `CaptchaAction::run()` was using obsolete `Controller::createUrl()` method (tonydspaniard)
- Bug #2760: Fixed GridView `filterUrl` parameters (qiangxue, AlexGx)
- Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark) - Bug: Fixed `Call to a member function registerAssetFiles() on a non-object` in case of wrong `sourcePath` for an asset bundle (samdark)
- Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark) - Bug: Fixed incorrect event name for `yii\jui\Spinner` (samdark)
- Bug: Json::encode() did not handle objects that implement JsonSerializable interface correctly (cebe) - Bug: Json::encode() did not handle objects that implement JsonSerializable interface correctly (cebe)
...@@ -72,6 +73,7 @@ Yii Framework 2 Change Log ...@@ -72,6 +73,7 @@ Yii Framework 2 Change Log
- Bug: `Query::queryScalar` wasn't making `SELECT DISTINCT` queries subqueries (jom) - Bug: `Query::queryScalar` wasn't making `SELECT DISTINCT` queries subqueries (jom)
- Enh #46: Added Image extension based on [Imagine library](http://imagine.readthedocs.org) (tonydspaniard) - Enh #46: Added Image extension based on [Imagine library](http://imagine.readthedocs.org) (tonydspaniard)
- Enh #364: Improve Inflector::slug with `intl` transliteration. Improved transliteration char map. (tonydspaniard) - Enh #364: Improve Inflector::slug with `intl` transliteration. Improved transliteration char map. (tonydspaniard)
- Enh #497: Removed `\yii\log\Target::logUser` and added `\yii\log\Target::prefix` to support customizing message prefix (qiangxue)
- Enh #797: Added support for validating multiple columns by `UniqueValidator` and `ExistValidator` (qiangxue) - Enh #797: Added support for validating multiple columns by `UniqueValidator` and `ExistValidator` (qiangxue)
- Enh #802: Added support for retrieving sub-array element or child object property through `ArrayHelper::getValue()` (qiangxue, cebe) - Enh #802: Added support for retrieving sub-array element or child object property through `ArrayHelper::getValue()` (qiangxue, cebe)
- Enh #938: Added `yii\web\View::renderAjax()` and `yii\web\Controller::renderAjax()` (qiangxue) - Enh #938: Added `yii\web\View::renderAjax()` and `yii\web\Controller::renderAjax()` (qiangxue)
...@@ -146,6 +148,7 @@ Yii Framework 2 Change Log ...@@ -146,6 +148,7 @@ Yii Framework 2 Change Log
- Enh #2729: Added `FilterValidator::skipOnArray` so that filters like `trim` will not fail for array inputs (qiangxue) - Enh #2729: Added `FilterValidator::skipOnArray` so that filters like `trim` will not fail for array inputs (qiangxue)
- Enh #2735: Added support for `DateTimeInterface` in `Formatter` (ivokund) - Enh #2735: Added support for `DateTimeInterface` in `Formatter` (ivokund)
- Enh #2756: Added support for injecting custom `isEmpty` check for all validators (qiangxue) - Enh #2756: Added support for injecting custom `isEmpty` check for all validators (qiangxue)
- Enh #2775: Added `yii\base\Application::bootstrap` to support running bootstrap classes when starting an application (qiangxue)
- Enh: Added support for using arrays as option values for console commands (qiangxue) - Enh: Added support for using arrays as option values for console commands (qiangxue)
- Enh: Added `favicon.ico` and `robots.txt` to default application templates (samdark) - Enh: Added `favicon.ico` and `robots.txt` to default application templates (samdark)
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue) - Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
...@@ -241,6 +244,7 @@ Yii Framework 2 Change Log ...@@ -241,6 +244,7 @@ Yii Framework 2 Change Log
- Renamed `yii\web\User::returnUrlVar` to `returnUrlParam` - Renamed `yii\web\User::returnUrlVar` to `returnUrlParam`
- Chg: Added `View::viewFile` and removed `ViewEvent::viewFile` (qiangxue) - Chg: Added `View::viewFile` and removed `ViewEvent::viewFile` (qiangxue)
- Chg: Changed `Controller::afterAction()`, `Module::afterAction()` and `ActionFilter::afterAction()` to pass `$result` by value instead of reference (qiangxue) - Chg: Changed `Controller::afterAction()`, `Module::afterAction()` and `ActionFilter::afterAction()` to pass `$result` by value instead of reference (qiangxue)
- Chg: `yii\base\Extension::init()` is renamed to `bootstrap()` (qiangxue)
- New #66: [Auth client library](https://github.com/yiisoft/yii2-authclient) OpenId, OAuth1, OAuth2 clients (klimov-paul) - New #66: [Auth client library](https://github.com/yiisoft/yii2-authclient) OpenId, OAuth1, OAuth2 clients (klimov-paul)
- New #706: Added `yii\widgets\Pjax` and enhanced `GridView` to work with `Pjax` to support AJAX-update (qiangxue) - New #706: Added `yii\widgets\Pjax` and enhanced `GridView` to work with `Pjax` to support AJAX-update (qiangxue)
- New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo) - New #1393: [Codeception testing framework integration](https://github.com/yiisoft/yii2-codeception) (Ragazzo)
......
...@@ -10,400 +10,400 @@ ...@@ -10,400 +10,400 @@
* @since 2.0 * @since 2.0
*/ */
(function ($) { (function ($) {
$.fn.yiiActiveForm = function (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.yiiActiveForm');
return false;
}
};
var defaults = { $.fn.yiiActiveForm = function (method) {
// the jQuery selector for the error summary if (methods[method]) {
errorSummary: undefined, return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
// whether to perform validation before submitting the form. } else if (typeof method === 'object' || !method) {
validateOnSubmit: true, return methods.init.apply(this, arguments);
// the container CSS class representing the corresponding attribute has validation error } else {
errorCssClass: 'error', $.error('Method ' + method + ' does not exist on jQuery.yiiActiveForm');
// the container CSS class representing the corresponding attribute passes validation return false;
successCssClass: 'success', }
// the container CSS class representing the corresponding attribute is being validated };
validatingCssClass: 'validating',
// the URL for performing AJAX-based validation. If not set, it will use the the form's action
validationUrl: undefined,
// a callback that is called before submitting the form. The signature of the callback should be:
// function ($form) { ...return false to cancel submission...}
beforeSubmit: undefined,
// a callback that is called before validating each attribute. The signature of the callback should be:
// function ($form, attribute, messages) { ...return false to cancel the validation...}
beforeValidate: undefined,
// a callback that is called after an attribute is validated. The signature of the callback should be:
// function ($form, attribute, messages)
afterValidate: undefined,
// the GET parameter name indicating an AJAX-based validation
ajaxParam: 'ajax',
// the type of data that you're expecting back from the server
ajaxDataType: 'json'
};
var attributeDefaults = { var defaults = {
// attribute name or expression (e.g. "[0]content" for tabular input) // the jQuery selector for the error summary
name: undefined, errorSummary: undefined,
// the jQuery selector of the container of the input field // whether to perform validation before submitting the form.
container: undefined, validateOnSubmit: true,
// the jQuery selector of the input field // the container CSS class representing the corresponding attribute has validation error
input: undefined, errorCssClass: 'error',
// the jQuery selector of the error tag // the container CSS class representing the corresponding attribute passes validation
error: undefined, successCssClass: 'success',
// whether to perform validation when a change is detected on the input // the container CSS class representing the corresponding attribute is being validated
validateOnChange: false, validatingCssClass: 'validating',
// whether to perform validation when the user is typing. // the URL for performing AJAX-based validation. If not set, it will use the the form's action
validateOnType: false, validationUrl: undefined,
// number of milliseconds that the validation should be delayed when a user is typing in the input field. // a callback that is called before submitting the form. The signature of the callback should be:
validationDelay: 200, // function ($form) { ...return false to cancel submission...}
// whether to enable AJAX-based validation. beforeSubmit: undefined,
enableAjaxValidation: false, // a callback that is called before validating each attribute. The signature of the callback should be:
// function (attribute, value, messages), the client-side validation function. // function ($form, attribute, messages) { ...return false to cancel the validation...}
validate: undefined, beforeValidate: undefined,
// status of the input field, 0: empty, not entered before, 1: validated, 2: pending validation, 3: validating // a callback that is called after an attribute is validated. The signature of the callback should be:
status: 0, // function ($form, attribute, messages)
// the value of the input afterValidate: undefined,
value: undefined // the GET parameter name indicating an AJAX-based validation
}; ajaxParam: 'ajax',
// the type of data that you're expecting back from the server
ajaxDataType: 'json'
};
var methods = { var attributeDefaults = {
init: function (attributes, options) { // attribute name or expression (e.g. "[0]content" for tabular input)
return this.each(function () { name: undefined,
var $form = $(this); // the jQuery selector of the container of the input field
if ($form.data('yiiActiveForm')) { container: undefined,
return; // the jQuery selector of the input field
} input: undefined,
// the jQuery selector of the error tag
error: undefined,
// whether to perform validation when a change is detected on the input
validateOnChange: false,
// whether to perform validation when the user is typing.
validateOnType: false,
// number of milliseconds that the validation should be delayed when a user is typing in the input field.
validationDelay: 200,
// whether to enable AJAX-based validation.
enableAjaxValidation: false,
// function (attribute, value, messages), the client-side validation function.
validate: undefined,
// status of the input field, 0: empty, not entered before, 1: validated, 2: pending validation, 3: validating
status: 0,
// the value of the input
value: undefined
};
var settings = $.extend({}, defaults, options || {}); var methods = {
if (settings.validationUrl === undefined) { init: function (attributes, options) {
settings.validationUrl = $form.prop('action'); return this.each(function () {
} var $form = $(this);
$.each(attributes, function (i) { if ($form.data('yiiActiveForm')) {
attributes[i] = $.extend({value: getValue($form, this)}, attributeDefaults, this); return;
}); }
$form.data('yiiActiveForm', {
settings: settings,
attributes: attributes,
submitting: false,
validated: false
});
watchAttributes($form, attributes); var settings = $.extend({}, defaults, options || {});
if (settings.validationUrl === undefined) {
settings.validationUrl = $form.prop('action');
}
$.each(attributes, function (i) {
attributes[i] = $.extend({value: getValue($form, this)}, attributeDefaults, this);
});
$form.data('yiiActiveForm', {
settings: settings,
attributes: attributes,
submitting: false,
validated: false
});
/** watchAttributes($form, attributes);
* Clean up error status when the form is reset.
* Note that $form.on('reset', ...) does work because the "reset" event does not bubble on IE.
*/
$form.bind('reset.yiiActiveForm', methods.resetForm);
if (settings.validateOnSubmit) { /**
$form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () { * Clean up error status when the form is reset.
$form.data('yiiActiveForm').submitObject = $(this); * Note that $form.on('reset', ...) does work because the "reset" event does not bubble on IE.
}); */
$form.on('submit', methods.submitForm); $form.bind('reset.yiiActiveForm', methods.resetForm);
}
});
},
destroy: function () { if (settings.validateOnSubmit) {
return this.each(function () { $form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () {
$(window).unbind('.yiiActiveForm'); $form.data('yiiActiveForm').submitObject = $(this);
$(this).removeData('yiiActiveForm'); });
}); $form.on('submit', methods.submitForm);
}, }
});
},
data: function() { destroy: function () {
return this.data('yiiActiveForm'); return this.each(function () {
}, $(window).unbind('.yiiActiveForm');
$(this).removeData('yiiActiveForm');
});
},
submitForm: function () { data: function () {
var $form = $(this), return this.data('yiiActiveForm');
data = $form.data('yiiActiveForm'); },
if (data.validated) {
if (data.settings.beforeSubmit !== undefined) {
if (data.settings.beforeSubmit($form) == false) {
data.validated = false;
data.submitting = false;
return false;
}
}
// continue submitting the form since validation passes
return true;
}
if (data.settings.timer !== undefined) { submitForm: function () {
clearTimeout(data.settings.timer); var $form = $(this),
} data = $form.data('yiiActiveForm');
data.submitting = true; if (data.validated) {
validate($form, function (messages) { if (data.settings.beforeSubmit !== undefined) {
var errors = []; if (data.settings.beforeSubmit($form) == false) {
$.each(data.attributes, function () { data.validated = false;
if (updateInput($form, this, messages)) { data.submitting = false;
errors.push(this.input); return false;
} }
}); }
updateSummary($form, messages); // continue submitting the form since validation passes
if (errors.length) { return true;
var top = $form.find(errors.join(',')).first().offset().top; }
var wtop = $(window).scrollTop();
if (top < wtop || top > wtop + $(window).height) {
$(window).scrollTop(top);
}
} else {
data.validated = true;
var $button = data.submitObject || $form.find(':submit:first');
// TODO: if the submission is caused by "change" event, it will not work
if ($button.length) {
$button.click();
} else {
// no submit button in the form
$form.submit();
}
return;
}
data.submitting = false;
}, function () {
data.submitting = false;
});
return false;
},
resetForm: function () { if (data.settings.timer !== undefined) {
var $form = $(this); clearTimeout(data.settings.timer);
var data = $form.data('yiiActiveForm'); }
// Because we bind directly to a form reset event instead of a reset button (that may not exist), data.submitting = true;
// when this function is executed form input values have not been reset yet. validate($form, function (messages) {
// Therefore we do the actual reset work through setTimeout. var errors = [];
setTimeout(function () { $.each(data.attributes, function () {
$.each(data.attributes, function () { if (updateInput($form, this, messages)) {
// Without setTimeout() we would get the input values that are not reset yet. errors.push(this.input);
this.value = getValue($form, this); }
this.status = 0; });
var $container = $form.find(this.container); updateSummary($form, messages);
$container.removeClass( if (errors.length) {
data.settings.validatingCssClass + ' ' + var top = $form.find(errors.join(',')).first().offset().top;
data.settings.errorCssClass + ' ' + var wtop = $(window).scrollTop();
data.settings.successCssClass if (top < wtop || top > wtop + $(window).height) {
); $(window).scrollTop(top);
$container.find(this.error).html(''); }
}); } else {
$form.find(data.settings.summary).hide().find('ul').html(''); data.validated = true;
}, 1); var $button = data.submitObject || $form.find(':submit:first');
} // TODO: if the submission is caused by "change" event, it will not work
}; if ($button.length) {
$button.click();
} else {
// no submit button in the form
$form.submit();
}
return;
}
data.submitting = false;
}, function () {
data.submitting = false;
});
return false;
},
var watchAttributes = function ($form, attributes) { resetForm: function () {
$.each(attributes, function (i, attribute) { var $form = $(this);
var $input = findInput($form, attribute); var data = $form.data('yiiActiveForm');
if (attribute.validateOnChange) { // Because we bind directly to a form reset event instead of a reset button (that may not exist),
$input.on('change.yiiActiveForm', function () { // when this function is executed form input values have not been reset yet.
validateAttribute($form, attribute, false); // Therefore we do the actual reset work through setTimeout.
}).on('blur.yiiActiveForm', function () { setTimeout(function () {
if (attribute.status == 0 || attribute.status == 1) { $.each(data.attributes, function () {
validateAttribute($form, attribute, !attribute.status); // Without setTimeout() we would get the input values that are not reset yet.
} this.value = getValue($form, this);
}); this.status = 0;
} var $container = $form.find(this.container);
if (attribute.validateOnType) { $container.removeClass(
$input.on('keyup.yiiActiveForm', function () { data.settings.validatingCssClass + ' ' +
if (attribute.value !== getValue($form, attribute)) { data.settings.errorCssClass + ' ' +
validateAttribute($form, attribute, false); data.settings.successCssClass
} );
}); $container.find(this.error).html('');
} });
}); $form.find(data.settings.summary).hide().find('ul').html('');
}; }, 1);
}
};
var validateAttribute = function ($form, attribute, forceValidate) { var watchAttributes = function ($form, attributes) {
var data = $form.data('yiiActiveForm'); $.each(attributes, function (i, attribute) {
var $input = findInput($form, attribute);
if (attribute.validateOnChange) {
$input.on('change.yiiActiveForm',function () {
validateAttribute($form, attribute, false);
}).on('blur.yiiActiveForm', function () {
if (attribute.status == 0 || attribute.status == 1) {
validateAttribute($form, attribute, !attribute.status);
}
});
}
if (attribute.validateOnType) {
$input.on('keyup.yiiActiveForm', function () {
if (attribute.value !== getValue($form, attribute)) {
validateAttribute($form, attribute, false);
}
});
}
});
};
if (forceValidate) { var validateAttribute = function ($form, attribute, forceValidate) {
attribute.status = 2; var data = $form.data('yiiActiveForm');
}
$.each(data.attributes, function () {
if (this.value !== getValue($form, this)) {
this.status = 2;
forceValidate = true;
}
});
if (!forceValidate) {
return;
}
if (data.settings.timer !== undefined) { if (forceValidate) {
clearTimeout(data.settings.timer); attribute.status = 2;
} }
data.settings.timer = setTimeout(function () { $.each(data.attributes, function () {
if (data.submitting || $form.is(':hidden')) { if (this.value !== getValue($form, this)) {
return; this.status = 2;
} forceValidate = true;
$.each(data.attributes, function () { }
if (this.status === 2) { });
this.status = 3; if (!forceValidate) {
$form.find(this.container).addClass(data.settings.validatingCssClass); return;
} }
});
validate($form, function (messages) {
var hasError = false;
$.each(data.attributes, function () {
if (this.status === 2 || this.status === 3) {
hasError = updateInput($form, this, messages) || hasError;
}
});
});
}, data.settings.validationDelay);
};
/**
* Performs validation.
* @param $form jQuery the jquery representation of the form
* @param successCallback function the function to be invoked if the validation completes
* @param errorCallback function the function to be invoked if the ajax validation request fails
*/
var validate = function ($form, successCallback, errorCallback) {
var data = $form.data('yiiActiveForm'),
needAjaxValidation = false,
messages = {};
$.each(data.attributes, function () { if (data.settings.timer !== undefined) {
if (data.submitting || this.status === 2 || this.status === 3) { clearTimeout(data.settings.timer);
var msg = []; }
if (!data.settings.beforeValidate || data.settings.beforeValidate($form, this, msg)) { data.settings.timer = setTimeout(function () {
if (this.validate) { if (data.submitting || $form.is(':hidden')) {
this.validate(this, getValue($form, this), msg); return;
} }
if (msg.length) { $.each(data.attributes, function () {
messages[this.name] = msg; if (this.status === 2) {
} else if (this.enableAjaxValidation) { this.status = 3;
needAjaxValidation = true; $form.find(this.container).addClass(data.settings.validatingCssClass);
} }
} });
} validate($form, function (messages) {
}); var hasError = false;
$.each(data.attributes, function () {
if (this.status === 2 || this.status === 3) {
hasError = updateInput($form, this, messages) || hasError;
}
});
});
}, data.settings.validationDelay);
};
if (needAjaxValidation && (!data.submitting || $.isEmptyObject(messages))) { /**
// Perform ajax validation when at least one input needs it. * Performs validation.
// If the validation is triggered by form submission, ajax validation * @param $form jQuery the jquery representation of the form
// should be done only when all inputs pass client validation * @param successCallback function the function to be invoked if the validation completes
var $button = data.submitObject, * @param errorCallback function the function to be invoked if the ajax validation request fails
extData = '&' + data.settings.ajaxParam + '=' + $form.prop('id'); */
if ($button && $button.length && $button.prop('name')) { var validate = function ($form, successCallback, errorCallback) {
extData += '&' + $button.prop('name') + '=' + $button.prop('value'); var data = $form.data('yiiActiveForm'),
} needAjaxValidation = false,
$.ajax({ messages = {};
url: data.settings.validationUrl,
type: $form.prop('method'),
data: $form.serialize() + extData,
dataType: data.settings.ajaxDataType,
success: function (msgs) {
if (msgs !== null && typeof msgs === 'object') {
$.each(data.attributes, function () {
if (!this.enableAjaxValidation) {
delete msgs[this.name];
}
});
successCallback($.extend({}, messages, msgs));
} else {
successCallback(messages);
}
},
error: errorCallback
});
} else if (data.submitting) {
// delay callback so that the form can be submitted without problem
setTimeout(function () {
successCallback(messages);
}, 200);
} else {
successCallback(messages);
}
};
/** $.each(data.attributes, function () {
* Updates the error message and the input container for a particular attribute. if (data.submitting || this.status === 2 || this.status === 3) {
* @param $form the form jQuery object var msg = [];
* @param attribute object the configuration for a particular attribute. if (!data.settings.beforeValidate || data.settings.beforeValidate($form, this, msg)) {
* @param messages array the validation error messages if (this.validate) {
* @return boolean whether there is a validation error for the specified attribute this.validate(this, getValue($form, this), msg);
*/ }
var updateInput = function ($form, attribute, messages) { if (msg.length) {
var data = $form.data('yiiActiveForm'), messages[this.name] = msg;
$input = findInput($form, attribute), } else if (this.enableAjaxValidation) {
hasError = false; needAjaxValidation = true;
}
}
}
});
if (data.settings.afterValidate) { if (needAjaxValidation && (!data.submitting || $.isEmptyObject(messages))) {
data.settings.afterValidate($form, attribute, messages); // Perform ajax validation when at least one input needs it.
} // If the validation is triggered by form submission, ajax validation
attribute.status = 1; // should be done only when all inputs pass client validation
if ($input.length) { var $button = data.submitObject,
hasError = messages && $.isArray(messages[attribute.name]) && messages[attribute.name].length; extData = '&' + data.settings.ajaxParam + '=' + $form.prop('id');
var $container = $form.find(attribute.container); if ($button && $button.length && $button.prop('name')) {
var $error = $container.find(attribute.error); extData += '&' + $button.prop('name') + '=' + $button.prop('value');
if (hasError) { }
$error.text(messages[attribute.name][0]); $.ajax({
$container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.successCssClass) url: data.settings.validationUrl,
.addClass(data.settings.errorCssClass); type: $form.prop('method'),
} else { data: $form.serialize() + extData,
$error.text(''); dataType: data.settings.ajaxDataType,
$container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.errorCssClass + ' ') success: function (msgs) {
.addClass(data.settings.successCssClass); if (msgs !== null && typeof msgs === 'object') {
} $.each(data.attributes, function () {
attribute.value = getValue($form, attribute); if (!this.enableAjaxValidation) {
} delete msgs[this.name];
return hasError; }
}; });
successCallback($.extend({}, messages, msgs));
} else {
successCallback(messages);
}
},
error: errorCallback
});
} else if (data.submitting) {
// delay callback so that the form can be submitted without problem
setTimeout(function () {
successCallback(messages);
}, 200);
} else {
successCallback(messages);
}
};
/** /**
* Updates the error summary. * Updates the error message and the input container for a particular attribute.
* @param $form the form jQuery object * @param $form the form jQuery object
* @param messages array the validation error messages * @param attribute object the configuration for a particular attribute.
*/ * @param messages array the validation error messages
var updateSummary = function ($form, messages) { * @return boolean whether there is a validation error for the specified attribute
var data = $form.data('yiiActiveForm'), */
$summary = $form.find(data.settings.errorSummary), var updateInput = function ($form, attribute, messages) {
$ul = $summary.find('ul').html(''); var data = $form.data('yiiActiveForm'),
$input = findInput($form, attribute),
hasError = false;
if ($summary.length && messages) { if (data.settings.afterValidate) {
$.each(data.attributes, function () { data.settings.afterValidate($form, attribute, messages);
if ($.isArray(messages[this.name]) && messages[this.name].length) { }
$ul.append($('<li/>').text(messages[this.name][0])); attribute.status = 1;
} if ($input.length) {
}); hasError = messages && $.isArray(messages[attribute.name]) && messages[attribute.name].length;
$summary.toggle($ul.find('li').length > 0); var $container = $form.find(attribute.container);
} var $error = $container.find(attribute.error);
}; if (hasError) {
$error.text(messages[attribute.name][0]);
$container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.successCssClass)
.addClass(data.settings.errorCssClass);
} else {
$error.text('');
$container.removeClass(data.settings.validatingCssClass + ' ' + data.settings.errorCssClass + ' ')
.addClass(data.settings.successCssClass);
}
attribute.value = getValue($form, attribute);
}
return hasError;
};
var getValue = function ($form, attribute) { /**
var $input = findInput($form, attribute); * Updates the error summary.
var type = $input.prop('type'); * @param $form the form jQuery object
if (type === 'checkbox' || type === 'radio') { * @param messages array the validation error messages
var $realInput = $input.filter(':checked'); */
if (!$realInput.length) { var updateSummary = function ($form, messages) {
$realInput = $form.find('input[type=hidden][name="'+$input.prop('name')+'"]'); var data = $form.data('yiiActiveForm'),
} $summary = $form.find(data.settings.errorSummary),
return $realInput.val(); $ul = $summary.find('ul').html('');
} else {
return $input.val();
}
};
var findInput = function ($form, attribute) { if ($summary.length && messages) {
var $input = $form.find(attribute.input); $.each(data.attributes, function () {
if ($input.length && $input[0].tagName.toLowerCase() === 'div') { if ($.isArray(messages[this.name]) && messages[this.name].length) {
// checkbox list or radio list $ul.append($('<li/>').text(messages[this.name][0]));
return $input.find('input'); }
} else { });
return $input; $summary.toggle($ul.find('li').length > 0);
} }
}; };
var getValue = function ($form, attribute) {
var $input = findInput($form, attribute);
var type = $input.prop('type');
if (type === 'checkbox' || type === 'radio') {
var $realInput = $input.filter(':checked');
if (!$realInput.length) {
$realInput = $form.find('input[type=hidden][name="' + $input.prop('name') + '"]');
}
return $realInput.val();
} else {
return $input.val();
}
};
var findInput = function ($form, attribute) {
var $input = $form.find(attribute.input);
if ($input.length && $input[0].tagName.toLowerCase() === 'div') {
// checkbox list or radio list
return $input.find('input');
} else {
return $input;
}
};
})(window.jQuery); })(window.jQuery);
...@@ -10,63 +10,63 @@ ...@@ -10,63 +10,63 @@
* @since 2.0 * @since 2.0
*/ */
(function ($) { (function ($) {
$.fn.yiiCaptcha = function (method) { $.fn.yiiCaptcha = function (method) {
if (methods[method]) { if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) { } else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments); return methods.init.apply(this, arguments);
} else { } else {
$.error('Method ' + method + ' does not exist on jQuery.yiiCaptcha'); $.error('Method ' + method + ' does not exist on jQuery.yiiCaptcha');
return false; return false;
} }
}; };
var defaults = { var defaults = {
refreshUrl: undefined, refreshUrl: undefined,
hashKey: undefined hashKey: undefined
}; };
var methods = { var methods = {
init: function (options) { init: function (options) {
return this.each(function () { return this.each(function () {
var $e = $(this); var $e = $(this);
var settings = $.extend({}, defaults, options || {}); var settings = $.extend({}, defaults, options || {});
$e.data('yiiCaptcha', { $e.data('yiiCaptcha', {
settings: settings settings: settings
}); });
$e.on('click.yiiCaptcha', function() { $e.on('click.yiiCaptcha', function () {
methods.refresh.apply($e); methods.refresh.apply($e);
return false; return false;
}); });
}); });
}, },
refresh: function () { refresh: function () {
var $e = this, var $e = this,
settings = this.data('yiiCaptcha').settings; settings = this.data('yiiCaptcha').settings;
$.ajax({ $.ajax({
url: $e.data('yiiCaptcha').settings.refreshUrl, url: $e.data('yiiCaptcha').settings.refreshUrl,
dataType: 'json', dataType: 'json',
cache: false, cache: false,
success: function(data) { success: function (data) {
$e.attr('src', data.url); $e.attr('src', data.url);
$('body').data(settings.hashKey, [data.hash1, data.hash2]); $('body').data(settings.hashKey, [data.hash1, data.hash2]);
} }
}); });
}, },
destroy: function () { destroy: function () {
return this.each(function () { return this.each(function () {
$(window).unbind('.yiiCaptcha'); $(window).unbind('.yiiCaptcha');
$(this).removeData('yiiCaptcha'); $(this).removeData('yiiCaptcha');
}); });
}, },
data: function() { data: function () {
return this.data('yiiCaptcha'); return this.data('yiiCaptcha');
} }
}; };
})(window.jQuery); })(window.jQuery);
...@@ -10,120 +10,120 @@ ...@@ -10,120 +10,120 @@
* @since 2.0 * @since 2.0
*/ */
(function ($) { (function ($) {
$.fn.yiiGridView = function (method) { $.fn.yiiGridView = function (method) {
if (methods[method]) { if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) { } else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments); return methods.init.apply(this, arguments);
} else { } else {
$.error('Method ' + method + ' does not exist on jQuery.yiiGridView'); $.error('Method ' + method + ' does not exist on jQuery.yiiGridView');
return false; return false;
} }
}; };
var defaults = { var defaults = {
filterUrl: undefined, filterUrl: undefined,
filterSelector: undefined filterSelector: undefined
}; };
var gridData = {}; var gridData = {};
var methods = { var methods = {
init: function (options) { init: function (options) {
return this.each(function () { return this.each(function () {
var $e = $(this); var $e = $(this);
var settings = $.extend({}, defaults, options || {}); var settings = $.extend({}, defaults, options || {});
gridData[$e.prop('id')] = {settings: settings}; gridData[$e.prop('id')] = {settings: settings};
var enterPressed = false; var enterPressed = false;
$(document).off('change.yiiGridView keydown.yiiGridView', settings.filterSelector) $(document).off('change.yiiGridView keydown.yiiGridView', settings.filterSelector)
.on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) { .on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) {
if (event.type === 'keydown') { if (event.type === 'keydown') {
if (event.keyCode !== 13) { if (event.keyCode !== 13) {
return; // only react to enter key return; // only react to enter key
} else { } else {
enterPressed = true; enterPressed = true;
} }
} else { } else {
// prevent processing for both keydown and change events // prevent processing for both keydown and change events
if (enterPressed) { if (enterPressed) {
enterPressed = false; enterPressed = false;
return; return;
} }
} }
methods.applyFilter.apply($e); methods.applyFilter.apply($e);
return false; return false;
}); });
}); });
}, },
applyFilter: function () { applyFilter: function () {
var $grid = $(this); var $grid = $(this);
var settings = gridData[$grid.prop('id')].settings; var settings = gridData[$grid.prop('id')].settings;
var data = {}; var data = {};
$.each($(settings.filterSelector).serializeArray(), function () { $.each($(settings.filterSelector).serializeArray(), function () {
data[this.name] = this.value; data[this.name] = this.value;
}); });
$.each(yii.getQueryParams(settings.filterUrl), function (name, value) { $.each(yii.getQueryParams(settings.filterUrl), function (name, value) {
if (data[name] === undefined) { if (data[name] === undefined) {
data[name] = value; data[name] = value;
} }
}); });
var pos = settings.filterUrl.indexOf('?'); var pos = settings.filterUrl.indexOf('?');
var url = pos < 0 ? settings.filterUrl : settings.filterUrl.substring(0, pos); var url = pos < 0 ? settings.filterUrl : settings.filterUrl.substring(0, pos);
$grid.find('form.gridview-filter-form').remove(); $grid.find('form.gridview-filter-form').remove();
var $form = $('<form action="' + url + '" method="get" class="gridview-filter-form" style="display:none" data-pjax></form>').appendTo($grid); var $form = $('<form action="' + url + '" method="get" class="gridview-filter-form" style="display:none" data-pjax></form>').appendTo($grid);
$.each(data, function (name, value) { $.each(data, function (name, value) {
$form.append($('<input type="hidden" name="t" value="" />').attr('name', name).val(value)); $form.append($('<input type="hidden" name="t" value="" />').attr('name', name).val(value));
}); });
$form.submit(); $form.submit();
}, },
setSelectionColumn: function (options) { setSelectionColumn: function (options) {
var $grid = $(this); var $grid = $(this);
var id = $(this).prop('id'); var id = $(this).prop('id');
gridData[id].selectionColumn = options.name; gridData[id].selectionColumn = options.name;
if (!options.multiple) { if (!options.multiple) {
return; return;
} }
var inputs = "#" + id + " input[name='" + options.checkAll + "']"; var inputs = "#" + id + " input[name='" + options.checkAll + "']";
$(document).off('click.yiiGridView', inputs).on('click.yiiGridView', inputs, function () { $(document).off('click.yiiGridView', inputs).on('click.yiiGridView', inputs, function () {
$grid.find("input[name='" + options.name + "']:enabled").prop('checked', this.checked); $grid.find("input[name='" + options.name + "']:enabled").prop('checked', this.checked);
}); });
$(document).off('click.yiiGridView', inputs + ":enabled").on('click.yiiGridView', inputs + ":enabled", function () { $(document).off('click.yiiGridView', inputs + ":enabled").on('click.yiiGridView', inputs + ":enabled", function () {
var all = $grid.find("input[name='" + options.name + "']").length == $grid.find("input[name='" + options.name + "']:checked").length; var all = $grid.find("input[name='" + options.name + "']").length == $grid.find("input[name='" + options.name + "']:checked").length;
$grid.find("input[name='" + options.checkAll + "']").prop('checked', all); $grid.find("input[name='" + options.checkAll + "']").prop('checked', all);
}); });
}, },
getSelectedRows: function () { getSelectedRows: function () {
var $grid = $(this); var $grid = $(this);
var data = gridData[$grid.prop('id')]; var data = gridData[$grid.prop('id')];
var keys = []; var keys = [];
if (data.selectionColumn) { if (data.selectionColumn) {
$grid.find("input[name='" + data.selectionColumn + "']:checked").each(function () { $grid.find("input[name='" + data.selectionColumn + "']:checked").each(function () {
keys.push($(this).parent().closest('tr').data('key')); keys.push($(this).parent().closest('tr').data('key'));
}); });
} }
return keys; return keys;
}, },
destroy: function () { destroy: function () {
return this.each(function () { return this.each(function () {
$(window).unbind('.yiiGridView'); $(window).unbind('.yiiGridView');
$(this).removeData('yiiGridView'); $(this).removeData('yiiGridView');
}); });
}, },
data: function () { data: function () {
var id = $(this).prop('id'); var id = $(this).prop('id');
return gridData[id]; return gridData[id];
} }
}; };
})(window.jQuery); })(window.jQuery);
...@@ -42,220 +42,220 @@ ...@@ -42,220 +42,220 @@
* You must call "yii.initModule()" once for the root module of all your modules. * You must call "yii.initModule()" once for the root module of all your modules.
*/ */
yii = (function ($) { yii = (function ($) {
var pub = { var pub = {
/** /**
* List of scripts that can be loaded multiple times via AJAX requests. Each script can be represented * List of scripts that can be loaded multiple times via AJAX requests. Each script can be represented
* as either an absolute URL or a relative one. * as either an absolute URL or a relative one.
*/ */
reloadableScripts: [], reloadableScripts: [],
/** /**
* The selector for clickable elements that need to support confirmation and form submission. * The selector for clickable elements that need to support confirmation and form submission.
*/ */
clickableSelector: 'a, button, input[type="submit"], input[type="button"], input[type="reset"], input[type="image"]', clickableSelector: 'a, button, input[type="submit"], input[type="button"], input[type="reset"], input[type="image"]',
/** /**
* The selector for changeable elements that need to support confirmation and form submission. * The selector for changeable elements that need to support confirmation and form submission.
*/ */
changeableSelector: 'select, input, textarea', changeableSelector: 'select, input, textarea',
/** /**
* @return string|undefined the CSRF parameter name. Undefined is returned if CSRF validation is not enabled. * @return string|undefined the CSRF parameter name. Undefined is returned if CSRF validation is not enabled.
*/ */
getCsrfParam: function () { getCsrfParam: function () {
return $('meta[name=csrf-param]').prop('content'); return $('meta[name=csrf-param]').prop('content');
}, },
/** /**
* @return string|undefined the CSRF token. Undefined is returned if CSRF validation is not enabled. * @return string|undefined the CSRF token. Undefined is returned if CSRF validation is not enabled.
*/ */
getCsrfToken: function () { getCsrfToken: function () {
return $('meta[name=csrf-token]').prop('content'); return $('meta[name=csrf-token]').prop('content');
}, },
/** /**
* Displays a confirmation dialog. * Displays a confirmation dialog.
* The default implementation simply displays a js confirmation dialog. * The default implementation simply displays a js confirmation dialog.
* You may override this by setting `yii.confirm`. * You may override this by setting `yii.confirm`.
* @param message the confirmation message. * @param message the confirmation message.
* @return boolean whether the user confirms with the message in the dialog * @return boolean whether the user confirms with the message in the dialog
*/ */
confirm: function (message) { confirm: function (message) {
return confirm(message); return confirm(message);
}, },
/** /**
* Returns a value indicating whether to allow executing the action defined for the specified element. * Returns a value indicating whether to allow executing the action defined for the specified element.
* This method recognizes the `data-confirm` attribute of the element and uses it * This method recognizes the `data-confirm` attribute of the element and uses it
* as the message in a confirmation dialog. The method will return true if this special attribute * as the message in a confirmation dialog. The method will return true if this special attribute
* is not defined or if the user confirms the message. * is not defined or if the user confirms the message.
* @param $e the jQuery representation of the element * @param $e the jQuery representation of the element
* @return boolean whether to allow executing the action defined for the specified element. * @return boolean whether to allow executing the action defined for the specified element.
*/ */
allowAction: function ($e) { allowAction: function ($e) {
var message = $e.data('confirm'); var message = $e.data('confirm');
return message === undefined || pub.confirm(message); return message === undefined || pub.confirm(message);
}, },
/** /**
* Handles the action triggered by user. * Handles the action triggered by user.
* This method recognizes the `data-method` attribute of the element. If the attribute exists, * This method recognizes the `data-method` attribute of the element. If the attribute exists,
* the method will submit the form containing this element. If there is no containing form, a form * the method will submit the form containing this element. If there is no containing form, a form
* will be created and submitted using the method given by this attribute value (e.g. "post", "put"). * will be created and submitted using the method given by this attribute value (e.g. "post", "put").
* For hyperlinks, the form action will take the value of the "href" attribute of the link. * For hyperlinks, the form action will take the value of the "href" attribute of the link.
* For other elements, either the containing form action or the current page URL will be used * For other elements, either the containing form action or the current page URL will be used
* as the form action URL. * as the form action URL.
* *
* If the `data-method` attribute is not defined, the default element action will be performed. * If the `data-method` attribute is not defined, the default element action will be performed.
* *
* @param $e the jQuery representation of the element * @param $e the jQuery representation of the element
* @return boolean whether to execute the default action for the element. * @return boolean whether to execute the default action for the element.
*/ */
handleAction: function ($e) { handleAction: function ($e) {
var method = $e.data('method'); var method = $e.data('method');
if (method === undefined) { if (method === undefined) {
return true; return true;
} }
var $form = $e.closest('form'); var $form = $e.closest('form');
var newForm = !$form.length; var newForm = !$form.length;
if (newForm) { if (newForm) {
var action = $e.prop('href'); var action = $e.prop('href');
if (!action || !action.match(/(^\/|:\/\/)/)) { if (!action || !action.match(/(^\/|:\/\/)/)) {
action = window.location.href; action = window.location.href;
} }
$form = $('<form method="' + method + '" action="' + action + '"></form>'); $form = $('<form method="' + method + '" action="' + action + '"></form>');
var target = $e.prop('target'); var target = $e.prop('target');
if (target) { if (target) {
$form.attr('target', target); $form.attr('target', target);
} }
if (!method.match(/(get|post)/i)) { if (!method.match(/(get|post)/i)) {
$form.append('<input name="_method" value="' + method + '" type="hidden">'); $form.append('<input name="_method" value="' + method + '" type="hidden">');
} }
var csrfParam = pub.getCsrfParam(); var csrfParam = pub.getCsrfParam();
if (csrfParam) { if (csrfParam) {
$form.append('<input name="' + csrfParam + '" value="' + pub.getCsrfToken() + '" type="hidden">'); $form.append('<input name="' + csrfParam + '" value="' + pub.getCsrfToken() + '" type="hidden">');
} }
$form.hide().appendTo('body'); $form.hide().appendTo('body');
} }
var activeFormData = $form.data('yiiActiveForm'); var activeFormData = $form.data('yiiActiveForm');
if (activeFormData) { if (activeFormData) {
// remember who triggers the form submission. This is used by yii.activeForm.js // remember who triggers the form submission. This is used by yii.activeForm.js
activeFormData.submitObject = $e; activeFormData.submitObject = $e;
} }
$form.trigger('submit'); $form.trigger('submit');
if (newForm) { if (newForm) {
$form.remove(); $form.remove();
} }
return false; return false;
}, },
getQueryParams: function (url) { getQueryParams: function (url) {
var pos = url.indexOf('?'); var pos = url.indexOf('?');
if (pos < 0) { if (pos < 0) {
return {}; return {};
} }
var qs = url.substring(pos + 1).split('&'); var qs = url.substring(pos + 1).split('&');
for (var i = 0, result = {}; i < qs.length; i++) { for (var i = 0, result = {}; i < qs.length; i++) {
qs[i] = qs[i].split('='); qs[i] = qs[i].split('=');
result[decodeURIComponent(qs[i][0])] = decodeURIComponent(qs[i][1]); result[decodeURIComponent(qs[i][0])] = decodeURIComponent(qs[i][1]);
} }
return result; return result;
}, },
initModule: function (module) { initModule: function (module) {
if (module.isActive === undefined || module.isActive) { if (module.isActive === undefined || module.isActive) {
if ($.isFunction(module.init)) { if ($.isFunction(module.init)) {
module.init(); module.init();
} }
$.each(module, function () { $.each(module, function () {
if ($.isPlainObject(this)) { if ($.isPlainObject(this)) {
pub.initModule(this); pub.initModule(this);
} }
}); });
} }
}, },
init: function () { init: function () {
initCsrfHandler(); initCsrfHandler();
initRedirectHandler(); initRedirectHandler();
initScriptFilter(); initScriptFilter();
initDataMethods(); initDataMethods();
} }
}; };
function initRedirectHandler() { function initRedirectHandler() {
// handle AJAX redirection // handle AJAX redirection
$(document).ajaxComplete(function (event, xhr, settings) { $(document).ajaxComplete(function (event, xhr, settings) {
var url = xhr.getResponseHeader('X-Redirect'); var url = xhr.getResponseHeader('X-Redirect');
if (url) { if (url) {
window.location = url; window.location = url;
} }
}); });
} }
function initCsrfHandler() { function initCsrfHandler() {
// automatically send CSRF token for all AJAX requests // automatically send CSRF token for all AJAX requests
$.ajaxPrefilter(function (options, originalOptions, xhr) { $.ajaxPrefilter(function (options, originalOptions, xhr) {
if (!options.crossDomain && pub.getCsrfParam()) { if (!options.crossDomain && pub.getCsrfParam()) {
xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken()); xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken());
} }
}); });
} }
function initDataMethods() { function initDataMethods() {
var $document = $(document); var $document = $(document);
// handle data-confirm and data-method for clickable elements // handle data-confirm and data-method for clickable elements
$document.on('click.yii', pub.clickableSelector, function (event) { $document.on('click.yii', pub.clickableSelector, function (event) {
var $this = $(this); var $this = $(this);
if (pub.allowAction($this)) { if (pub.allowAction($this)) {
return pub.handleAction($this); return pub.handleAction($this);
} else { } else {
event.stopImmediatePropagation(); event.stopImmediatePropagation();
return false; return false;
} }
}); });
// handle data-confirm and data-method for changeable elements // handle data-confirm and data-method for changeable elements
$document.on('change.yii', pub.changeableSelector, function (event) { $document.on('change.yii', pub.changeableSelector, function (event) {
var $this = $(this); var $this = $(this);
if (pub.allowAction($this)) { if (pub.allowAction($this)) {
return pub.handleAction($this); return pub.handleAction($this);
} else { } else {
event.stopImmediatePropagation(); event.stopImmediatePropagation();
return false; return false;
} }
}); });
} }
function initScriptFilter() { function initScriptFilter() {
var hostInfo = location.protocol + '//' + location.host; var hostInfo = location.protocol + '//' + location.host;
var loadedScripts = $('script[src]').map(function () { var loadedScripts = $('script[src]').map(function () {
return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src; return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src;
}).toArray(); }).toArray();
$.ajaxPrefilter('script', function (options, originalOptions, xhr) { $.ajaxPrefilter('script', function (options, originalOptions, xhr) {
if(options.dataType == 'jsonp') { if (options.dataType == 'jsonp') {
return; return;
} }
var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url; var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url;
if ($.inArray(url, loadedScripts) === -1) { if ($.inArray(url, loadedScripts) === -1) {
loadedScripts.push(url); loadedScripts.push(url);
} else { } else {
var found = $.inArray(url, $.map(pub.reloadableScripts, function (script) { var found = $.inArray(url, $.map(pub.reloadableScripts, function (script) {
return script.charAt(0) === '/' ? hostInfo + script : script; return script.charAt(0) === '/' ? hostInfo + script : script;
})) !== -1; })) !== -1;
if (!found) { if (!found) {
xhr.abort(); xhr.abort();
} }
} }
}); });
} }
return pub; return pub;
})(jQuery); })(jQuery);
jQuery(document).ready(function () { jQuery(document).ready(function () {
yii.initModule(yii); yii.initModule(yii);
}); });
...@@ -11,218 +11,218 @@ ...@@ -11,218 +11,218 @@
*/ */
yii.validation = (function ($) { yii.validation = (function ($) {
var pub = { var pub = {
isEmpty: function (value) { isEmpty: function (value) {
return value === null || value === undefined || value == [] || value === ''; return value === null || value === undefined || value == [] || value === '';
}, },
addMessage: function (messages, message, value) { addMessage: function (messages, message, value) {
messages.push(message.replace(/\{value\}/g, value)); messages.push(message.replace(/\{value\}/g, value));
}, },
required: function (value, messages, options) { required: function (value, messages, options) {
var valid = false; var valid = false;
if (options.requiredValue === undefined) { if (options.requiredValue === undefined) {
var isString = typeof value == 'string' || value instanceof String; var isString = typeof value == 'string' || value instanceof String;
if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) { if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) {
valid = true; valid = true;
} }
} else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) { } else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
valid = true; valid = true;
} }
if (!valid) { if (!valid) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
boolean: function (value, messages, options) { boolean: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
var valid = !options.strict && (value == options.trueValue || value == options.falseValue) var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
|| options.strict && (value === options.trueValue || value === options.falseValue); || options.strict && (value === options.trueValue || value === options.falseValue);
if (!valid) { if (!valid) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
string: function (value, messages, options) { string: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
if (typeof value !== 'string') { if (typeof value !== 'string') {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
return; return;
} }
if (options.min !== undefined && value.length < options.min) { if (options.min !== undefined && value.length < options.min) {
pub.addMessage(messages, options.tooShort, value); pub.addMessage(messages, options.tooShort, value);
} }
if (options.max !== undefined && value.length > options.max) { if (options.max !== undefined && value.length > options.max) {
pub.addMessage(messages, options.tooLong, value); pub.addMessage(messages, options.tooLong, value);
} }
if (options.is !== undefined && value.length != options.is) { if (options.is !== undefined && value.length != options.is) {
pub.addMessage(messages, options.is, value); pub.addMessage(messages, options.is, value);
} }
}, },
number: function (value, messages, options) { number: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
if (typeof value === 'string' && !value.match(options.pattern)) { if (typeof value === 'string' && !value.match(options.pattern)) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
return; return;
} }
if (options.min !== undefined && value < options.min) { if (options.min !== undefined && value < options.min) {
pub.addMessage(messages, options.tooSmall, value); pub.addMessage(messages, options.tooSmall, value);
} }
if (options.max !== undefined && value > options.max) { if (options.max !== undefined && value > options.max) {
pub.addMessage(messages, options.tooBig, value); pub.addMessage(messages, options.tooBig, value);
} }
}, },
range: function (value, messages, options) { range: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
var valid = !options.not && $.inArray(value, options.range) > -1 var valid = !options.not && $.inArray(value, options.range) > -1
|| options.not && $.inArray(value, options.range) == -1; || options.not && $.inArray(value, options.range) == -1;
if (!valid) { if (!valid) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
regularExpression: function (value, messages, options) { regularExpression: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) { if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
email: function (value, messages, options) { email: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
var valid = true; var valid = true;
if (options.enableIDN) { if (options.enableIDN) {
var regexp = /^(.*<?)(.*)@(.*)(>?)$/, var regexp = /^(.*<?)(.*)@(.*)(>?)$/,
matches = regexp.exec(value); matches = regexp.exec(value);
if (matches === null) { if (matches === null) {
valid = false; valid = false;
} else { } else {
value = matches[1] + punycode.toASCII(matches[2]) + '@' + punycode.toASCII(matches[3]) + matches[4]; value = matches[1] + punycode.toASCII(matches[2]) + '@' + punycode.toASCII(matches[3]) + matches[4];
} }
} }
if (!valid || !(value.match(options.pattern) || (options.allowName && value.match(options.fullPattern)))) { if (!valid || !(value.match(options.pattern) || (options.allowName && value.match(options.fullPattern)))) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
url: function (value, messages, options) { url: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
if (options.defaultScheme && !value.match(/:\/\//)) { if (options.defaultScheme && !value.match(/:\/\//)) {
value = options.defaultScheme + '://' + value; value = options.defaultScheme + '://' + value;
} }
var valid = true; var valid = true;
if (options.enableIDN) { if (options.enableIDN) {
var regexp = /^([^:]+):\/\/([^\/]+)(.*)$/, var regexp = /^([^:]+):\/\/([^\/]+)(.*)$/,
matches = regexp.exec(value); matches = regexp.exec(value);
if (matches === null) { if (matches === null) {
valid = false; valid = false;
} else { } else {
value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3]; value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3];
} }
} }
if (!valid || !value.match(options.pattern)) { if (!valid || !value.match(options.pattern)) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
captcha: function (value, messages, options) { captcha: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
// CAPTCHA may be updated via AJAX and the updated hash is stored in body data // CAPTCHA may be updated via AJAX and the updated hash is stored in body data
var hash = $('body').data(options.hashKey); var hash = $('body').data(options.hashKey);
if (hash == null) { if (hash == null) {
hash = options.hash; hash = options.hash;
} else { } else {
hash = hash[options.caseSensitive ? 0 : 1]; hash = hash[options.caseSensitive ? 0 : 1];
} }
var v = options.caseSensitive ? value : value.toLowerCase(); var v = options.caseSensitive ? value : value.toLowerCase();
for (var i = v.length - 1, h = 0; i >= 0; --i) { for (var i = v.length - 1, h = 0; i >= 0; --i) {
h += v.charCodeAt(i); h += v.charCodeAt(i);
} }
if (h != hash) { if (h != hash) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
}, },
compare: function (value, messages, options) { compare: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) { if (options.skipOnEmpty && pub.isEmpty(value)) {
return; return;
} }
var compareValue, valid = true; var compareValue, valid = true;
if (options.compareAttribute === undefined) { if (options.compareAttribute === undefined) {
compareValue = options.compareValue; compareValue = options.compareValue;
} else { } else {
compareValue = $('#' + options.compareAttribute).val(); compareValue = $('#' + options.compareAttribute).val();
} }
switch (options.operator) { switch (options.operator) {
case '==': case '==':
valid = value == compareValue; valid = value == compareValue;
break; break;
case '===': case '===':
valid = value === compareValue; valid = value === compareValue;
break; break;
case '!=': case '!=':
valid = value != compareValue; valid = value != compareValue;
break; break;
case '!==': case '!==':
valid = value !== compareValue; valid = value !== compareValue;
break; break;
case '>': case '>':
valid = value > compareValue; valid = value > compareValue;
break; break;
case '>=': case '>=':
valid = value >= compareValue; valid = value >= compareValue;
break; break;
case '<': case '<':
valid = value < compareValue; valid = value < compareValue;
break; break;
case '<=': case '<=':
valid = value <= compareValue; valid = value <= compareValue;
break; break;
default: default:
valid = false; valid = false;
break; break;
} }
if (!valid) { if (!valid) {
pub.addMessage(messages, options.message, value); pub.addMessage(messages, options.message, value);
} }
} }
}; };
return pub; return pub;
})(jQuery); })(jQuery);
...@@ -124,11 +124,20 @@ abstract class Application extends Module ...@@ -124,11 +124,20 @@ abstract class Application extends Module
* 'name' => 'extension name', * 'name' => 'extension name',
* 'version' => 'version number', * 'version' => 'version number',
* 'bootstrap' => 'BootstrapClassName', * 'bootstrap' => 'BootstrapClassName',
* 'alias' => [
* '@alias1' => 'to/path1',
* '@alias2' => 'to/path2',
* ],
* ] * ]
* ~~~ * ~~~
*/ */
public $extensions = []; public $extensions = [];
/** /**
* @var array list of bootstrap classes. A bootstrap class must have a public static method named
* `bootstrap()`. The method will be called during [[init()]] for every bootstrap class.
*/
public $bootstrap = [];
/**
* @var \Exception the exception that is being handled currently. When this is not null, * @var \Exception the exception that is being handled currently. When this is not null,
* it means the application is handling some exception and extra care should be taken. * it means the application is handling some exception and extra care should be taken.
*/ */
...@@ -205,6 +214,10 @@ abstract class Application extends Module ...@@ -205,6 +214,10 @@ abstract class Application extends Module
public function init() public function init()
{ {
$this->initExtensions($this->extensions); $this->initExtensions($this->extensions);
foreach ($this->bootstrap as $class) {
/** @var Extension $class */
$class::bootstrap();
}
parent::init(); parent::init();
} }
...@@ -224,7 +237,7 @@ abstract class Application extends Module ...@@ -224,7 +237,7 @@ abstract class Application extends Module
if (isset($extension['bootstrap'])) { if (isset($extension['bootstrap'])) {
/** @var Extension $class */ /** @var Extension $class */
$class = $extension['bootstrap']; $class = $extension['bootstrap'];
$class::init(); $class::bootstrap();
} }
} }
} }
......
...@@ -11,7 +11,7 @@ namespace yii\base; ...@@ -11,7 +11,7 @@ namespace yii\base;
* Extension is the base class that may be extended by individual extensions. * Extension is the base class that may be extended by individual extensions.
* *
* Extension serves as the bootstrap class for extensions. When an extension * Extension serves as the bootstrap class for extensions. When an extension
* is installed via composer, the [[init()]] method of its Extension class (if any) * is installed via composer, the [[bootstrap()]] method of its Extension class (if any)
* will be invoked during the application initialization stage. * will be invoked during the application initialization stage.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
...@@ -21,9 +21,9 @@ class Extension ...@@ -21,9 +21,9 @@ class Extension
{ {
/** /**
* Initializes the extension. * Initializes the extension.
* This method is invoked at the end of [[Application::init()]]. * This method is invoked at the beginning of [[Application::init()]].
*/ */
public static function init() public static function bootstrap()
{ {
} }
} }
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace yii\db; namespace yii\db;
use Yii;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\helpers\Inflector; use yii\helpers\Inflector;
use yii\helpers\StringHelper; use yii\helpers\StringHelper;
...@@ -376,6 +377,7 @@ class ActiveRecord extends BaseActiveRecord ...@@ -376,6 +377,7 @@ class ActiveRecord extends BaseActiveRecord
public function insert($runValidation = true, $attributes = null) public function insert($runValidation = true, $attributes = null)
{ {
if ($runValidation && !$this->validate($attributes)) { if ($runValidation && !$this->validate($attributes)) {
Yii::info('Model not inserted due to validation error.', __METHOD__);
return false; return false;
} }
$db = static::getDb(); $db = static::getDb();
...@@ -493,6 +495,7 @@ class ActiveRecord extends BaseActiveRecord ...@@ -493,6 +495,7 @@ class ActiveRecord extends BaseActiveRecord
public function update($runValidation = true, $attributes = null) public function update($runValidation = true, $attributes = null)
{ {
if ($runValidation && !$this->validate($attributes)) { if ($runValidation && !$this->validate($attributes)) {
Yii::info('Model not updated due to validation error.', __METHOD__);
return false; return false;
} }
$db = static::getDb(); $db = static::getDb();
......
...@@ -219,7 +219,7 @@ class GridView extends BaseListView ...@@ -219,7 +219,7 @@ class GridView extends BaseListView
*/ */
protected function getClientOptions() protected function getClientOptions()
{ {
$filterUrl = isset($this->filterUrl) ? $this->filterUrl : [Yii::$app->controller->action->id]; $filterUrl = isset($this->filterUrl) ? $this->filterUrl : Yii::$app->request->url;
$id = $this->filterRowOptions['id']; $id = $this->filterRowOptions['id'];
$filterSelector = "#$id input, #$id select"; $filterSelector = "#$id input, #$id select";
if (isset($this->filterSelector)) { if (isset($this->filterSelector)) {
......
...@@ -10,6 +10,7 @@ namespace yii\log; ...@@ -10,6 +10,7 @@ namespace yii\log;
use Yii; use Yii;
use yii\base\Component; use yii\base\Component;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\web\Request;
/** /**
* Target is the base class for all log target classes. * Target is the base class for all log target classes.
...@@ -52,17 +53,18 @@ abstract class Target extends Component ...@@ -52,17 +53,18 @@ abstract class Target extends Component
*/ */
public $except = []; public $except = [];
/** /**
* @var boolean whether to log a message containing the current user name and ID. Defaults to false.
* @see \yii\web\User
*/
public $logUser = false;
/**
* @var array list of the PHP predefined variables that should be logged in a message. * @var array list of the PHP predefined variables that should be logged in a message.
* Note that a variable must be accessible via `$GLOBALS`. Otherwise it won't be logged. * Note that a variable must be accessible via `$GLOBALS`. Otherwise it won't be logged.
* Defaults to `['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER']`. * Defaults to `['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER']`.
*/ */
public $logVars = ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER']; public $logVars = ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'];
/** /**
* @var callable a PHP callable that returns a string to be prefix to every exported message.
* If not set, [[getMessagePrefix()]] will be used, which prefixes user IP, user ID and session ID
* to every message. The signature of the callable should be `function ($message)`.
*/
public $prefix;
/**
* @var integer how many messages should be accumulated before they are exported. * @var integer how many messages should be accumulated before they are exported.
* Defaults to 1000. Note that messages will always be exported when the application terminates. * Defaults to 1000. Note that messages will always be exported when the application terminates.
* Set this property to be 0 if you don't want to export messages until the application terminates. * Set this property to be 0 if you don't want to export messages until the application terminates.
...@@ -111,11 +113,6 @@ abstract class Target extends Component ...@@ -111,11 +113,6 @@ abstract class Target extends Component
protected function getContextMessage() protected function getContextMessage()
{ {
$context = []; $context = [];
if ($this->logUser && ($user = Yii::$app->getComponent('user', false)) !== null) {
/** @var \yii\web\User $user */
$context[] = 'User: ' . $user->getId();
}
foreach ($this->logVars as $name) { foreach ($this->logVars as $name) {
if (!empty($GLOBALS[$name])) { if (!empty($GLOBALS[$name])) {
$context[] = "\${$name} = " . var_export($GLOBALS[$name], true); $context[] = "\${$name} = " . var_export($GLOBALS[$name], true);
...@@ -233,8 +230,28 @@ abstract class Target extends Component ...@@ -233,8 +230,28 @@ abstract class Target extends Component
if (!is_string($text)) { if (!is_string($text)) {
$text = var_export($text, true); $text = var_export($text, true);
} }
$ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
return date('Y/m/d H:i:s', $timestamp) . " [$ip] [$level] [$category] $text"; $prefix = $this->prefix ? call_user_func($this->prefix, $message) : $this->getMessagePrefix($message);
return date('Y/m/d H:i:s', $timestamp) . " $prefix [$level] [$category] $text";
}
/**
* Returns a string to be prefixed to the given message.
* The default implementation will return user IP, user ID and session ID as a prefix.
* @param array $message the message being exported
* @return string the prefix string
*/
public function getMessagePrefix($message)
{
$request = Yii::$app->getRequest();
$ip = $request instanceof Request ? $request->getUserIP() : '-';
/** @var \yii\web\User $user */
$user = Yii::$app->getComponent('user', false);
$userID = $user ? $user->getId(false) : '-';
/** @var \yii\web\Session $session */
$session = Yii::$app->getComponent('session', false);
$sessionID = $session && $session->getIsActive() ? $session->getId() : '-';
return "[$ip] [$userID] [$sessionID]";
} }
} }
...@@ -7,7 +7,7 @@ return [ ...@@ -7,7 +7,7 @@ return [
'messagePath' => __DIR__, 'messagePath' => __DIR__,
// array, required, list of language codes that the extracted messages // array, required, list of language codes that the extracted messages
// should be translated to. For example, ['zh-CN', 'de']. // should be translated to. For example, ['zh-CN', 'de'].
'languages' => ['ar', 'da', 'de', 'el', 'es', 'fa-IR', 'fr', 'it', 'ja', 'kz', 'lv', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sr', 'sr-Latn', 'uk', 'zh-CN'], 'languages' => ['ar', 'da', 'de', 'el', 'es', 'fa-IR', 'fi', 'fr', 'it', 'ja', 'kz', 'lv', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sr', 'sr-Latn', 'uk', 'zh-CN'],
// string, the name of the function for translating messages. // string, the name of the function for translating messages.
// Defaults to 'Yii::t'. This is used as a mark to find the messages to be // Defaults to 'Yii::t'. This is used as a mark to find the messages to be
// translated. You may use a string for single function name or an array for // translated. You may use a string for single function name or an array for
......
<?php
/**
* Message translations.
*
* This file is automatically generated by 'yii message' command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of '@@' marks.
*
* Message string can be used with plural forms format. Check i18n section
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return array (
'(not set)' => '(ei asetettu)',
'An internal server error occurred.' => 'Sisäinen palvelinvirhe.',
'Are you sure you want to delete this item?' => 'Haluatko varmasti poistaa tämän?',
'Delete' => 'Poista',
'Error' => 'Virhe',
'File upload failed.' => 'Tiedoston lähetys epäonnistui.',
'Home' => 'Koti',
'Invalid data received for parameter "{param}".' => 'Parametri "{param}" vastaanotti virheellistä dataa.',
'Login Required' => 'Kirjautuminen vaaditaan',
'Missing required arguments: {params}' => 'Pakolliset argumentit puuttuu: {params}',
'Missing required parameters: {params}' => 'Pakolliset parametrit puuttuu: {params}',
'No' => 'Ei',
'No help for unknown command "{command}".' => 'Ei ohjetta tuntemattomalle komennolle "{command}".',
'No help for unknown sub-command "{command}".' => 'Ei ohjetta tuntemattomalle alikomennolle "{command}".',
'No results found.' => 'Ei tuloksia.',
'Only files with these extensions are allowed: {extensions}.' => 'Sallittuja ovat vain tiedostot, joiden tiedostopääte on: {extensions}.',
'Only files with these MIME types are allowed: {mimeTypes}.' => 'Sallittuja ovat vain tiedostot, joiden MIME-tyyppi on: {mimeTypes}.',
'Page not found.' => 'Sivua ei löytynyt.',
'Please fix the following errors:' => 'Korjaa seuraavat virheet:',
'Please upload a file.' => 'Lähetä tiedosto.',
'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.' => 'Näytetään <b>{begin, number}-{end, number}</b> kaikkiaan <b>{totalCount, number}</b> {totalCount, plural, one{tuloksesta} other{tuloksesta}}.',
'The file "{file}" is not an image.' => 'Tiedosto "{file}" ei ole kuva.',
'The file "{file}" is too big. Its size cannot exceed {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Tiedosto "{file}" on liian iso. Sen koko ei voi olla suurempi kuin {limit, number} {limit, plural, one{tavu} other{tavua}}.',
'The file "{file}" is too small. Its size cannot be smaller than {limit, number} {limit, plural, one{byte} other{bytes}}.' => 'Tiedosto "{file}" on liian pieni. Sen koko ei voi olla pienempi kuin {limit, number} {limit, plural, one{tavu} other{tavua}}.',
'The format of {attribute} is invalid.' => 'Attribuutin {attribute} formaatti on virheellinen.',
'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian suuri. Korkeus ei voi olla suurempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
'The image "{file}" is too large. The width cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian suuri. Leveys ei voi olla suurempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
'The image "{file}" is too small. The height cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian pieni. Korkeus ei voi olla pienempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
'The image "{file}" is too small. The width cannot be smaller than {limit, number} {limit, plural, one{pixel} other{pixels}}.' => 'Kuva "{file}" on liian pieni. Leveys ei voi olla pienempi kuin {limit, number} {limit, plural, one{pikseli} other{pikseliä}}.',
'The verification code is incorrect.' => 'Vahvistuskoodi on virheellinen.',
'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.' => 'Yhteensä <b>{count, number}</b> {count, plural, one{tulos} other{tulosta}}.',
'Unable to verify your data submission.' => 'Tietojen lähetystä ei voida varmistaa.',
'Unknown command "{command}".' => 'Tuntematon komento "{command}".',
'Unknown option: --{name}' => 'Tuntematon valinta: --{name}',
'Update' => 'Päivitä',
'View' => 'Näytä',
'Yes' => 'Kyllä',
'You are not allowed to perform this action.' => 'Sinulla ei ole tarvittavia oikeuksia toiminnon suorittamiseen.',
'You can upload at most {limit, number} {limit, plural, one{file} other{files}}.' => 'Voit lähettää enintään {limit, number} {limit, plural, one{tiedoston} other{tiedostoa}}.',
'the input value' => 'tuloarvo',
'{attribute} "{value}" has already been taken.' => '{attribute} "{value}" on jo käytössä.',
'{attribute} cannot be blank.' => '{attribute} ei voi olla tyhjä.',
'{attribute} is invalid.' => '{attribute} on virheellinen.',
'{attribute} is not a valid URL.' => '{attribute} on virheellinen URL.',
'{attribute} is not a valid email address.' => '{attribute} on virheellinen sähköpostiosoite.',
'{attribute} must be "{requiredValue}".' => '{attribute} täytyy olla "{requiredValue}".',
'{attribute} must be a number.' => '{attribute} täytyy olla luku.',
'{attribute} must be a string.' => '{attribute} täytyy olla merkkijono.',
'{attribute} must be an integer.' => '{attribute} täytyy olla kokonaisluku.',
'{attribute} must be either "{true}" or "{false}".' => '{attribute} täytyy olla joko {true} tai {false}.',
'{attribute} must be greater than "{compareValue}".' => '{attribute} täytyy olla suurempi kuin "{compareValue}".',
'{attribute} must be greater than or equal to "{compareValue}".' => '{attribute} täytyy olla suurempi tai yhtä suuri kuin "{compareValue}".',
'{attribute} must be less than "{compareValue}".' => '{attribute} täytyy olla pienempi kuin "{compareValue}".',
'{attribute} must be less than or equal to "{compareValue}".' => '{attribute} täytyy olla pienempi tai yhtä suuri kuin "{compareValue}".',
'{attribute} must be no greater than {max}.' => '{attribute} ei saa olla suurempi kuin "{max}".',
'{attribute} must be no less than {min}.' => '{attribute} ei saa olla pienempi kuin "{min}".',
'{attribute} must be repeated exactly.' => '{attribute} täytyy toistaa täsmälleen.',
'{attribute} must not be equal to "{compareValue}".' => '{attribute} ei saa olla yhtä suuri kuin "{compareValue}".',
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää vähintään {min, number} {min, plural, one{merkki} other{merkkiä}}.',
'{attribute} should contain at most {max, number} {max, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää enintään {max, number} {max, plural, one{merkki} other{merkkiä}}.',
'{attribute} should contain {length, number} {length, plural, one{character} other{characters}}.' => '{attribute} tulisi sisältää {length, number} {length, plural, one{merkki} other{merkkiä}}.',
'{n, plural, =1{# byte} other{# bytes}}' => '{n, plural, =1{# tavu} other{# tavua}}',
'{n, plural, =1{# gigabyte} other{# gigabytes}}' => '{n, plural, =1{# gigatavu} other{# gigatavua}}',
'{n, plural, =1{# kilobyte} other{# kilobytes}}' => '{n, plural, =1{# kilotavu} other{# kilotavua}}',
'{n, plural, =1{# megabyte} other{# megabytes}}' => '{n, plural, =1{# megatavu} other{# megatavua}}',
'{n, plural, =1{# petabyte} other{# petabytes}}' => '{n, plural, =1{# petatavu} other{# petatavua}}',
'{n, plural, =1{# terabyte} other{# terabytes}}' => '{n, plural, =1{# teratavu} other{# teratavua}}',
'{n} B' => '{n} t',
'{n} GB' => '{n} Gt',
'{n} KB' => '{n} kt',
'{n} MB' => '{n} Mt',
'{n} PB' => '{n} Pt',
'{n} TB' => '{n} Tt',
);
...@@ -72,7 +72,7 @@ return array ( ...@@ -72,7 +72,7 @@ return array (
'{attribute} must be less than "{compareValue}".' => '{attribute} moet minder zijn dan "{compareValue}".', '{attribute} must be less than "{compareValue}".' => '{attribute} moet minder zijn dan "{compareValue}".',
'{attribute} must be less than or equal to "{compareValue}".' => '{attribute} moet minder dan of gelijk aan "{compareValue}" zijn.', '{attribute} must be less than or equal to "{compareValue}".' => '{attribute} moet minder dan of gelijk aan "{compareValue}" zijn.',
'{attribute} must be no greater than {max}.' => '{attribute} mag niet groter zijn dan {max}.', '{attribute} must be no greater than {max}.' => '{attribute} mag niet groter zijn dan {max}.',
'{attribute} must be no less than {min}.' => '{attribute} mag niet kleiner zijn dan {max}.', '{attribute} must be no less than {min}.' => '{attribute} mag niet kleiner zijn dan {min}.',
'{attribute} must be repeated exactly.' => '{attribute} moet exact herhaald worden.', '{attribute} must be repeated exactly.' => '{attribute} moet exact herhaald worden.',
'{attribute} must not be equal to "{compareValue}".' => '{attribute} mag niet gelijk zijn aan "{compareValue}".', '{attribute} must not be equal to "{compareValue}".' => '{attribute} mag niet gelijk zijn aan "{compareValue}".',
'{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} moet minstens {min, number} {min, plural, one{karakter} other{karakters}} bevatten.', '{attribute} should contain at least {min, number} {min, plural, one{character} other{characters}}.' => '{attribute} moet minstens {min, number} {min, plural, one{karakter} other{karakters}} bevatten.',
......
...@@ -65,7 +65,7 @@ class YiiRequirementChecker ...@@ -65,7 +65,7 @@ class YiiRequirementChecker
* If a string, it is treated as the path of the file, which contains the requirements; * If a string, it is treated as the path of the file, which contains the requirements;
* @return static self instance. * @return static self instance.
*/ */
public function check($requirements) function check($requirements)
{ {
if (is_string($requirements)) { if (is_string($requirements)) {
$requirements = require($requirements); $requirements = require($requirements);
...@@ -110,7 +110,7 @@ class YiiRequirementChecker ...@@ -110,7 +110,7 @@ class YiiRequirementChecker
* Performs the check for the Yii core requirements. * Performs the check for the Yii core requirements.
* @return YiiRequirementChecker self instance. * @return YiiRequirementChecker self instance.
*/ */
public function checkYii() function checkYii()
{ {
return $this->check(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'requirements.php'); return $this->check(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'requirements.php');
} }
...@@ -137,7 +137,7 @@ class YiiRequirementChecker ...@@ -137,7 +137,7 @@ class YiiRequirementChecker
* ) * )
* ``` * ```
*/ */
public function getResult() function getResult()
{ {
if (isset($this->result)) { if (isset($this->result)) {
return $this->result; return $this->result;
...@@ -150,7 +150,7 @@ class YiiRequirementChecker ...@@ -150,7 +150,7 @@ class YiiRequirementChecker
* Renders the requirements check result. * Renders the requirements check result.
* The output will vary depending is a script running from web or from console. * The output will vary depending is a script running from web or from console.
*/ */
public function render() function render()
{ {
if (!isset($this->result)) { if (!isset($this->result)) {
$this->usageError('Nothing to render!'); $this->usageError('Nothing to render!');
...@@ -171,7 +171,7 @@ class YiiRequirementChecker ...@@ -171,7 +171,7 @@ class YiiRequirementChecker
* @param string $compare comparison operator, by default '>=' * @param string $compare comparison operator, by default '>='
* @return boolean if PHP extension version matches. * @return boolean if PHP extension version matches.
*/ */
public function checkPhpExtensionVersion($extensionName, $version, $compare = '>=') function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
{ {
if (!extension_loaded($extensionName)) { if (!extension_loaded($extensionName)) {
return false; return false;
...@@ -192,7 +192,7 @@ class YiiRequirementChecker ...@@ -192,7 +192,7 @@ class YiiRequirementChecker
* @param string $name configuration option name. * @param string $name configuration option name.
* @return boolean option is on. * @return boolean option is on.
*/ */
public function checkPhpIniOn($name) function checkPhpIniOn($name)
{ {
$value = ini_get($name); $value = ini_get($name);
if (empty($value)) { if (empty($value)) {
...@@ -207,7 +207,7 @@ class YiiRequirementChecker ...@@ -207,7 +207,7 @@ class YiiRequirementChecker
* @param string $name configuration option name. * @param string $name configuration option name.
* @return boolean option is off. * @return boolean option is off.
*/ */
public function checkPhpIniOff($name) function checkPhpIniOff($name)
{ {
$value = ini_get($name); $value = ini_get($name);
if (empty($value)) { if (empty($value)) {
...@@ -225,7 +225,7 @@ class YiiRequirementChecker ...@@ -225,7 +225,7 @@ class YiiRequirementChecker
* @param string $compare comparison operator, by default '>='. * @param string $compare comparison operator, by default '>='.
* @return boolean comparison result. * @return boolean comparison result.
*/ */
public function compareByteSize($a, $b, $compare = '>=') function compareByteSize($a, $b, $compare = '>=')
{ {
$compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')'; $compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')';
...@@ -238,7 +238,7 @@ class YiiRequirementChecker ...@@ -238,7 +238,7 @@ class YiiRequirementChecker
* @param string $verboseSize verbose size representation. * @param string $verboseSize verbose size representation.
* @return integer actual size in bytes. * @return integer actual size in bytes.
*/ */
public function getByteSize($verboseSize) function getByteSize($verboseSize)
{ {
if (empty($verboseSize)) { if (empty($verboseSize)) {
return 0; return 0;
...@@ -277,7 +277,7 @@ class YiiRequirementChecker ...@@ -277,7 +277,7 @@ class YiiRequirementChecker
* @param string|null $max verbose file size maximum required value, pass null to skip maximum check. * @param string|null $max verbose file size maximum required value, pass null to skip maximum check.
* @return boolean success. * @return boolean success.
*/ */
public function checkUploadMaxFileSize($min = null, $max = null) function checkUploadMaxFileSize($min = null, $max = null)
{ {
$postMaxSize = ini_get('post_max_size'); $postMaxSize = ini_get('post_max_size');
$uploadMaxFileSize = ini_get('upload_max_filesize'); $uploadMaxFileSize = ini_get('upload_max_filesize');
...@@ -305,7 +305,7 @@ class YiiRequirementChecker ...@@ -305,7 +305,7 @@ class YiiRequirementChecker
* @param boolean $_return_ whether the rendering result should be returned as a string * @param boolean $_return_ whether the rendering result should be returned as a string
* @return string the rendering result. Null if the rendering result is not required. * @return string the rendering result. Null if the rendering result is not required.
*/ */
public function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false) function renderViewFile($_viewFile_, $_data_ = null, $_return_ = false)
{ {
// we use special variable names here to avoid conflict when extracting data // we use special variable names here to avoid conflict when extracting data
if (is_array($_data_)) { if (is_array($_data_)) {
...@@ -330,7 +330,7 @@ class YiiRequirementChecker ...@@ -330,7 +330,7 @@ class YiiRequirementChecker
* @param integer $requirementKey requirement key in the list. * @param integer $requirementKey requirement key in the list.
* @return array normalized requirement. * @return array normalized requirement.
*/ */
public function normalizeRequirement($requirement, $requirementKey = 0) function normalizeRequirement($requirement, $requirementKey = 0)
{ {
if (!is_array($requirement)) { if (!is_array($requirement)) {
$this->usageError('Requirement must be an array!'); $this->usageError('Requirement must be an array!');
...@@ -369,7 +369,7 @@ class YiiRequirementChecker ...@@ -369,7 +369,7 @@ class YiiRequirementChecker
* This method will then terminate the execution of the current application. * This method will then terminate the execution of the current application.
* @param string $message the error message * @param string $message the error message
*/ */
public function usageError($message) function usageError($message)
{ {
echo "Error: $message\n\n"; echo "Error: $message\n\n";
exit(1); exit(1);
...@@ -380,7 +380,7 @@ class YiiRequirementChecker ...@@ -380,7 +380,7 @@ class YiiRequirementChecker
* @param string $expression a PHP expression to be evaluated. * @param string $expression a PHP expression to be evaluated.
* @return mixed the expression result. * @return mixed the expression result.
*/ */
public function evaluateExpression($expression) function evaluateExpression($expression)
{ {
return eval('return ' . $expression . ';'); return eval('return ' . $expression . ';');
} }
...@@ -389,7 +389,7 @@ class YiiRequirementChecker ...@@ -389,7 +389,7 @@ class YiiRequirementChecker
* Returns the server information. * Returns the server information.
* @return string server information. * @return string server information.
*/ */
public function getServerInfo() function getServerInfo()
{ {
$info = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : ''; $info = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';
...@@ -400,7 +400,7 @@ class YiiRequirementChecker ...@@ -400,7 +400,7 @@ class YiiRequirementChecker
* Returns the now date if possible in string representation. * Returns the now date if possible in string representation.
* @return string now date. * @return string now date.
*/ */
public function getNowDate() function getNowDate()
{ {
$nowDate = @strftime('%Y-%m-%d %H:%M', time()); $nowDate = @strftime('%Y-%m-%d %H:%M', time());
......
...@@ -132,7 +132,7 @@ class ImageValidator extends FileValidator ...@@ -132,7 +132,7 @@ class ImageValidator extends FileValidator
$this->overHeight = Yii::t('yii', 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.'); $this->overHeight = Yii::t('yii', 'The image "{file}" is too large. The height cannot be larger than {limit, number} {limit, plural, one{pixel} other{pixels}}.');
} }
if ($this->wrongMimeType === null) { if ($this->wrongMimeType === null) {
$this->wrongMimeType = Yii::t('yii', 'Only files with these mimeTypes are allowed: {mimeTypes}.'); $this->wrongMimeType = Yii::t('yii', 'Only files with these MIME types are allowed: {mimeTypes}.');
} }
if (!is_array($this->mimeTypes)) { if (!is_array($this->mimeTypes)) {
$this->mimeTypes = preg_split('/[\s,]+/', strtolower($this->mimeTypes), -1, PREG_SPLIT_NO_EMPTY); $this->mimeTypes = preg_split('/[\s,]+/', strtolower($this->mimeTypes), -1, PREG_SPLIT_NO_EMPTY);
......
<?php
/**
* @var \Exception $exception
* @var \yii\base\ErrorHandler $handler
*/
?>
<?php if (method_exists($this, 'beginPage')) $this->beginPage(); ?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title><?php
if ($exception instanceof \yii\web\HttpException) {
echo (int) $exception->statusCode . ' ' . $handler->htmlEncode($exception->getName());
} elseif ($exception instanceof \yii\base\Exception) {
echo $handler->htmlEncode($exception->getName() . ' – ' . get_class($exception));
} else {
echo $handler->htmlEncode(get_class($exception));
}
?></title>
<style type="text/css">
/* reset */
html,body,div,span,h1,h2,h3,h4,h5,h6,p,pre,a,code,em,img,strong,b,i,ul,li{
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
body{
line-height: 1;
}
ul{
list-style: none;
}
/* base */
a{
text-decoration: none;
}
a:hover{
text-decoration: underline;
}
h1,h2,h3,p,img,ul li{
font-family: Arial,sans-serif;
color: #505050;
}
html,body{
overflow-x: hidden;
}
/* header */
.header{
min-width: 860px; /* 960px - 50px * 2 */
margin: 0 auto;
background: #f3f3f3;
padding: 40px 50px 30px 50px;
border-bottom: #ccc 1px solid;
}
.header h1{
font-size: 30px;
color: #e57373;
margin-bottom: 30px;
}
.header h1 span, .header h1 span a{
color: #e51717;
}
.header h1 a{
color: #e57373;
}
.header h1 a:hover{
color: #e51717;
}
.header img{
float: right;
margin-top: -15px;
}
.header h2{
font-size: 20px;
line-height: 1.25;
}
/* previous exceptions */
.header .previous{
margin: 20px 0;
padding-left: 30px;
}
.header .previous div{
margin: 20px 0;
}
.header .previous .arrow{
-moz-transform: scale(-1, 1);
-webkit-transform: scale(-1, 1);
-o-transform: scale(-1, 1);
transform: scale(-1, 1);
filter: progid:DXImageTransform.Microsoft.BasicImage(mirror=1);
font-size: 26px;
position: absolute;
margin-top: -5px;
margin-left: -25px;
color: #e51717;
}
.header .previous h2{
font-size: 20px;
color: #e57373;
margin-bottom: 10px;
}
.header .previous h2 span{
color: #e51717;
}
.header .previous h2 a{
color: #e57373;
}
.header .previous h2 a:hover{
color: #e51717;
}
.header .previous h3{
font-size: 14px;
margin: 10px 0;
}
.header .previous p{
font-size: 14px;
color: #aaa;
}
/* call stack */
.call-stack{
margin-top: 30px;
margin-bottom: 40px;
}
.call-stack ul li{
margin: 1px 0;
}
.call-stack ul li .element-wrap{
cursor: pointer;
padding: 15px 0;
}
.call-stack ul li.application .element-wrap{
background-color: #fafafa;
}
.call-stack ul li .element-wrap:hover{
background-color: #edf9ff;
}
.call-stack ul li .element{
min-width: 860px; /* 960px - 50px * 2 */
margin: 0 auto;
padding: 0 50px;
position: relative;
}
.call-stack ul li a{
color: #505050;
}
.call-stack ul li a:hover{
color: #000;
}
.call-stack ul li .item-number{
width: 45px;
display: inline-block;
}
.call-stack ul li .text{
color: #aaa;
}
.call-stack ul li.application .text{
color: #505050;
}
.call-stack ul li .at{
position: absolute;
right: 110px; /* 50px + 60px */
color: #aaa;
}
.call-stack ul li.application .at{
color: #505050;
}
.call-stack ul li .line{
position: absolute;
right: 50px;
width: 60px;
text-align: right;
}
.call-stack ul li .code-wrap{
display: none;
position: relative;
}
.call-stack ul li.application .code-wrap{
display: block;
}
.call-stack ul li .error-line,
.call-stack ul li .hover-line{
background-color: #ffebeb;
position: absolute;
width: 100%;
z-index: 100;
margin-top: -61px;
}
.call-stack ul li .hover-line{
background: none;
}
.call-stack ul li .hover-line.hover,
.call-stack ul li .hover-line:hover{
background: #edf9ff !important;
}
.call-stack ul li .code{
min-width: 860px; /* 960px - 50px * 2 */
margin: 15px auto;
padding: 0 50px;
position: relative;
}
.call-stack ul li .code .lines-item{
position: absolute;
z-index: 200;
display: block;
width: 25px;
text-align: right;
color: #aaa;
line-height: 20px;
font-size: 12px;
margin-top: -63px;
font-family: Consolas, Courier New, monospace;
}
.call-stack ul li .code pre{
position: relative;
z-index: 200;
left: 50px;
line-height: 20px;
font-size: 12px;
font-family: Consolas, Courier New, monospace;
display: inline;
}
@-moz-document url-prefix() {
.call-stack ul li .code pre{
line-height: 20px;
}
}
/* request */
.request{
background-color: #fafafa;
padding-top: 40px;
padding-bottom: 40px;
margin-top: 40px;
margin-bottom: 1px;
}
.request .code{
min-width: 860px; /* 960px - 50px * 2 */
margin: 0 auto;
padding: 15px 50px;
}
.request .code pre{
font-size: 14px;
line-height: 18px;
font-family: Consolas, Courier New, monospace;
display: inline;
word-wrap: break-word;
}
/* footer */
.footer{
position: relative;
height: 222px;
min-width: 860px; /* 960px - 50px * 2 */
padding: 0 50px;
margin: 1px auto 0 auto;
}
.footer p{
font-size: 16px;
padding-bottom: 10px;
}
.footer p a{
color: #505050;
}
.footer p a:hover{
color: #000;
}
.footer .timestamp{
font-size: 14px;
padding-top: 67px;
margin-bottom: 28px;
}
.footer img{
position: absolute;
right: -50px;
}
/* highlight.js */
pre .subst,pre .title{
font-weight: normal;
color: #505050;
}
pre .comment,pre .template_comment,pre .javadoc,pre .diff .header{
color: #808080;
font-style: italic;
}
pre .annotation,pre .decorator,pre .preprocessor,pre .doctype,pre .pi,pre .chunk,pre .shebang,pre .apache .cbracket,
pre .prompt,pre .http .title{
color: #808000;
}
pre .tag,pre .pi{
background: #efefef;
}
pre .tag .title,pre .id,pre .attr_selector,pre .pseudo,pre .literal,pre .keyword,pre .hexcolor,pre .css .function,
pre .ini .title,pre .css .class,pre .list .title,pre .clojure .title,pre .nginx .title,pre .tex .command,
pre .request,pre .status{
color: #000080;
}
pre .attribute,pre .rules .keyword,pre .number,pre .date,pre .regexp,pre .tex .special{
color: #00a;
}
pre .number,pre .regexp{
font-weight: normal;
}
pre .string,pre .value,pre .filter .argument,pre .css .function .params,pre .apache .tag{
color: #0a0;
}
pre .symbol,pre .ruby .symbol .string,pre .char,pre .tex .formula{
color: #505050;
background: #d0eded;
font-style: italic;
}
pre .phpdoc,pre .yardoctag,pre .javadoctag{
text-decoration: underline;
}
pre .variable,pre .envvar,pre .apache .sqbracket,pre .nginx .built_in{
color: #a00;
}
pre .addition{
background: #baeeba;
}
pre .deletion{
background: #ffc8bd;
}
pre .diff .change{
background: #bccff9;
}
</style>
</head>
<body>
<div class="header">
<?php if ($exception instanceof \yii\base\ErrorException): ?>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEwAAABACAMAAACHi2FiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6Mjk0MTdEMEI1QjhGMTFFM0I3QzE5ODkzMUQwNUQyMzYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Mjk0MTdEMEE1QjhGMTFFM0I3QzE5ODkzMUQwNUQyMzYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NThCMjFBODBDNTUwMTFFMkE0QzFFREYxQTMyMDUzRTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NThCMjFBODFDNTUwMTFFMkE0QzFFREYxQTMyMDUzRTEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6hNq0vAAACylBMVEXz8/Plc3P////m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" alt="Error"/>
<h1>
<span><?= $handler->htmlEncode($exception->getName()) ?></span>
&ndash; <?= $handler->addTypeLinks(get_class($exception)) ?>
</h1>
<?php else: ?>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAA6CAMAAAA3Dq9LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUFDNzhCNUM1QjhDMTFFM0I3QzE5ODkzMUQwNUQyMzYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUFDNzhCNUI1QjhDMTFFM0I3QzE5ODkzMUQwNUQyMzYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NzBFREE5RDFDNDdEMTFFMkJGNUU4MkNCQUY4MUM3RUEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NzBFREE5RDJDNDdEMTFFMkJGNUU4MkNCQUY4MUM3RUEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5g4xOFAAADAFBMVEUAAAD////lc3PahobplZXhl5felpbdlpbqoKDln5/moqLgn5/ppqbopaXmpqborKznrKziqKjlq6vnrq7psLDnr6/irKzpsrLqtLTps7Pst7ferKzqtrbntLTturrtvLzqvLzourrhtbXrwMDov7/sw8PrwsLowMDhvb3tysrqycntz8/qzMzqzs7u1NTr09Ps19fo1NTv29vo1dXx4ODx4uLw4uLx5OTq39/x5+fx6Ojw5+fo39/x6enw6Ojp4eHz7Ozy6+vt5+fq5OTz7u7y7e3s5+fz8PDy7+/x7u7z8fHy8PDt6+vz8vLz8/Py8vLw8PDv7+/t7e0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxvAGHAAAB9klEQVR42qTXfVvBUBgG8Od6qGwx75WoVCKJSlR6pZJSQt//w8S2w86cPXaO+z9n8xu7bs8Z+KXSDgWDoTZ5ClAHm2GcJNxUBfoRNBPpKwInaKesBnQ1BmjvSkAeZ8mrAC1tDmgtBSCFjmTkgQZyuZUGDB6IygJ1dKUuCRhuwJADKriQmgzQ0xcBXQYooiBl/0BXEwHiQgNV4oAd++WxX4CV+PRvZObnyP4IHZ8AK/E1W7giCg1EiS/ZygVRaCA6VGUrVaLQQJR4EcCGD8CgAGM54CjxDDgnCg1Eic/YYokoNBAlLrHFgmOxQgMdZ4kLIkDvkUAelwFYpICWJgT2uN9UhwC4SYyHbDmN3hMaiEmcFgP8JgHEIJwBMX495QXUXBMk5gFwhQZiEjNgECMmNBCTOPZtHXhCYpMAahLv7E+zu43EJgH0JPZKZRHoaDLAvNAzICM4zTWVhYUGYYmtxB/H06E8fokLNomuC0gJrpJgV0kIDuZ5oCH6okkGJEX7VIsDDGmAFRqEJfYD4I0D0FWA6ByooApgFRo8HidM4NN+ZvYADAZ4ljh3YCbndbxmAXIldj/1gGsSy6U8BQaaOqAPJsADrpD7CfC1tgLwPL0HW+rv3zRv4uu66vs37qwefGQDSsm+sSoPR2OFjIZL/zf6yb8AAwCmB2Y7BrVl9wAAAABJRU5ErkJggg==" alt="Exception"/>
<h1><?php
if ($exception instanceof \yii\web\HttpException) {
echo '<span>' . $handler->createHttpStatusLink($exception->statusCode, $handler->htmlEncode($exception->getName())) . '</span>';
echo ' &ndash; ' . $handler->addTypeLinks(get_class($exception));
} elseif ($exception instanceof \yii\base\Exception) {
echo '<span>' . $handler->htmlEncode($exception->getName()) . '</span>';
echo ' &ndash; ' . $handler->addTypeLinks(get_class($exception));
} else {
echo '<span>' . $handler->htmlEncode(get_class($exception)) . '</span>';
}
?></h1>
<?php endif; ?>
<h2><?= nl2br($handler->htmlEncode($exception->getMessage())) ?></h2>
<?= $handler->renderPreviousExceptions($exception) ?>
</div>
<div class="call-stack">
<ul>
<?= $handler->renderCallStackItem($exception->getFile(), $exception->getLine(), null, null, 1) ?>
<?php for ($i = 0, $trace = $exception->getTrace(), $length = count($trace); $i < $length; ++$i): ?>
<?= $handler->renderCallStackItem(@$trace[$i]['file'] ?: null, @$trace[$i]['line'] ?: null,
@$trace[$i]['class'] ?: null, @$trace[$i]['function'] ?: null, $i + 2) ?>
<?php endfor; ?>
</ul>
</div>
<div class="request">
<div class="code">
<?= $handler->renderRequest() ?>
</div>
</div>
<div class="footer">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS4AAADeCAIAAAAMx3q5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkE5NkEyOTAzQzQ3RDExRTI4NjIzOEE2RkU5QTc4RTU0IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkE5NkEyOTA0QzQ3RDExRTI4NjIzOEE2RkU5QTc4RTU0Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTk2QTI5MDFDNDdEMTFFMjg2MjM4QTZGRTlBNzhFNTQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTk2QTI5MDJDNDdEMTFFMjg2MjM4QTZGRTlBNzhFNTQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4DYCAjAAAx4UlEQVR42ux9aZvjuJEm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" alt="Yii Framework"/>
<p class="timestamp"><?= date('Y-m-d, H:i:s') ?></p>
<p><?= $handler->createServerInformationLink() ?></p>
<p><a href="http://yiiframework.com/">Yii Framework</a>/<?= $handler->createFrameworkVersionLink() ?></p>
</div>
<script type="text/javascript">
var hljs=new function(){function l(o){return o.replace(/&/gm,"&amp;").replace(/</gm,"&lt;").replace(/>/gm,"&gt;")}function b(p){for(var o=p.firstChild;o;o=o.nextSibling){if(o.nodeName=="CODE"){return o}if(!(o.nodeType==3&&o.nodeValue.match(/\s+/))){break}}}function h(p,o){return Array.prototype.map.call(p.childNodes,function(q){if(q.nodeType==3){return o?q.nodeValue.replace(/\n/g,""):q.nodeValue}if(q.nodeName=="BR"){return"\n"}return h(q,o)}).join("")}function a(q){var p=(q.className+" "+q.parentNode.className).split(/\s+/);p=p.map(function(r){return r.replace(/^language-/,"")});for(var o=0;o<p.length;o++){if(e[p[o]]||p[o]=="no-highlight"){return p[o]}}}function c(q){var o=[];(function p(r,s){for(var t=r.firstChild;t;t=t.nextSibling){if(t.nodeType==3){s+=t.nodeValue.length}else{if(t.nodeName=="BR"){s+=1}else{if(t.nodeType==1){o.push({event:"start",offset:s,node:t});s=p(t,s);o.push({event:"stop",offset:s,node:t})}}}}return s})(q,0);return o}function j(x,v,w){var p=0;var y="";var r=[];function t(){if(x.length&&v.length){if(x[0].offset!=v[0].offset){return(x[0].offset<v[0].offset)?x:v}else{return v[0].event=="start"?x:v}}else{return x.length?x:v}}function s(A){function z(B){return" "+B.nodeName+'="'+l(B.value)+'"'}return"<"+A.nodeName+Array.prototype.map.call(A.attributes,z).join("")+">"}while(x.length||v.length){var u=t().splice(0,1)[0];y+=l(w.substr(p,u.offset-p));p=u.offset;if(u.event=="start"){y+=s(u.node);r.push(u.node)}else{if(u.event=="stop"){var o,q=r.length;do{q--;o=r[q];y+=("</"+o.nodeName.toLowerCase()+">")}while(o!=u.node);r.splice(q,1);while(q<r.length){y+=s(r[q]);q++}}}}return y+l(w.substr(p))}function f(q){function o(s,r){return RegExp(s,"m"+(q.cI?"i":"")+(r?"g":""))}function p(y,w){if(y.compiled){return}y.compiled=true;var s=[];if(y.k){var r={};function z(A,t){t.split(" ").forEach(function(B){var C=B.split("|");r[C[0]]=[A,C[1]?Number(C[1]):1];s.push(C[0])})}y.lR=o(y.l||hljs.IR,true);if(typeof y.k=="string"){z("keyword",y.k)}else{for(var x in y.k){if(!y.k.hasOwnProperty(x)){continue}z(x,y.k[x])}}y.k=r}if(w){if(y.bWK){y.b="\\b("+s.join("|")+")\\s"}y.bR=o(y.b?y.b:"\\B|\\b");if(!y.e&&!y.eW){y.e="\\B|\\b"}if(y.e){y.eR=o(y.e)}y.tE=y.e||"";if(y.eW&&w.tE){y.tE+=(y.e?"|":"")+w.tE}}if(y.i){y.iR=o(y.i)}if(y.r===undefined){y.r=1}if(!y.c){y.c=[]}for(var v=0;v<y.c.length;v++){if(y.c[v]=="self"){y.c[v]=y}p(y.c[v],y)}if(y.starts){p(y.starts,w)}var u=[];for(var v=0;v<y.c.length;v++){u.push(y.c[v].b)}if(y.tE){u.push(y.tE)}if(y.i){u.push(y.i)}y.t=u.length?o(u.join("|"),true):{exec:function(t){return null}}}p(q)}function d(D,E){function o(r,M){for(var L=0;L<M.c.length;L++){var K=M.c[L].bR.exec(r);if(K&&K.index==0){return M.c[L]}}}function s(K,r){if(K.e&&K.eR.test(r)){return K}if(K.eW){return s(K.parent,r)}}function t(r,K){return K.i&&K.iR.test(r)}function y(L,r){var K=F.cI?r[0].toLowerCase():r[0];return L.k.hasOwnProperty(K)&&L.k[K]}function G(){var K=l(w);if(!A.k){return K}var r="";var N=0;A.lR.lastIndex=0;var L=A.lR.exec(K);while(L){r+=K.substr(N,L.index-N);var M=y(A,L);if(M){v+=M[1];r+='<span class="'+M[0]+'">'+L[0]+"</span>"}else{r+=L[0]}N=A.lR.lastIndex;L=A.lR.exec(K)}return r+K.substr(N)}function z(){if(A.sL&&!e[A.sL]){return l(w)}var r=A.sL?d(A.sL,w):g(w);if(A.r>0){v+=r.keyword_count;B+=r.r}return'<span class="'+r.language+'">'+r.value+"</span>"}function J(){return A.sL!==undefined?z():G()}function I(L,r){var K=L.cN?'<span class="'+L.cN+'">':"";if(L.rB){x+=K;w=""}else{if(L.eB){x+=l(r)+K;w=""}else{x+=K;w=r}}A=Object.create(L,{parent:{value:A}});B+=L.r}function C(K,r){w+=K;if(r===undefined){x+=J();return 0}var L=o(r,A);if(L){x+=J();I(L,r);return L.rB?0:r.length}var M=s(A,r);if(M){if(!(M.rE||M.eE)){w+=r}x+=J();do{if(A.cN){x+="</span>"}A=A.parent}while(A!=M.parent);if(M.eE){x+=l(r)}w="";if(M.starts){I(M.starts,"")}return M.rE?0:r.length}if(t(r,A)){throw"Illegal"}w+=r;return r.length||1}var F=e[D];f(F);var A=F;var w="";var B=0;var v=0;var x="";try{var u,q,p=0;while(true){A.t.lastIndex=p;u=A.t.exec(E);if(!u){break}q=C(E.substr(p,u.index-p),u[0]);p=u.index+q}C(E.substr(p));return{r:B,keyword_count:v,value:x,language:D}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:l(E)}}else{throw H}}}function g(s){var o={keyword_count:0,r:0,value:l(s)};var q=o;for(var p in e){if(!e.hasOwnProperty(p)){continue}var r=d(p,s);r.language=p;if(r.keyword_count+r.r>q.keyword_count+q.r){q=r}if(r.keyword_count+r.r>o.keyword_count+o.r){q=o;o=r}}if(q.language){o.second_best=q}return o}function i(q,p,o){if(p){q=q.replace(/^((<[^>]+>|\t)+)/gm,function(r,v,u,t){return v.replace(/\t/g,p)})}if(o){q=q.replace(/\n/g,"<br>")}return q}function m(r,u,p){var v=h(r,p);var t=a(r);if(t=="no-highlight"){return}var w=t?d(t,v):g(v);t=w.language;var o=c(r);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=j(o,c(q),v)}w.value=i(w.value,u,p);var s=r.className;if(!s.match("(\\s|^)(language-)?"+t+"(\\s|$)")){s=s?(s+" "+t):t}r.innerHTML=w.value;r.className=s;r.result={language:t,kw:w.keyword_count,re:w.r};if(w.second_best){r.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function n(){if(n.called){return}n.called=true;Array.prototype.map.call(document.getElementsByTagName("pre"),b).filter(Boolean).forEach(function(o){m(o,hljs.tabReplace)})}function k(){window.addEventListener("DOMContentLoaded",n,false);window.addEventListener("load",n,false)}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=m;this.initHighlighting=n;this.initHighlightingOnLoad=k;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(q,r){var o={};for(var p in q){o[p]=q[p]}if(r){for(var p in r){o[p]=r[p]}}return o}}();hljs.LANGUAGES.php=function(a){var e={cN:"variable",b:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"};var b=[a.inherit(a.ASM,{i:null}),a.inherit(a.QSM,{i:null}),{cN:"string",b:'b"',e:'"',c:[a.BE]},{cN:"string",b:"b'",e:"'",c:[a.BE]}];var c=[a.BNM,a.CNM];var d={cN:"title",b:a.UIR};return{cI:true,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return implements parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception php_user_filter default die require __FUNCTION__ enddeclare final try this switch continue endfor endif declare unset true false namespace trait goto instanceof insteadof __DIR__ __NAMESPACE__ __halt_compiler",c:[a.CLCM,a.HCM,{cN:"comment",b:"/\\*",e:"\\*/",c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"}]},{cN:"comment",eB:true,b:"__halt_compiler.+?;",eW:true},{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[a.BE]},{cN:"preprocessor",b:"<\\?php",r:10},{cN:"preprocessor",b:"\\?>"},e,{cN:"function",bWK:true,e:"{",k:"function",i:"\\$|\\[|%",c:[d,{cN:"params",b:"\\(",e:"\\)",c:["self",e,a.CBLCLM].concat(b).concat(c)}]},{cN:"class",bWK:true,e:"{",k:"class",i:"[:\\(\\$]",c:[{bWK:true,eW:true,k:"extends",c:[d]},d]},{b:"=>"}].concat(b).concat(c)}}(hljs);
</script>
<script type="text/javascript">
/*! Sizzle v1.9.4-pre | (c) 2013 jQuery Foundation, Inc. | jquery.org/license
//@ sourceMappingURL=sizzle.min.map
*/(function(e,t){function n(e,t,n,r){var o,i,u,l,a,c,s,f,p,d;if((t?t.ownerDocument||t:U)!==H&&q(t),t=t||H,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(O&&!r){if(o=Ct.exec(e))if(u=o[1]){if(9===l){if(i=t.getElementById(u),!i||!i.parentNode)return n;if(i.id===u)return n.push(i),n}else if(t.ownerDocument&&(i=t.ownerDocument.getElementById(u))&&j(t,i)&&i.id===u)return n.push(i),n}else{if(o[2])return ot.apply(n,t.getElementsByTagName(e)),n;if((u=o[3])&&S.getElementsByClassName&&t.getElementsByClassName)return ot.apply(n,t.getElementsByClassName(u)),n}if(S.qsa&&(!k||!k.test(e))){if(f=s=G,p=t,d=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){for(c=g(e),(s=t.getAttribute("id"))?f=s.replace(Tt,"\\$&"):t.setAttribute("id",f),f="[id='"+f+"'] ",a=c.length;a--;)c[a]=f+m(c[a]);p=mt.test(e)&&t.parentNode||t,d=c.join(",")}if(d)try{return ot.apply(n,p.querySelectorAll(d)),n}catch(h){}finally{s||t.removeAttribute("id")}}}return w(e.replace(dt,"$1"),t,n,r)}function r(e){return xt.test(e+"")}function o(){function e(n,r){return t.push(n+=" ")>L.cacheLength&&delete e[t.shift()],e[n]=r}var t=[];return e}function i(e){return e[G]=!0,e}function u(e){var t=H.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function l(e,t,n){e=e.split("|");for(var r,o=e.length,i=n?null:t;o--;)(r=L.attrHandle[e[o]])&&r!==t||(L.attrHandle[e[o]]=i)}function a(e,t){var n=e.getAttributeNode(t);return n&&n.specified?n.value:e[t]===!0?t.toLowerCase():null}function c(e,t){return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function s(e){return"input"===e.nodeName.toLowerCase()?e.defaultValue:t}function f(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||_)-(~e.sourceIndex||_);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function p(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function d(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function h(e){return i(function(t){return t=+t,i(function(n,r){for(var o,i=e([],n.length,t),u=i.length;u--;)n[o=i[u]]&&(n[o]=!(r[o]=n[o]))})})}function g(e,t){var r,o,i,u,l,a,c,s=K[e+" "];if(s)return t?0:s.slice(0);for(l=e,a=[],c=L.preFilter;l;){(!r||(o=ht.exec(l)))&&(o&&(l=l.slice(o[0].length)||l),a.push(i=[])),r=!1,(o=gt.exec(l))&&(r=o.shift(),i.push({value:r,type:o[0].replace(dt," ")}),l=l.slice(r.length));for(u in L.filter)!(o=bt[u].exec(l))||c[u]&&!(o=c[u](o))||(r=o.shift(),i.push({value:r,type:u,matches:o}),l=l.slice(r.length));if(!r)break}return t?l.length:l?n.error(e):K(e,a).slice(0)}function m(e){for(var t=0,n=e.length,r="";n>t;t++)r+=e[t].value;return r}function y(e,t,n){var r=t.dir,o=n&&"parentNode"===r,i=X++;return t.first?function(t,n,i){for(;t=t[r];)if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,u){var l,a,c,s=V+" "+i;if(u){for(;t=t[r];)if((1===t.nodeType||o)&&e(t,n,u))return!0}else for(;t=t[r];)if(1===t.nodeType||o)if(c=t[G]||(t[G]={}),(a=c[r])&&a[0]===s){if((l=a[1])===!0||l===D)return l===!0}else if(a=c[r]=[s],a[1]=e(t,n,u)||D,a[1]===!0)return!0}}function v(e){return e.length>1?function(t,n,r){for(var o=e.length;o--;)if(!e[o](t,n,r))return!1;return!0}:e[0]}function N(e,t,n,r,o){for(var i,u=[],l=0,a=e.length,c=null!=t;a>l;l++)(i=e[l])&&(!n||n(i,r,o))&&(u.push(i),c&&t.push(l));return u}function b(e,t,n,r,o,u){return r&&!r[G]&&(r=b(r)),o&&!o[G]&&(o=b(o,u)),i(function(i,u,l,a){var c,s,f,p=[],d=[],h=u.length,g=i||E(t||"*",l.nodeType?[l]:l,[]),m=!e||!i&&t?g:N(g,p,e,l,a),y=n?o||(i?e:h||r)?[]:u:m;if(n&&n(m,y,l,a),r)for(c=N(y,d),r(c,[],l,a),s=c.length;s--;)(f=c[s])&&(y[d[s]]=!(m[d[s]]=f));if(i){if(o||e){if(o){for(c=[],s=y.length;s--;)(f=y[s])&&c.push(m[s]=f);o(null,y=[],c,a)}for(s=y.length;s--;)(f=y[s])&&(c=o?ut.call(i,f):p[s])>-1&&(i[c]=!(u[c]=f))}}else y=N(y===u?y.splice(h,y.length):y),o?o(null,u,y,a):ot.apply(u,y)})}function x(e){for(var t,n,r,o=e.length,i=L.relative[e[0].type],u=i||L.relative[" "],l=i?1:0,a=y(function(e){return e===t},u,!0),c=y(function(e){return ut.call(t,e)>-1},u,!0),s=[function(e,n,r){return!i&&(r||n!==P)||((t=n).nodeType?a(e,n,r):c(e,n,r))}];o>l;l++)if(n=L.relative[e[l].type])s=[y(v(s),n)];else{if(n=L.filter[e[l].type].apply(null,e[l].matches),n[G]){for(r=++l;o>r&&!L.relative[e[r].type];r++);return b(l>1&&v(s),l>1&&m(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(dt,"$1"),n,r>l&&x(e.slice(l,r)),o>r&&x(e=e.slice(r)),o>r&&m(e))}s.push(n)}return v(s)}function C(e,t){var r=0,o=t.length>0,u=e.length>0,l=function(i,l,a,c,s){var f,p,d,h=[],g=0,m="0",y=i&&[],v=null!=s,b=P,x=i||u&&L.find.TAG("*",s&&l.parentNode||l),C=V+=null==b?1:Math.random()||.1;for(v&&(P=l!==H&&l,D=r);null!=(f=x[m]);m++){if(u&&f){for(p=0;d=e[p++];)if(d(f,l,a)){c.push(f);break}v&&(V=C,D=++r)}o&&((f=!d&&f)&&g--,i&&y.push(f))}if(g+=m,o&&m!==g){for(p=0;d=t[p++];)d(y,h,l,a);if(i){if(g>0)for(;m--;)y[m]||h[m]||(h[m]=nt.call(c));h=N(h)}ot.apply(c,h),v&&!i&&h.length>0&&g+t.length>1&&n.uniqueSort(c)}return v&&(V=C,P=b),y};return o?i(l):l}function E(e,t,r){for(var o=0,i=t.length;i>o;o++)n(e,t[o],r);return r}function w(e,t,n,r){var o,i,u,l,a,c=g(e);if(!r&&1===c.length){if(i=c[0]=c[0].slice(0),i.length>2&&"ID"===(u=i[0]).type&&S.getById&&9===t.nodeType&&O&&L.relative[i[1].type]){if(t=(L.find.ID(u.matches[0].replace(At,St),t)||[])[0],!t)return n;e=e.slice(i.shift().value.length)}for(o=bt.needsContext.test(e)?0:i.length;o--&&(u=i[o],!L.relative[l=u.type]);)if((a=L.find[l])&&(r=a(u.matches[0].replace(At,St),mt.test(i[0].type)&&t.parentNode||t))){if(i.splice(o,1),e=r.length&&m(i),!e)return ot.apply(n,r),n;break}}return R(e,c)(r,t,!O,n,mt.test(e)),n}function T(){}var A,S,D,L,B,I,R,P,$,q,H,M,O,k,F,z,j,G="sizzle"+-new Date,U=e.document,V=0,X=0,J=o(),K=o(),Q=o(),W=!1,Y=function(){return 0},Z=typeof t,_=1<<31,et={}.hasOwnProperty,tt=[],nt=tt.pop,rt=tt.push,ot=tt.push,it=tt.slice,ut=tt.indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(this[t]===e)return t;return-1},lt="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",at="[\\x20\\t\\r\\n\\f]",ct="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",st=ct.replace("w","w#"),ft="\\["+at+"*("+ct+")"+at+"*(?:([*^$|!~]?=)"+at+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+st+")|)|)"+at+"*\\]",pt=":("+ct+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+ft.replace(3,8)+")*)|.*)\\)|)",dt=RegExp("^"+at+"+|((?:^|[^\\\\])(?:\\\\.)*)"+at+"+$","g"),ht=RegExp("^"+at+"*,"+at+"*"),gt=RegExp("^"+at+"*([>+~]|"+at+")"+at+"*"),mt=RegExp(at+"*[+~]"),yt=RegExp("="+at+"*([^\\]'\"]*)"+at+"*\\]","g"),vt=RegExp(pt),Nt=RegExp("^"+st+"$"),bt={ID:RegExp("^#("+ct+")"),CLASS:RegExp("^\\.("+ct+")"),TAG:RegExp("^("+ct.replace("w","w*")+")"),ATTR:RegExp("^"+ft),PSEUDO:RegExp("^"+pt),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+at+"*(even|odd|(([+-]|)(\\d*)n|)"+at+"*(?:([+-]|)"+at+"*(\\d+)|))"+at+"*\\)|)","i"),bool:RegExp("^(?:"+lt+")$","i"),needsContext:RegExp("^"+at+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+at+"*((?:-\\d)?\\d*)"+at+"*\\)|)(?=[^-]|$)","i")},xt=/^[^{]+\{\s*\[native \w/,Ct=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Et=/^(?:input|select|textarea|button)$/i,wt=/^h\d$/i,Tt=/'|\\/g,At=RegExp("\\\\([\\da-f]{1,6}"+at+"?|("+at+")|.)","ig"),St=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{ot.apply(tt=it.call(U.childNodes),U.childNodes),tt[U.childNodes.length].nodeType}catch(Dt){ot={apply:tt.length?function(e,t){rt.apply(e,it.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}I=n.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},S=n.support={},q=n.setDocument=function(e){var n=e?e.ownerDocument||e:U;return n!==H&&9===n.nodeType&&n.documentElement?(H=n,M=n.documentElement,O=!I(n),S.attributes=u(function(e){return e.innerHTML="<a href='#'></a>",l("type|href|height|width",c,"#"===e.firstChild.getAttribute("href")),l(lt,a,null==e.getAttribute("disabled")),e.className="i",!e.getAttribute("className")}),S.input=u(function(e){return e.innerHTML="<input>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}),l("value",s,S.attributes&&S.input),S.getElementsByTagName=u(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),S.getElementsByClassName=u(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),S.getById=u(function(e){return M.appendChild(e).id=G,!n.getElementsByName||!n.getElementsByName(G).length}),S.getById?(L.find.ID=function(e,t){if(typeof t.getElementById!==Z&&O){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},L.filter.ID=function(e){var t=e.replace(At,St);return function(e){return e.getAttribute("id")===t}}):(delete L.find.ID,L.filter.ID=function(e){var t=e.replace(At,St);return function(e){var n=typeof e.getAttributeNode!==Z&&e.getAttributeNode("id");return n&&n.value===t}}),L.find.TAG=S.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==Z?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],o=0,i=t.getElementsByTagName(e);if("*"===e){for(;n=i[o++];)1===n.nodeType&&r.push(n);return r}return i},L.find.CLASS=S.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==Z&&O?n.getElementsByClassName(e):t},F=[],k=[],(S.qsa=r(n.querySelectorAll))&&(u(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||k.push("\\["+at+"*(?:value|"+lt+")"),e.querySelectorAll(":checked").length||k.push(":checked")}),u(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&k.push("[*^$]="+at+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||k.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),k.push(",.*:")})),(S.matchesSelector=r(z=M.webkitMatchesSelector||M.mozMatchesSelector||M.oMatchesSelector||M.msMatchesSelector))&&u(function(e){S.disconnectedMatch=z.call(e,"div"),z.call(e,"[s!='']:x"),F.push("!=",pt)}),k=k.length&&RegExp(k.join("|")),F=F.length&&RegExp(F.join("|")),j=r(M.contains)||M.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},S.sortDetached=u(function(e){return 1&e.compareDocumentPosition(n.createElement("div"))}),Y=M.compareDocumentPosition?function(e,t){if(e===t)return W=!0,0;var r=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return r?1&r||!S.sortDetached&&t.compareDocumentPosition(e)===r?e===n||j(U,e)?-1:t===n||j(U,t)?1:$?ut.call($,e)-ut.call($,t):0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,o=0,i=e.parentNode,u=t.parentNode,l=[e],a=[t];if(e===t)return W=!0,0;if(!i||!u)return e===n?-1:t===n?1:i?-1:u?1:$?ut.call($,e)-ut.call($,t):0;if(i===u)return f(e,t);for(r=e;r=r.parentNode;)l.unshift(r);for(r=t;r=r.parentNode;)a.unshift(r);for(;l[o]===a[o];)o++;return o?f(l[o],a[o]):l[o]===U?-1:a[o]===U?1:0},n):H},n.matches=function(e,t){return n(e,null,null,t)},n.matchesSelector=function(e,t){if((e.ownerDocument||e)!==H&&q(e),t=t.replace(yt,"='$1']"),!(!S.matchesSelector||!O||F&&F.test(t)||k&&k.test(t)))try{var r=z.call(e,t);if(r||S.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(o){}return n(t,H,null,[e]).length>0},n.contains=function(e,t){return(e.ownerDocument||e)!==H&&q(e),j(e,t)},n.attr=function(e,n){(e.ownerDocument||e)!==H&&q(e);var r=L.attrHandle[n.toLowerCase()],o=r&&et.call(L.attrHandle,n.toLowerCase())?r(e,n,!O):t;return o===t?S.attributes||!O?e.getAttribute(n):(o=e.getAttributeNode(n))&&o.specified?o.value:null:o},n.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},n.uniqueSort=function(e){var t,n=[],r=0,o=0;if(W=!S.detectDuplicates,$=!S.sortStable&&e.slice(0),e.sort(Y),W){for(;t=e[o++];)t===e[o]&&(r=n.push(o));for(;r--;)e.splice(n[r],1)}return e},B=n.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=B(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r];r++)n+=B(t);return n},L=n.selectors={cacheLength:50,createPseudo:i,match:bt,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(At,St),e[3]=(e[4]||e[5]||"").replace(At,St),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||n.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&n.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return bt.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&vt.test(r)&&(n=g(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(At,St).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=J[e+" "];return t||(t=RegExp("(^|"+at+")"+e+"("+at+"|$)"))&&J(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==Z&&e.getAttribute("class")||"")})},ATTR:function(e,t,r){return function(o){var i=n.attr(o,e);return null==i?"!="===t:t?(i+="","="===t?i===r:"!="===t?i!==r:"^="===t?r&&0===i.indexOf(r):"*="===t?r&&i.indexOf(r)>-1:"$="===t?r&&i.slice(-r.length)===r:"~="===t?(" "+i+" ").indexOf(r)>-1:"|="===t?i===r||i.slice(0,r.length+1)===r+"-":!1):!0}},CHILD:function(e,t,n,r,o){var i="nth"!==e.slice(0,3),u="last"!==e.slice(-4),l="of-type"===t;return 1===r&&0===o?function(e){return!!e.parentNode}:function(t,n,a){var c,s,f,p,d,h,g=i!==u?"nextSibling":"previousSibling",m=t.parentNode,y=l&&t.nodeName.toLowerCase(),v=!a&&!l;if(m){if(i){for(;g;){for(f=t;f=f[g];)if(l?f.nodeName.toLowerCase()===y:1===f.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[u?m.firstChild:m.lastChild],u&&v){for(s=m[G]||(m[G]={}),c=s[e]||[],d=c[0]===V&&c[1],p=c[0]===V&&c[2],f=d&&m.childNodes[d];f=++d&&f&&f[g]||(p=d=0)||h.pop();)if(1===f.nodeType&&++p&&f===t){s[e]=[V,d,p];break}}else if(v&&(c=(t[G]||(t[G]={}))[e])&&c[0]===V)p=c[1];else for(;(f=++d&&f&&f[g]||(p=d=0)||h.pop())&&((l?f.nodeName.toLowerCase()!==y:1!==f.nodeType)||!++p||(v&&((f[G]||(f[G]={}))[e]=[V,p]),f!==t)););return p-=o,p===r||0===p%r&&p/r>=0}}},PSEUDO:function(e,t){var r,o=L.pseudos[e]||L.setFilters[e.toLowerCase()]||n.error("unsupported pseudo: "+e);return o[G]?o(t):o.length>1?(r=[e,e,"",t],L.setFilters.hasOwnProperty(e.toLowerCase())?i(function(e,n){for(var r,i=o(e,t),u=i.length;u--;)r=ut.call(e,i[u]),e[r]=!(n[r]=i[u])}):function(e){return o(e,0,r)}):o}},pseudos:{not:i(function(e){var t=[],n=[],r=R(e.replace(dt,"$1"));return r[G]?i(function(e,t,n,o){for(var i,u=r(e,null,o,[]),l=e.length;l--;)(i=u[l])&&(e[l]=!(t[l]=i))}):function(e,o,i){return t[0]=e,r(t,null,i,n),!n.pop()}}),has:i(function(e){return function(t){return n(e,t).length>0}}),contains:i(function(e){return function(t){return(t.textContent||t.innerText||B(t)).indexOf(e)>-1}}),lang:i(function(e){return Nt.test(e||"")||n.error("unsupported lang: "+e),e=e.replace(At,St).toLowerCase(),function(t){var n;do if(n=O?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===M},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!L.pseudos.empty(e)},header:function(e){return wt.test(e.nodeName)},input:function(e){return Et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:h(function(){return[0]}),last:h(function(e,t){return[t-1]}),eq:h(function(e,t,n){return[0>n?n+t:n]}),even:h(function(e,t){for(var n=0;t>n;n+=2)e.push(n);return e}),odd:h(function(e,t){for(var n=1;t>n;n+=2)e.push(n);return e}),lt:h(function(e,t,n){for(var r=0>n?n+t:n;--r>=0;)e.push(r);return e}),gt:h(function(e,t,n){for(var r=0>n?n+t:n;t>++r;)e.push(r);return e})}};for(A in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})L.pseudos[A]=p(A);for(A in{submit:!0,reset:!0})L.pseudos[A]=d(A);R=n.compile=function(e,t){var n,r=[],o=[],i=Q[e+" "];if(!i){for(t||(t=g(e)),n=t.length;n--;)i=x(t[n]),i[G]?r.push(i):o.push(i);i=Q(e,C(o,r))}return i},L.pseudos.nth=L.pseudos.eq,T.prototype=L.filters=L.pseudos,L.setFilters=new T,S.sortStable=G.split("").sort(Y).join("")===G,q(),[0,0].sort(Y),S.detectDuplicates=W,"function"==typeof define&&define.amd?define(function(){return n}):e.Sizzle=n})(window);
</script>
<script type="text/javascript">
window.onload = function() {
var codeBlocks = Sizzle('pre'),
callStackItems = Sizzle('.call-stack-item');
// highlight code blocks
for (var i = 0, imax = codeBlocks.length; i < imax; ++i) {
hljs.highlightBlock(codeBlocks[i], ' ');
}
// code block hover line
document.onmousemove = function(e) {
var event = e || window.event,
clientY = event.clientY,
lineFound = false,
hoverLines = Sizzle('.hover-line');
for (var i = 0, imax = codeBlocks.length - 1; i < imax; ++i) {
var lines = codeBlocks[i].getClientRects();
for (var j = 0, jmax = lines.length; j < jmax; ++j) {
if (clientY >= lines[j].top && clientY <= lines[j].bottom) {
lineFound = true;
break;
}
}
if (lineFound) {
break;
}
}
for (var k = 0, kmax = hoverLines.length; k < kmax; ++k) {
hoverLines[k].className = 'hover-line';
}
if (lineFound) {
var line = Sizzle('.call-stack-item:eq(' + i + ') .hover-line:eq(' + j + ')')[0];
if (line) {
line.className = 'hover-line hover';
}
}
};
var refreshCallStackItemCode = function(callStackItem) {
if (!Sizzle('pre', callStackItem)[0]) {
return;
}
var top = callStackItem.offsetTop - window.pageYOffset,
lines = Sizzle('pre', callStackItem)[0].getClientRects(),
lineNumbers = Sizzle('.lines-item', callStackItem),
errorLine = Sizzle('.error-line', callStackItem)[0],
hoverLines = Sizzle('.hover-line', callStackItem);
for (var i = 0, imax = lines.length; i < imax; ++i) {
if (!lineNumbers[i]) {
continue;
}
lineNumbers[i].style.top = parseInt(lines[i].top - top) + 'px';
hoverLines[i].style.top = parseInt(lines[i].top - top - 3) + 'px';
hoverLines[i].style.height = parseInt(lines[i].bottom - lines[i].top + 6) + 'px';
if (parseInt(callStackItem.getAttribute('data-line')) == i) {
errorLine.style.top = parseInt(lines[i].top - top - 3) + 'px';
errorLine.style.height = parseInt(lines[i].bottom - lines[i].top + 6) + 'px';
}
}
};
for (var i = 0, imax = callStackItems.length; i < imax; ++i) {
refreshCallStackItemCode(callStackItems[i]);
// toggle code block visibility
Sizzle('.element-wrap', callStackItems[i])[0].addEventListener('click', function() {
var callStackItem = this.parentNode,
code = Sizzle('.code-wrap', callStackItem)[0];
code.style.display = window.getComputedStyle(code).display == 'block' ? 'none' : 'block';
refreshCallStackItemCode(callStackItem);
});
}
};
</script>
<?php if (method_exists($this, 'endBody')) $this->endBody(); // to allow injecting code into body (mostly by Yii Debug Toolbar) ?>
</body>
</html>
<?php if (method_exists($this, 'endPage')) $this->endPage(); ?>
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
echo "<?php\n"; echo "<?php\n";
?> ?>
use yii\db\Schema;
class <?= $className ?> extends \yii\db\Migration class <?= $className ?> extends \yii\db\Migration
{ {
public function up() public function up()
......
...@@ -265,6 +265,7 @@ class User extends Component ...@@ -265,6 +265,7 @@ class User extends Component
* This will remove authentication-related session data. * This will remove authentication-related session data.
* If `$destroySession` is true, all session data will be removed. * If `$destroySession` is true, all session data will be removed.
* @param boolean $destroySession whether to destroy the whole session. Defaults to true. * @param boolean $destroySession whether to destroy the whole session. Defaults to true.
* @return boolean whether the user is logged out
*/ */
public function logout($destroySession = true) public function logout($destroySession = true)
{ {
...@@ -279,24 +280,31 @@ class User extends Component ...@@ -279,24 +280,31 @@ class User extends Component
} }
$this->afterLogout($identity); $this->afterLogout($identity);
} }
return $this->getIsGuest();
} }
/** /**
* Returns a value indicating whether the user is a guest (not authenticated). * Returns a value indicating whether the user is a guest (not authenticated).
* @param boolean $checkSession whether to check the session to determine if the user is a guest.
* Note that if this is false, it is possible that the user may not be a guest while this method still returns
* true. This is because the session is not checked.
* @return boolean whether the current user is a guest. * @return boolean whether the current user is a guest.
*/ */
public function getIsGuest() public function getIsGuest($checkSession = true)
{ {
return $this->getIdentity() === null; return $this->getIdentity($checkSession) === null;
} }
/** /**
* Returns a value that uniquely represents the user. * Returns a value that uniquely represents the user.
* @param boolean $checkSession whether to check the session to determine the user ID.
* Note that if this is false, it is possible that this method returns null although the user may not
* be a guest. This is because the session is not checked.
* @return string|integer the unique identifier for the user. If null, it means the user is a guest. * @return string|integer the unique identifier for the user. If null, it means the user is a guest.
*/ */
public function getId() public function getId($checkSession = true)
{ {
$identity = $this->getIdentity(); $identity = $this->getIdentity($checkSession);
return $identity !== null ? $identity->getId() : null; return $identity !== null ? $identity->getId() : null;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment