Commit 302b7a7d by Tobias Munk

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

parents 36b41bad 1ccad3d9
......@@ -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:
```
```php
$customer->email = 'jane@example.com';
$customer->save();
```
......
......@@ -114,9 +114,11 @@ There are several classes provided by framework:
- FileHelper
- Html
- HtmlPurifier
- Image
- Inflector
- Json
- Markdown
- Security
- StringHelper
- Url
- VarDumper
......@@ -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
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
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.
......
......@@ -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
the [Authorization chapter](authorization.md).
You may use the [[yii\web\AccessControl]] filter and/or the Role-Based Access Control (RBAC) component
to implementation authorization.
You may use the Role-Based Access Control (RBAC) component to implementation authorization.
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
......
......@@ -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
`\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)`
- `createAbsoluteUrl($params, $schema = null)`
......
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
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.
- There should be a newline at the end of file.
- 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 constants MUST be declared in all upper case with underscore separators.
- Method names MUST be declared in `camelCase`.
......
(function() {
var ajax = function(url, settings) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
settings = settings || {};
xhr.open(settings.method || 'GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function(state) {
if (xhr.readyState == 4) {
if (xhr.status == 200 && settings.success) {
settings.success(xhr);
} else if (xhr.status != 200 && settings.error) {
settings.error(xhr);
}
}
};
xhr.send(settings.data || '');
};
(function () {
var ajax = function (url, settings) {
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
settings = settings || {};
xhr.open(settings.method || 'GET', url, true);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = function (state) {
if (xhr.readyState == 4) {
if (xhr.status == 200 && settings.success) {
settings.success(xhr);
} else if (xhr.status != 200 && settings.error) {
settings.error(xhr);
}
}
};
xhr.send(settings.data || '');
};
var e = document.getElementById('yii-debug-toolbar');
if (e) {
e.style.display = 'block';
var url = e.getAttribute('data-url');
ajax(url, {
success: function(xhr) {
var div = document.createElement('div');
div.innerHTML = xhr.responseText;
e.parentNode.replaceChild(div, e);
if (window.localStorage) {
var pref = localStorage.getItem('yii-debug-toolbar');
if (pref == 'minimized') {
document.getElementById('yii-debug-toolbar').style.display = 'none';
document.getElementById('yii-debug-toolbar-min').style.display = 'block';
}
}
},
error: function(xhr) {
e.innerHTML = xhr.responseText;
}
});
}
var e = document.getElementById('yii-debug-toolbar');
if (e) {
e.style.display = 'block';
var url = e.getAttribute('data-url');
ajax(url, {
success: function (xhr) {
var div = document.createElement('div');
div.innerHTML = xhr.responseText;
e.parentNode.replaceChild(div, e);
if (window.localStorage) {
var pref = localStorage.getItem('yii-debug-toolbar');
if (pref == 'minimized') {
document.getElementById('yii-debug-toolbar').style.display = 'none';
document.getElementById('yii-debug-toolbar-min').style.display = 'block';
}
}
},
error: function (xhr) {
e.innerHTML = xhr.responseText;
}
});
}
})();
......@@ -13,16 +13,16 @@ echo DetailView::widget([
'to',
'charset',
[
'name' => 'time',
'attribute' => 'time',
'value' => $timeFormatter->asDateTime($model['time'], 'short'),
],
'subject',
[
'name' => 'body',
'attribute' => 'body',
'label' => 'Text body',
],
[
'name' => 'isSuccessful',
'attribute' => 'isSuccessful',
'label' => 'Successfully sent',
'value' => $model['isSuccessful'] ? 'Yes' : 'No'
],
......@@ -30,7 +30,7 @@ echo DetailView::widget([
'bcc',
'cc',
[
'name' => 'file',
'attribute' => 'file',
'format' => 'html',
'value' => Html::a('Download eml', ['download-mail', 'file' => $model['file']]),
],
......
yii.gii = (function ($) {
var isActive = $('.default-view').length > 0;
var isActive = $('.default-view').length > 0;
var initHintBlocks = function () {
$('.hint-block').each(function () {
var $hint = $(this);
$hint.parent().find('label').addClass('help').popover({
html: true,
trigger: 'hover',
placement: 'right',
content: $hint.html()
});
});
};
var initHintBlocks = function () {
$('.hint-block').each(function () {
var $hint = $(this);
$hint.parent().find('label').addClass('help').popover({
html: true,
trigger: 'hover',
placement: 'right',
content: $hint.html()
});
});
};
var initStickyInputs = function () {
$('.sticky:not(.error)').find('input[type="text"],select,textarea').each(function () {
var value;
if (this.tagName === 'SELECT') {
value = this.options[this.selectedIndex].text;
} else if (this.tagName === 'TEXTAREA') {
value = $(this).html();
} else {
value = $(this).val();
}
if (value === '') {
value = '[empty]';
}
$(this).before('<div class="sticky-value">' + value + '</div>').hide();
});
$('.sticky-value').on('click', function () {
$(this).hide();
$(this).next().show().get(0).focus();
});
};
var initStickyInputs = function () {
$('.sticky:not(.error)').find('input[type="text"],select,textarea').each(function () {
var value;
if (this.tagName === 'SELECT') {
value = this.options[this.selectedIndex].text;
} else if (this.tagName === 'TEXTAREA') {
value = $(this).html();
} else {
value = $(this).val();
}
if (value === '') {
value = '[empty]';
}
$(this).before('<div class="sticky-value">' + value + '</div>').hide();
});
$('.sticky-value').on('click', function () {
$(this).hide();
$(this).next().show().get(0).focus();
});
};
var initPreviewDiffLinks = function () {
$('.preview-code, .diff-code, .modal-refresh, .modal-previous, .modal-next').on('click', function () {
var $modal = $('#preview-modal');
var $link = $(this);
$modal.find('.modal-refresh').attr('href', $link.attr('href'));
if ($link.hasClass('preview-code') || $link.hasClass('diff-code')) {
$modal.data('action', ($link.hasClass('preview-code') ? 'preview-code' : 'diff-code'))
}
$modal.find('.modal-title').text($link.data('title'));
$modal.find('.modal-body').html('Loading ...');
$modal.modal('show');
$.ajax({
type: 'POST',
cache: false,
url: $link.prop('href'),
data: $('.default-view form').serializeArray(),
success: function (data) {
if (!$link.hasClass('modal-refresh')) {
var filesSelector = 'a.' + $modal.data('action');
var $files = $(filesSelector);
var index = $files.filter('[href="' + $link.attr('href') + '"]').index(filesSelector);
var $prev = $files.eq(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-next').attr('href', $next.attr('href')).data('title', $next.data('title'));
}
$modal.find('.modal-body').html(data);
$modal.find('.content').css('max-height', ($(window).height() - 200) + 'px');
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$modal.find('.modal-body').html('<div class="error">' + XMLHttpRequest.responseText + '</div>');
}
});
return false;
});
var initPreviewDiffLinks = function () {
$('.preview-code, .diff-code, .modal-refresh, .modal-previous, .modal-next').on('click', function () {
var $modal = $('#preview-modal');
var $link = $(this);
$modal.find('.modal-refresh').attr('href', $link.attr('href'));
if ($link.hasClass('preview-code') || $link.hasClass('diff-code')) {
$modal.data('action', ($link.hasClass('preview-code') ? 'preview-code' : 'diff-code'))
}
$modal.find('.modal-title').text($link.data('title'));
$modal.find('.modal-body').html('Loading ...');
$modal.modal('show');
$.ajax({
type: 'POST',
cache: false,
url: $link.prop('href'),
data: $('.default-view form').serializeArray(),
success: function (data) {
if (!$link.hasClass('modal-refresh')) {
var filesSelector = 'a.' + $modal.data('action');
var $files = $(filesSelector);
var index = $files.filter('[href="' + $link.attr('href') + '"]').index(filesSelector);
var $prev = $files.eq(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-next').attr('href', $next.attr('href')).data('title', $next.data('title'));
}
$modal.find('.modal-body').html(data);
$modal.find('.content').css('max-height', ($(window).height() - 200) + 'px');
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$modal.find('.modal-body').html('<div class="error">' + XMLHttpRequest.responseText + '</div>');
}
});
return false;
});
$('#preview-modal').on('keydown', function(e) {
if (e.keyCode === 37) {
$('.modal-previous').trigger('click');
} else if(e.keyCode === 39) {
$('.modal-next').trigger('click');
} else if(e.keyCode === 82) {
$('.modal-refresh').trigger('click');
}
});
};
$('#preview-modal').on('keydown', function (e) {
if (e.keyCode === 37) {
$('.modal-previous').trigger('click');
} else if (e.keyCode === 39) {
$('.modal-next').trigger('click');
} else if (e.keyCode === 82) {
$('.modal-refresh').trigger('click');
}
});
};
var initConfirmationCheckboxes = function () {
var $checkAll = $('#check-all');
$checkAll.click(function () {
$('.default-view-files table .check input').prop('checked', this.checked);
});
$('.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);
};
var initConfirmationCheckboxes = function () {
var $checkAll = $('#check-all');
$checkAll.click(function () {
$('.default-view-files table .check input').prop('checked', this.checked);
});
$('.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);
};
return {
autocomplete: function (counter, data) {
var datum = new Bloodhound({
datumTokenizer: function(d){return Bloodhound.tokenizers.whitespace(d.word);},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: data
});
datum.initialize();
jQuery('.typeahead-'+counter).typeahead(null,{displayKey: 'word', source: datum.ttAdapter()});
},
init: function () {
initHintBlocks();
initStickyInputs();
initPreviewDiffLinks();
initConfirmationCheckboxes();
return {
autocomplete: function (counter, data) {
var datum = new Bloodhound({
datumTokenizer: function (d) {
return Bloodhound.tokenizers.whitespace(d.word);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: data
});
datum.initialize();
jQuery('.typeahead-' + counter).typeahead(null, {displayKey: 'word', source: datum.ttAdapter()});
},
init: function () {
initHintBlocks();
initStickyInputs();
initPreviewDiffLinks();
initConfirmationCheckboxes();
// model generator: hide class name input when table name input contains *
$('#model-generator #generator-tablename').on('change', function () {
$('#model-generator .field-generator-modelclass').toggle($(this).val().indexOf('*') == -1);
}).change();
// model generator: hide class name input when table name input contains *
$('#model-generator #generator-tablename').on('change',function () {
$('#model-generator .field-generator-modelclass').toggle($(this).val().indexOf('*') == -1);
}).change();
// hide Generate button if any input is changed
$('.default-view .form-group input,select,textarea').change(function () {
$('.default-view-results,.default-view-files').hide();
$('.default-view button[name="generate"]').hide();
});
// hide Generate button if any input is changed
$('.default-view .form-group input,select,textarea').change(function () {
$('.default-view-results,.default-view-files').hide();
$('.default-view button[name="generate"]').hide();
});
$('.module-form #generator-moduleclass').change(function () {
var value = $(this).val().match(/(\w+)\\\w+$/);
var $idInput = $('#generator-moduleid');
if (value && value[1] && $idInput.val() == '') {
$idInput.val(value[1]);
}
});
}
};
$('.module-form #generator-moduleclass').change(function () {
var value = $(this).val().match(/(\w+)\\\w+$/);
var $idInput = $('#generator-moduleid');
if (value && value[1] && $idInput.val() == '') {
$idInput.val(value[1]);
}
});
}
};
})(jQuery);
......@@ -70,7 +70,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/**
* Displays a single <?= $modelClass ?> model.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?>
* <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed
*/
public function actionView(<?= $actionParams ?>)
......@@ -101,7 +101,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/**
* Updates an existing <?= $modelClass ?> model.
* If update is successful, the browser will be redirected to the 'view' page.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?>
* <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed
*/
public function actionUpdate(<?= $actionParams ?>)
......@@ -120,7 +120,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/**
* Deletes an existing <?= $modelClass ?> model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* <?= implode("\n\t * ", $actionParamComments) . "\n" ?>
* <?= implode("\n * ", $actionParamComments) . "\n" ?>
* @return mixed
*/
public function actionDelete(<?= $actionParams ?>)
......@@ -133,7 +133,7 @@ class <?= $controllerClass ?> extends <?= StringHelper::basename($generator->bas
/**
* Finds the <?= $modelClass ?> model based on its primary key value.
* 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
* @throws NotFoundHttpException if the model cannot be found
*/
......
......@@ -33,12 +33,12 @@ use <?= ltrim($generator->modelClass, '\\') . (isset($modelAlias) ? " as $modelA
*/
class <?= $searchModelClass ?> extends Model
{
public $<?= implode(";\n\tpublic $", $searchAttributes) ?>;
public $<?= implode(";\n public $", $searchAttributes) ?>;
public function rules()
{
return [
<?= implode(",\n\t\t\t", $rules) ?>,
<?= implode(",\n ", $rules) ?>,
];
}
......@@ -65,7 +65,7 @@ class <?= $searchModelClass ?> extends Model
return $dataProvider;
}
<?= implode("\n\t\t", $searchConditions) ?>
<?= implode("\n ", $searchConditions) ?>
return $dataProvider;
}
......
......@@ -33,11 +33,11 @@ use yii\widgets\ActiveForm;
<?= "<?php " ?>$form = ActiveForm::begin(); ?>
<?php foreach ($safeAttributes as $attribute) {
echo "\t\t<?= " . $generator->generateActiveField($attribute) . " ?>\n\n";
echo " <?= " . $generator->generateActiveField($attribute) . " ?>\n\n";
} ?>
<div class="form-group">
<?= "<?= " ?>Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<div class="form-group">
<?= "<?= " ?>Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?= "<?php " ?>ActiveForm::end(); ?>
......
......@@ -32,16 +32,16 @@ use yii\widgets\ActiveForm;
$count = 0;
foreach ($generator->getColumnNames() as $attribute) {
if (++$count < 6) {
echo "\t\t<?= " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
echo " <?= " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
} else {
echo "\t\t<?php // echo " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
echo " <?php // echo " . $generator->generateActiveSearchField($attribute) . " ?>\n\n";
}
}
?>
<div class="form-group">
<?= "<?= " ?>Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= "<?= " ?>Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<div class="form-group">
<?= "<?= " ?>Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= "<?= " ?>Html::resetButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?= "<?php " ?>ActiveForm::end(); ?>
......
......@@ -48,18 +48,18 @@ $count = 0;
if (($tableSchema = $generator->getTableSchema()) === false) {
foreach ($generator->getColumnNames() as $name) {
if (++$count < 6) {
echo "\t\t\t'" . $name . "',\n";
echo " '" . $name . "',\n";
} else {
echo "\t\t\t// '" . $name . "',\n";
echo " // '" . $name . "',\n";
}
}
} else {
foreach ($tableSchema->columns as $column) {
$format = $generator->generateColumnFormat($column);
if (++$count < 6) {
echo "\t\t\t'" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
echo " '" . $column->name . ($format === 'text' ? "" : ":" . $format) . "',\n";
} 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;
<?php
if (($tableSchema = $generator->getTableSchema()) === false) {
foreach ($generator->getColumnNames() as $name) {
echo "\t\t\t'" . $name . "',\n";
echo " '" . $name . "',\n";
}
} else {
foreach ($generator->getTableSchema()->columns as $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, '\\') .
*/
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
- 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 #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 incorrect event name for `yii\jui\Spinner` (samdark)
- Bug: Json::encode() did not handle objects that implement JsonSerializable interface correctly (cebe)
......@@ -72,6 +73,7 @@ Yii Framework 2 Change Log
- 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 #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 #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)
......@@ -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 #2735: Added support for `DateTimeInterface` in `Formatter` (ivokund)
- 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 `favicon.ico` and `robots.txt` to default application templates (samdark)
- Enh: Added `Widget::autoIdPrefix` to support prefixing automatically generated widget IDs (qiangxue)
......@@ -241,6 +244,7 @@ Yii Framework 2 Change Log
- Renamed `yii\web\User::returnUrlVar` to `returnUrlParam`
- 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: `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 #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)
......
......@@ -10,400 +10,400 @@
* @since 2.0
*/
(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 = {
// the jQuery selector for the error summary
errorSummary: undefined,
// whether to perform validation before submitting the form.
validateOnSubmit: true,
// the container CSS class representing the corresponding attribute has validation error
errorCssClass: 'error',
// the container CSS class representing the corresponding attribute passes validation
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'
};
$.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 attributeDefaults = {
// attribute name or expression (e.g. "[0]content" for tabular input)
name: undefined,
// the jQuery selector of the container of the input field
container: undefined,
// 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 defaults = {
// the jQuery selector for the error summary
errorSummary: undefined,
// whether to perform validation before submitting the form.
validateOnSubmit: true,
// the container CSS class representing the corresponding attribute has validation error
errorCssClass: 'error',
// the container CSS class representing the corresponding attribute passes validation
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 methods = {
init: function (attributes, options) {
return this.each(function () {
var $form = $(this);
if ($form.data('yiiActiveForm')) {
return;
}
var attributeDefaults = {
// attribute name or expression (e.g. "[0]content" for tabular input)
name: undefined,
// the jQuery selector of the container of the input field
container: undefined,
// 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 || {});
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
});
var methods = {
init: function (attributes, options) {
return this.each(function () {
var $form = $(this);
if ($form.data('yiiActiveForm')) {
return;
}
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
});
/**
* 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);
watchAttributes($form, attributes);
if (settings.validateOnSubmit) {
$form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () {
$form.data('yiiActiveForm').submitObject = $(this);
});
$form.on('submit', methods.submitForm);
}
});
},
/**
* 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);
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiActiveForm');
$(this).removeData('yiiActiveForm');
});
},
if (settings.validateOnSubmit) {
$form.on('mouseup.yiiActiveForm keyup.yiiActiveForm', ':submit', function () {
$form.data('yiiActiveForm').submitObject = $(this);
});
$form.on('submit', methods.submitForm);
}
});
},
data: function() {
return this.data('yiiActiveForm');
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiActiveForm');
$(this).removeData('yiiActiveForm');
});
},
submitForm: function () {
var $form = $(this),
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;
}
data: function () {
return this.data('yiiActiveForm');
},
if (data.settings.timer !== undefined) {
clearTimeout(data.settings.timer);
}
data.submitting = true;
validate($form, function (messages) {
var errors = [];
$.each(data.attributes, function () {
if (updateInput($form, this, messages)) {
errors.push(this.input);
}
});
updateSummary($form, messages);
if (errors.length) {
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;
},
submitForm: function () {
var $form = $(this),
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;
}
resetForm: function () {
var $form = $(this);
var data = $form.data('yiiActiveForm');
// Because we bind directly to a form reset event instead of a reset button (that may not exist),
// when this function is executed form input values have not been reset yet.
// Therefore we do the actual reset work through setTimeout.
setTimeout(function () {
$.each(data.attributes, function () {
// 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);
$container.removeClass(
data.settings.validatingCssClass + ' ' +
data.settings.errorCssClass + ' ' +
data.settings.successCssClass
);
$container.find(this.error).html('');
});
$form.find(data.settings.summary).hide().find('ul').html('');
}, 1);
}
};
if (data.settings.timer !== undefined) {
clearTimeout(data.settings.timer);
}
data.submitting = true;
validate($form, function (messages) {
var errors = [];
$.each(data.attributes, function () {
if (updateInput($form, this, messages)) {
errors.push(this.input);
}
});
updateSummary($form, messages);
if (errors.length) {
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;
},
var watchAttributes = function ($form, attributes) {
$.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);
}
});
}
});
};
resetForm: function () {
var $form = $(this);
var data = $form.data('yiiActiveForm');
// Because we bind directly to a form reset event instead of a reset button (that may not exist),
// when this function is executed form input values have not been reset yet.
// Therefore we do the actual reset work through setTimeout.
setTimeout(function () {
$.each(data.attributes, function () {
// 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);
$container.removeClass(
data.settings.validatingCssClass + ' ' +
data.settings.errorCssClass + ' ' +
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 data = $form.data('yiiActiveForm');
var watchAttributes = function ($form, attributes) {
$.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) {
attribute.status = 2;
}
$.each(data.attributes, function () {
if (this.value !== getValue($form, this)) {
this.status = 2;
forceValidate = true;
}
});
if (!forceValidate) {
return;
}
var validateAttribute = function ($form, attribute, forceValidate) {
var data = $form.data('yiiActiveForm');
if (data.settings.timer !== undefined) {
clearTimeout(data.settings.timer);
}
data.settings.timer = setTimeout(function () {
if (data.submitting || $form.is(':hidden')) {
return;
}
$.each(data.attributes, function () {
if (this.status === 2) {
this.status = 3;
$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);
};
/**
* 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 = {};
if (forceValidate) {
attribute.status = 2;
}
$.each(data.attributes, function () {
if (this.value !== getValue($form, this)) {
this.status = 2;
forceValidate = true;
}
});
if (!forceValidate) {
return;
}
$.each(data.attributes, function () {
if (data.submitting || this.status === 2 || this.status === 3) {
var msg = [];
if (!data.settings.beforeValidate || data.settings.beforeValidate($form, this, msg)) {
if (this.validate) {
this.validate(this, getValue($form, this), msg);
}
if (msg.length) {
messages[this.name] = msg;
} else if (this.enableAjaxValidation) {
needAjaxValidation = true;
}
}
}
});
if (data.settings.timer !== undefined) {
clearTimeout(data.settings.timer);
}
data.settings.timer = setTimeout(function () {
if (data.submitting || $form.is(':hidden')) {
return;
}
$.each(data.attributes, function () {
if (this.status === 2) {
this.status = 3;
$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.
// If the validation is triggered by form submission, ajax validation
// should be done only when all inputs pass client validation
var $button = data.submitObject,
extData = '&' + data.settings.ajaxParam + '=' + $form.prop('id');
if ($button && $button.length && $button.prop('name')) {
extData += '&' + $button.prop('name') + '=' + $button.prop('value');
}
$.ajax({
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);
}
};
/**
* 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 = {};
/**
* Updates the error message and the input container for a particular attribute.
* @param $form the form jQuery object
* @param attribute object the configuration for a particular attribute.
* @param messages array the validation error messages
* @return boolean whether there is a validation error for the specified attribute
*/
var updateInput = function ($form, attribute, messages) {
var data = $form.data('yiiActiveForm'),
$input = findInput($form, attribute),
hasError = false;
$.each(data.attributes, function () {
if (data.submitting || this.status === 2 || this.status === 3) {
var msg = [];
if (!data.settings.beforeValidate || data.settings.beforeValidate($form, this, msg)) {
if (this.validate) {
this.validate(this, getValue($form, this), msg);
}
if (msg.length) {
messages[this.name] = msg;
} else if (this.enableAjaxValidation) {
needAjaxValidation = true;
}
}
}
});
if (data.settings.afterValidate) {
data.settings.afterValidate($form, attribute, messages);
}
attribute.status = 1;
if ($input.length) {
hasError = messages && $.isArray(messages[attribute.name]) && messages[attribute.name].length;
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;
};
if (needAjaxValidation && (!data.submitting || $.isEmptyObject(messages))) {
// Perform ajax validation when at least one input needs it.
// If the validation is triggered by form submission, ajax validation
// should be done only when all inputs pass client validation
var $button = data.submitObject,
extData = '&' + data.settings.ajaxParam + '=' + $form.prop('id');
if ($button && $button.length && $button.prop('name')) {
extData += '&' + $button.prop('name') + '=' + $button.prop('value');
}
$.ajax({
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);
}
};
/**
* Updates the error summary.
* @param $form the form jQuery object
* @param messages array the validation error messages
*/
var updateSummary = function ($form, messages) {
var data = $form.data('yiiActiveForm'),
$summary = $form.find(data.settings.errorSummary),
$ul = $summary.find('ul').html('');
/**
* Updates the error message and the input container for a particular attribute.
* @param $form the form jQuery object
* @param attribute object the configuration for a particular attribute.
* @param messages array the validation error messages
* @return boolean whether there is a validation error for the specified attribute
*/
var updateInput = function ($form, attribute, messages) {
var data = $form.data('yiiActiveForm'),
$input = findInput($form, attribute),
hasError = false;
if ($summary.length && messages) {
$.each(data.attributes, function () {
if ($.isArray(messages[this.name]) && messages[this.name].length) {
$ul.append($('<li/>').text(messages[this.name][0]));
}
});
$summary.toggle($ul.find('li').length > 0);
}
};
if (data.settings.afterValidate) {
data.settings.afterValidate($form, attribute, messages);
}
attribute.status = 1;
if ($input.length) {
hasError = messages && $.isArray(messages[attribute.name]) && messages[attribute.name].length;
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);
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();
}
};
/**
* Updates the error summary.
* @param $form the form jQuery object
* @param messages array the validation error messages
*/
var updateSummary = function ($form, messages) {
var data = $form.data('yiiActiveForm'),
$summary = $form.find(data.settings.errorSummary),
$ul = $summary.find('ul').html('');
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;
}
};
if ($summary.length && messages) {
$.each(data.attributes, function () {
if ($.isArray(messages[this.name]) && messages[this.name].length) {
$ul.append($('<li/>').text(messages[this.name][0]));
}
});
$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);
......@@ -10,63 +10,63 @@
* @since 2.0
*/
(function ($) {
$.fn.yiiCaptcha = 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.yiiCaptcha');
return false;
}
};
$.fn.yiiCaptcha = 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.yiiCaptcha');
return false;
}
};
var defaults = {
refreshUrl: undefined,
hashKey: undefined
};
var defaults = {
refreshUrl: undefined,
hashKey: undefined
};
var methods = {
init: function (options) {
return this.each(function () {
var $e = $(this);
var settings = $.extend({}, defaults, options || {});
$e.data('yiiCaptcha', {
settings: settings
});
var methods = {
init: function (options) {
return this.each(function () {
var $e = $(this);
var settings = $.extend({}, defaults, options || {});
$e.data('yiiCaptcha', {
settings: settings
});
$e.on('click.yiiCaptcha', function() {
methods.refresh.apply($e);
return false;
});
$e.on('click.yiiCaptcha', function () {
methods.refresh.apply($e);
return false;
});
});
},
});
},
refresh: function () {
var $e = this,
settings = this.data('yiiCaptcha').settings;
$.ajax({
url: $e.data('yiiCaptcha').settings.refreshUrl,
dataType: 'json',
cache: false,
success: function(data) {
$e.attr('src', data.url);
$('body').data(settings.hashKey, [data.hash1, data.hash2]);
}
});
},
refresh: function () {
var $e = this,
settings = this.data('yiiCaptcha').settings;
$.ajax({
url: $e.data('yiiCaptcha').settings.refreshUrl,
dataType: 'json',
cache: false,
success: function (data) {
$e.attr('src', data.url);
$('body').data(settings.hashKey, [data.hash1, data.hash2]);
}
});
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiCaptcha');
$(this).removeData('yiiCaptcha');
});
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiCaptcha');
$(this).removeData('yiiCaptcha');
});
},
data: function() {
return this.data('yiiCaptcha');
}
};
data: function () {
return this.data('yiiCaptcha');
}
};
})(window.jQuery);
......@@ -10,120 +10,120 @@
* @since 2.0
*/
(function ($) {
$.fn.yiiGridView = 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.yiiGridView');
return false;
}
};
$.fn.yiiGridView = 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.yiiGridView');
return false;
}
};
var defaults = {
filterUrl: undefined,
filterSelector: undefined
};
var defaults = {
filterUrl: undefined,
filterSelector: undefined
};
var gridData = {};
var gridData = {};
var methods = {
init: function (options) {
return this.each(function () {
var $e = $(this);
var settings = $.extend({}, defaults, options || {});
gridData[$e.prop('id')] = {settings: settings};
var methods = {
init: function (options) {
return this.each(function () {
var $e = $(this);
var settings = $.extend({}, defaults, options || {});
gridData[$e.prop('id')] = {settings: settings};
var enterPressed = false;
$(document).off('change.yiiGridView keydown.yiiGridView', settings.filterSelector)
.on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) {
if (event.type === 'keydown') {
if (event.keyCode !== 13) {
return; // only react to enter key
} else {
enterPressed = true;
}
} else {
// prevent processing for both keydown and change events
if (enterPressed) {
enterPressed = false;
return;
}
}
var enterPressed = false;
$(document).off('change.yiiGridView keydown.yiiGridView', settings.filterSelector)
.on('change.yiiGridView keydown.yiiGridView', settings.filterSelector, function (event) {
if (event.type === 'keydown') {
if (event.keyCode !== 13) {
return; // only react to enter key
} else {
enterPressed = true;
}
} else {
// prevent processing for both keydown and change events
if (enterPressed) {
enterPressed = false;
return;
}
}
methods.applyFilter.apply($e);
methods.applyFilter.apply($e);
return false;
});
});
},
return false;
});
});
},
applyFilter: function () {
var $grid = $(this);
var settings = gridData[$grid.prop('id')].settings;
var data = {};
$.each($(settings.filterSelector).serializeArray(), function () {
data[this.name] = this.value;
});
applyFilter: function () {
var $grid = $(this);
var settings = gridData[$grid.prop('id')].settings;
var data = {};
$.each($(settings.filterSelector).serializeArray(), function () {
data[this.name] = this.value;
});
$.each(yii.getQueryParams(settings.filterUrl), function (name, value) {
if (data[name] === undefined) {
data[name] = value;
}
});
$.each(yii.getQueryParams(settings.filterUrl), function (name, value) {
if (data[name] === undefined) {
data[name] = value;
}
});
var pos = settings.filterUrl.indexOf('?');
var url = pos < 0 ? settings.filterUrl : settings.filterUrl.substring(0, pos);
var pos = settings.filterUrl.indexOf('?');
var url = pos < 0 ? settings.filterUrl : settings.filterUrl.substring(0, pos);
$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);
$.each(data, function (name, value) {
$form.append($('<input type="hidden" name="t" value="" />').attr('name', name).val(value));
});
$form.submit();
},
$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);
$.each(data, function (name, value) {
$form.append($('<input type="hidden" name="t" value="" />').attr('name', name).val(value));
});
$form.submit();
},
setSelectionColumn: function (options) {
var $grid = $(this);
var id = $(this).prop('id');
gridData[id].selectionColumn = options.name;
if (!options.multiple) {
return;
}
var inputs = "#" + id + " input[name='" + options.checkAll + "']";
$(document).off('click.yiiGridView', inputs).on('click.yiiGridView', inputs, function () {
$grid.find("input[name='" + options.name + "']:enabled").prop('checked', this.checked);
});
$(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;
$grid.find("input[name='" + options.checkAll + "']").prop('checked', all);
});
},
setSelectionColumn: function (options) {
var $grid = $(this);
var id = $(this).prop('id');
gridData[id].selectionColumn = options.name;
if (!options.multiple) {
return;
}
var inputs = "#" + id + " input[name='" + options.checkAll + "']";
$(document).off('click.yiiGridView', inputs).on('click.yiiGridView', inputs, function () {
$grid.find("input[name='" + options.name + "']:enabled").prop('checked', this.checked);
});
$(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;
$grid.find("input[name='" + options.checkAll + "']").prop('checked', all);
});
},
getSelectedRows: function () {
var $grid = $(this);
var data = gridData[$grid.prop('id')];
var keys = [];
if (data.selectionColumn) {
$grid.find("input[name='" + data.selectionColumn + "']:checked").each(function () {
keys.push($(this).parent().closest('tr').data('key'));
});
}
return keys;
},
getSelectedRows: function () {
var $grid = $(this);
var data = gridData[$grid.prop('id')];
var keys = [];
if (data.selectionColumn) {
$grid.find("input[name='" + data.selectionColumn + "']:checked").each(function () {
keys.push($(this).parent().closest('tr').data('key'));
});
}
return keys;
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiGridView');
$(this).removeData('yiiGridView');
});
},
destroy: function () {
return this.each(function () {
$(window).unbind('.yiiGridView');
$(this).removeData('yiiGridView');
});
},
data: function () {
var id = $(this).prop('id');
return gridData[id];
}
};
data: function () {
var id = $(this).prop('id');
return gridData[id];
}
};
})(window.jQuery);
......@@ -42,220 +42,220 @@
* You must call "yii.initModule()" once for the root module of all your modules.
*/
yii = (function ($) {
var pub = {
/**
* 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.
*/
reloadableScripts: [],
/**
* 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"]',
/**
* The selector for changeable elements that need to support confirmation and form submission.
*/
changeableSelector: 'select, input, textarea',
var pub = {
/**
* 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.
*/
reloadableScripts: [],
/**
* 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"]',
/**
* The selector for changeable elements that need to support confirmation and form submission.
*/
changeableSelector: 'select, input, textarea',
/**
* @return string|undefined the CSRF parameter name. Undefined is returned if CSRF validation is not enabled.
*/
getCsrfParam: function () {
return $('meta[name=csrf-param]').prop('content');
},
/**
* @return string|undefined the CSRF parameter name. Undefined is returned if CSRF validation is not enabled.
*/
getCsrfParam: function () {
return $('meta[name=csrf-param]').prop('content');
},
/**
* @return string|undefined the CSRF token. Undefined is returned if CSRF validation is not enabled.
*/
getCsrfToken: function () {
return $('meta[name=csrf-token]').prop('content');
},
/**
* @return string|undefined the CSRF token. Undefined is returned if CSRF validation is not enabled.
*/
getCsrfToken: function () {
return $('meta[name=csrf-token]').prop('content');
},
/**
* Displays a confirmation dialog.
* The default implementation simply displays a js confirmation dialog.
* You may override this by setting `yii.confirm`.
* @param message the confirmation message.
* @return boolean whether the user confirms with the message in the dialog
*/
confirm: function (message) {
return confirm(message);
},
/**
* Displays a confirmation dialog.
* The default implementation simply displays a js confirmation dialog.
* You may override this by setting `yii.confirm`.
* @param message the confirmation message.
* @return boolean whether the user confirms with the message in the dialog
*/
confirm: function (message) {
return confirm(message);
},
/**
* 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
* 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.
* @param $e the jQuery representation of the element
* @return boolean whether to allow executing the action defined for the specified element.
*/
allowAction: function ($e) {
var message = $e.data('confirm');
return message === undefined || pub.confirm(message);
},
/**
* 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
* 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.
* @param $e the jQuery representation of the element
* @return boolean whether to allow executing the action defined for the specified element.
*/
allowAction: function ($e) {
var message = $e.data('confirm');
return message === undefined || pub.confirm(message);
},
/**
* Handles the action triggered by user.
* 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
* 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 other elements, either the containing form action or the current page URL will be used
* as the form action URL.
*
* If the `data-method` attribute is not defined, the default element action will be performed.
*
* @param $e the jQuery representation of the element
* @return boolean whether to execute the default action for the element.
*/
handleAction: function ($e) {
var method = $e.data('method');
if (method === undefined) {
return true;
}
/**
* Handles the action triggered by user.
* 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
* 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 other elements, either the containing form action or the current page URL will be used
* as the form action URL.
*
* If the `data-method` attribute is not defined, the default element action will be performed.
*
* @param $e the jQuery representation of the element
* @return boolean whether to execute the default action for the element.
*/
handleAction: function ($e) {
var method = $e.data('method');
if (method === undefined) {
return true;
}
var $form = $e.closest('form');
var newForm = !$form.length;
if (newForm) {
var action = $e.prop('href');
if (!action || !action.match(/(^\/|:\/\/)/)) {
action = window.location.href;
}
$form = $('<form method="' + method + '" action="' + action + '"></form>');
var target = $e.prop('target');
if (target) {
$form.attr('target', target);
}
if (!method.match(/(get|post)/i)) {
$form.append('<input name="_method" value="' + method + '" type="hidden">');
}
var csrfParam = pub.getCsrfParam();
if (csrfParam) {
$form.append('<input name="' + csrfParam + '" value="' + pub.getCsrfToken() + '" type="hidden">');
}
$form.hide().appendTo('body');
}
var $form = $e.closest('form');
var newForm = !$form.length;
if (newForm) {
var action = $e.prop('href');
if (!action || !action.match(/(^\/|:\/\/)/)) {
action = window.location.href;
}
$form = $('<form method="' + method + '" action="' + action + '"></form>');
var target = $e.prop('target');
if (target) {
$form.attr('target', target);
}
if (!method.match(/(get|post)/i)) {
$form.append('<input name="_method" value="' + method + '" type="hidden">');
}
var csrfParam = pub.getCsrfParam();
if (csrfParam) {
$form.append('<input name="' + csrfParam + '" value="' + pub.getCsrfToken() + '" type="hidden">');
}
$form.hide().appendTo('body');
}
var activeFormData = $form.data('yiiActiveForm');
if (activeFormData) {
// remember who triggers the form submission. This is used by yii.activeForm.js
activeFormData.submitObject = $e;
}
var activeFormData = $form.data('yiiActiveForm');
if (activeFormData) {
// remember who triggers the form submission. This is used by yii.activeForm.js
activeFormData.submitObject = $e;
}
$form.trigger('submit');
$form.trigger('submit');
if (newForm) {
$form.remove();
}
if (newForm) {
$form.remove();
}
return false;
},
return false;
},
getQueryParams: function (url) {
var pos = url.indexOf('?');
if (pos < 0) {
return {};
}
var qs = url.substring(pos + 1).split('&');
for (var i = 0, result = {}; i < qs.length; i++) {
qs[i] = qs[i].split('=');
result[decodeURIComponent(qs[i][0])] = decodeURIComponent(qs[i][1]);
}
return result;
},
getQueryParams: function (url) {
var pos = url.indexOf('?');
if (pos < 0) {
return {};
}
var qs = url.substring(pos + 1).split('&');
for (var i = 0, result = {}; i < qs.length; i++) {
qs[i] = qs[i].split('=');
result[decodeURIComponent(qs[i][0])] = decodeURIComponent(qs[i][1]);
}
return result;
},
initModule: function (module) {
if (module.isActive === undefined || module.isActive) {
if ($.isFunction(module.init)) {
module.init();
}
$.each(module, function () {
if ($.isPlainObject(this)) {
pub.initModule(this);
}
});
}
},
initModule: function (module) {
if (module.isActive === undefined || module.isActive) {
if ($.isFunction(module.init)) {
module.init();
}
$.each(module, function () {
if ($.isPlainObject(this)) {
pub.initModule(this);
}
});
}
},
init: function () {
initCsrfHandler();
initRedirectHandler();
initScriptFilter();
initDataMethods();
}
};
init: function () {
initCsrfHandler();
initRedirectHandler();
initScriptFilter();
initDataMethods();
}
};
function initRedirectHandler() {
// handle AJAX redirection
$(document).ajaxComplete(function (event, xhr, settings) {
var url = xhr.getResponseHeader('X-Redirect');
if (url) {
window.location = url;
}
});
}
function initRedirectHandler() {
// handle AJAX redirection
$(document).ajaxComplete(function (event, xhr, settings) {
var url = xhr.getResponseHeader('X-Redirect');
if (url) {
window.location = url;
}
});
}
function initCsrfHandler() {
// automatically send CSRF token for all AJAX requests
$.ajaxPrefilter(function (options, originalOptions, xhr) {
if (!options.crossDomain && pub.getCsrfParam()) {
xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken());
}
});
}
function initCsrfHandler() {
// automatically send CSRF token for all AJAX requests
$.ajaxPrefilter(function (options, originalOptions, xhr) {
if (!options.crossDomain && pub.getCsrfParam()) {
xhr.setRequestHeader('X-CSRF-Token', pub.getCsrfToken());
}
});
}
function initDataMethods() {
var $document = $(document);
// handle data-confirm and data-method for clickable elements
$document.on('click.yii', pub.clickableSelector, function (event) {
var $this = $(this);
if (pub.allowAction($this)) {
return pub.handleAction($this);
} else {
event.stopImmediatePropagation();
return false;
}
});
function initDataMethods() {
var $document = $(document);
// handle data-confirm and data-method for clickable elements
$document.on('click.yii', pub.clickableSelector, function (event) {
var $this = $(this);
if (pub.allowAction($this)) {
return pub.handleAction($this);
} else {
event.stopImmediatePropagation();
return false;
}
});
// handle data-confirm and data-method for changeable elements
$document.on('change.yii', pub.changeableSelector, function (event) {
var $this = $(this);
if (pub.allowAction($this)) {
return pub.handleAction($this);
} else {
event.stopImmediatePropagation();
return false;
}
});
}
// handle data-confirm and data-method for changeable elements
$document.on('change.yii', pub.changeableSelector, function (event) {
var $this = $(this);
if (pub.allowAction($this)) {
return pub.handleAction($this);
} else {
event.stopImmediatePropagation();
return false;
}
});
}
function initScriptFilter() {
var hostInfo = location.protocol + '//' + location.host;
var loadedScripts = $('script[src]').map(function () {
return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src;
}).toArray();
$.ajaxPrefilter('script', function (options, originalOptions, xhr) {
if(options.dataType == 'jsonp') {
return;
}
var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url;
if ($.inArray(url, loadedScripts) === -1) {
loadedScripts.push(url);
} else {
var found = $.inArray(url, $.map(pub.reloadableScripts, function (script) {
return script.charAt(0) === '/' ? hostInfo + script : script;
})) !== -1;
if (!found) {
xhr.abort();
}
}
});
}
function initScriptFilter() {
var hostInfo = location.protocol + '//' + location.host;
var loadedScripts = $('script[src]').map(function () {
return this.src.charAt(0) === '/' ? hostInfo + this.src : this.src;
}).toArray();
$.ajaxPrefilter('script', function (options, originalOptions, xhr) {
if (options.dataType == 'jsonp') {
return;
}
var url = options.url.charAt(0) === '/' ? hostInfo + options.url : options.url;
if ($.inArray(url, loadedScripts) === -1) {
loadedScripts.push(url);
} else {
var found = $.inArray(url, $.map(pub.reloadableScripts, function (script) {
return script.charAt(0) === '/' ? hostInfo + script : script;
})) !== -1;
if (!found) {
xhr.abort();
}
}
});
}
return pub;
return pub;
})(jQuery);
jQuery(document).ready(function () {
yii.initModule(yii);
yii.initModule(yii);
});
......@@ -11,218 +11,218 @@
*/
yii.validation = (function ($) {
var pub = {
isEmpty: function (value) {
return value === null || value === undefined || value == [] || value === '';
},
addMessage: function (messages, message, value) {
messages.push(message.replace(/\{value\}/g, value));
},
required: function (value, messages, options) {
var valid = false;
if (options.requiredValue === undefined) {
var isString = typeof value == 'string' || value instanceof String;
if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) {
valid = true;
}
} else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
valid = true;
}
if (!valid) {
pub.addMessage(messages, options.message, value);
}
},
boolean: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
|| options.strict && (value === options.trueValue || value === options.falseValue);
if (!valid) {
pub.addMessage(messages, options.message, value);
}
},
string: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (typeof value !== 'string') {
pub.addMessage(messages, options.message, value);
return;
}
if (options.min !== undefined && value.length < options.min) {
pub.addMessage(messages, options.tooShort, value);
}
if (options.max !== undefined && value.length > options.max) {
pub.addMessage(messages, options.tooLong, value);
}
if (options.is !== undefined && value.length != options.is) {
pub.addMessage(messages, options.is, value);
}
},
number: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (typeof value === 'string' && !value.match(options.pattern)) {
pub.addMessage(messages, options.message, value);
return;
}
if (options.min !== undefined && value < options.min) {
pub.addMessage(messages, options.tooSmall, value);
}
if (options.max !== undefined && value > options.max) {
pub.addMessage(messages, options.tooBig, value);
}
},
range: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var valid = !options.not && $.inArray(value, options.range) > -1
|| options.not && $.inArray(value, options.range) == -1;
if (!valid) {
pub.addMessage(messages, options.message, value);
}
},
regularExpression: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) {
pub.addMessage(messages, options.message, value);
}
},
email: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var valid = true;
if (options.enableIDN) {
var regexp = /^(.*<?)(.*)@(.*)(>?)$/,
matches = regexp.exec(value);
if (matches === null) {
valid = false;
} else {
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)))) {
pub.addMessage(messages, options.message, value);
}
},
url: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (options.defaultScheme && !value.match(/:\/\//)) {
value = options.defaultScheme + '://' + value;
}
var valid = true;
if (options.enableIDN) {
var regexp = /^([^:]+):\/\/([^\/]+)(.*)$/,
matches = regexp.exec(value);
if (matches === null) {
valid = false;
} else {
value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3];
}
}
if (!valid || !value.match(options.pattern)) {
pub.addMessage(messages, options.message, value);
}
},
captcha: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
// CAPTCHA may be updated via AJAX and the updated hash is stored in body data
var hash = $('body').data(options.hashKey);
if (hash == null) {
hash = options.hash;
} else {
hash = hash[options.caseSensitive ? 0 : 1];
}
var v = options.caseSensitive ? value : value.toLowerCase();
for (var i = v.length - 1, h = 0; i >= 0; --i) {
h += v.charCodeAt(i);
}
if (h != hash) {
pub.addMessage(messages, options.message, value);
}
},
compare: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var compareValue, valid = true;
if (options.compareAttribute === undefined) {
compareValue = options.compareValue;
} else {
compareValue = $('#' + options.compareAttribute).val();
}
switch (options.operator) {
case '==':
valid = value == compareValue;
break;
case '===':
valid = value === compareValue;
break;
case '!=':
valid = value != compareValue;
break;
case '!==':
valid = value !== compareValue;
break;
case '>':
valid = value > compareValue;
break;
case '>=':
valid = value >= compareValue;
break;
case '<':
valid = value < compareValue;
break;
case '<=':
valid = value <= compareValue;
break;
default:
valid = false;
break;
}
if (!valid) {
pub.addMessage(messages, options.message, value);
}
}
};
return pub;
var pub = {
isEmpty: function (value) {
return value === null || value === undefined || value == [] || value === '';
},
addMessage: function (messages, message, value) {
messages.push(message.replace(/\{value\}/g, value));
},
required: function (value, messages, options) {
var valid = false;
if (options.requiredValue === undefined) {
var isString = typeof value == 'string' || value instanceof String;
if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) {
valid = true;
}
} else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) {
valid = true;
}
if (!valid) {
pub.addMessage(messages, options.message, value);
}
},
boolean: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var valid = !options.strict && (value == options.trueValue || value == options.falseValue)
|| options.strict && (value === options.trueValue || value === options.falseValue);
if (!valid) {
pub.addMessage(messages, options.message, value);
}
},
string: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (typeof value !== 'string') {
pub.addMessage(messages, options.message, value);
return;
}
if (options.min !== undefined && value.length < options.min) {
pub.addMessage(messages, options.tooShort, value);
}
if (options.max !== undefined && value.length > options.max) {
pub.addMessage(messages, options.tooLong, value);
}
if (options.is !== undefined && value.length != options.is) {
pub.addMessage(messages, options.is, value);
}
},
number: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (typeof value === 'string' && !value.match(options.pattern)) {
pub.addMessage(messages, options.message, value);
return;
}
if (options.min !== undefined && value < options.min) {
pub.addMessage(messages, options.tooSmall, value);
}
if (options.max !== undefined && value > options.max) {
pub.addMessage(messages, options.tooBig, value);
}
},
range: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var valid = !options.not && $.inArray(value, options.range) > -1
|| options.not && $.inArray(value, options.range) == -1;
if (!valid) {
pub.addMessage(messages, options.message, value);
}
},
regularExpression: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (!options.not && !value.match(options.pattern) || options.not && value.match(options.pattern)) {
pub.addMessage(messages, options.message, value);
}
},
email: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var valid = true;
if (options.enableIDN) {
var regexp = /^(.*<?)(.*)@(.*)(>?)$/,
matches = regexp.exec(value);
if (matches === null) {
valid = false;
} else {
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)))) {
pub.addMessage(messages, options.message, value);
}
},
url: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
if (options.defaultScheme && !value.match(/:\/\//)) {
value = options.defaultScheme + '://' + value;
}
var valid = true;
if (options.enableIDN) {
var regexp = /^([^:]+):\/\/([^\/]+)(.*)$/,
matches = regexp.exec(value);
if (matches === null) {
valid = false;
} else {
value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3];
}
}
if (!valid || !value.match(options.pattern)) {
pub.addMessage(messages, options.message, value);
}
},
captcha: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
// CAPTCHA may be updated via AJAX and the updated hash is stored in body data
var hash = $('body').data(options.hashKey);
if (hash == null) {
hash = options.hash;
} else {
hash = hash[options.caseSensitive ? 0 : 1];
}
var v = options.caseSensitive ? value : value.toLowerCase();
for (var i = v.length - 1, h = 0; i >= 0; --i) {
h += v.charCodeAt(i);
}
if (h != hash) {
pub.addMessage(messages, options.message, value);
}
},
compare: function (value, messages, options) {
if (options.skipOnEmpty && pub.isEmpty(value)) {
return;
}
var compareValue, valid = true;
if (options.compareAttribute === undefined) {
compareValue = options.compareValue;
} else {
compareValue = $('#' + options.compareAttribute).val();
}
switch (options.operator) {
case '==':
valid = value == compareValue;
break;
case '===':
valid = value === compareValue;
break;
case '!=':
valid = value != compareValue;
break;
case '!==':
valid = value !== compareValue;
break;
case '>':
valid = value > compareValue;
break;
case '>=':
valid = value >= compareValue;
break;
case '<':
valid = value < compareValue;
break;
case '<=':
valid = value <= compareValue;
break;
default:
valid = false;
break;
}
if (!valid) {
pub.addMessage(messages, options.message, value);
}
}
};
return pub;
})(jQuery);
......@@ -124,11 +124,20 @@ abstract class Application extends Module
* 'name' => 'extension name',
* 'version' => 'version number',
* 'bootstrap' => 'BootstrapClassName',
* 'alias' => [
* '@alias1' => 'to/path1',
* '@alias2' => 'to/path2',
* ],
* ]
* ~~~
*/
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,
* it means the application is handling some exception and extra care should be taken.
*/
......@@ -205,6 +214,10 @@ abstract class Application extends Module
public function init()
{
$this->initExtensions($this->extensions);
foreach ($this->bootstrap as $class) {
/** @var Extension $class */
$class::bootstrap();
}
parent::init();
}
......@@ -224,7 +237,7 @@ abstract class Application extends Module
if (isset($extension['bootstrap'])) {
/** @var Extension $class */
$class = $extension['bootstrap'];
$class::init();
$class::bootstrap();
}
}
}
......
......@@ -11,7 +11,7 @@ namespace yii\base;
* Extension is the base class that may be extended by individual extensions.
*
* 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.
*
* @author Qiang Xue <qiang.xue@gmail.com>
......@@ -21,9 +21,9 @@ class 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 @@
namespace yii\db;
use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\Inflector;
use yii\helpers\StringHelper;
......@@ -376,6 +377,7 @@ class ActiveRecord extends BaseActiveRecord
public function insert($runValidation = true, $attributes = null)
{
if ($runValidation && !$this->validate($attributes)) {
Yii::info('Model not inserted due to validation error.', __METHOD__);
return false;
}
$db = static::getDb();
......@@ -493,6 +495,7 @@ class ActiveRecord extends BaseActiveRecord
public function update($runValidation = true, $attributes = null)
{
if ($runValidation && !$this->validate($attributes)) {
Yii::info('Model not updated due to validation error.', __METHOD__);
return false;
}
$db = static::getDb();
......
......@@ -219,7 +219,7 @@ class GridView extends BaseListView
*/
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'];
$filterSelector = "#$id input, #$id select";
if (isset($this->filterSelector)) {
......
......@@ -10,6 +10,7 @@ namespace yii\log;
use Yii;
use yii\base\Component;
use yii\base\InvalidConfigException;
use yii\web\Request;
/**
* Target is the base class for all log target classes.
......@@ -52,17 +53,18 @@ abstract class Target extends Component
*/
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.
* Note that a variable must be accessible via `$GLOBALS`. Otherwise it won't be logged.
* Defaults to `['_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.
* 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.
......@@ -111,11 +113,6 @@ abstract class Target extends Component
protected function getContextMessage()
{
$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) {
if (!empty($GLOBALS[$name])) {
$context[] = "\${$name} = " . var_export($GLOBALS[$name], true);
......@@ -233,8 +230,28 @@ abstract class Target extends Component
if (!is_string($text)) {
$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 [
'messagePath' => __DIR__,
// array, required, list of language codes that the extracted messages
// 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.
// 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
......
<?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 (
'{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 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 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.',
......
......@@ -65,7 +65,7 @@ class YiiRequirementChecker
* If a string, it is treated as the path of the file, which contains the requirements;
* @return static self instance.
*/
public function check($requirements)
function check($requirements)
{
if (is_string($requirements)) {
$requirements = require($requirements);
......@@ -110,7 +110,7 @@ class YiiRequirementChecker
* Performs the check for the Yii core requirements.
* @return YiiRequirementChecker self instance.
*/
public function checkYii()
function checkYii()
{
return $this->check(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'requirements.php');
}
......@@ -137,7 +137,7 @@ class YiiRequirementChecker
* )
* ```
*/
public function getResult()
function getResult()
{
if (isset($this->result)) {
return $this->result;
......@@ -150,7 +150,7 @@ class YiiRequirementChecker
* Renders the requirements check result.
* The output will vary depending is a script running from web or from console.
*/
public function render()
function render()
{
if (!isset($this->result)) {
$this->usageError('Nothing to render!');
......@@ -171,7 +171,7 @@ class YiiRequirementChecker
* @param string $compare comparison operator, by default '>='
* @return boolean if PHP extension version matches.
*/
public function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
function checkPhpExtensionVersion($extensionName, $version, $compare = '>=')
{
if (!extension_loaded($extensionName)) {
return false;
......@@ -192,7 +192,7 @@ class YiiRequirementChecker
* @param string $name configuration option name.
* @return boolean option is on.
*/
public function checkPhpIniOn($name)
function checkPhpIniOn($name)
{
$value = ini_get($name);
if (empty($value)) {
......@@ -207,7 +207,7 @@ class YiiRequirementChecker
* @param string $name configuration option name.
* @return boolean option is off.
*/
public function checkPhpIniOff($name)
function checkPhpIniOff($name)
{
$value = ini_get($name);
if (empty($value)) {
......@@ -225,7 +225,7 @@ class YiiRequirementChecker
* @param string $compare comparison operator, by default '>='.
* @return boolean comparison result.
*/
public function compareByteSize($a, $b, $compare = '>=')
function compareByteSize($a, $b, $compare = '>=')
{
$compareExpression = '(' . $this->getByteSize($a) . $compare . $this->getByteSize($b) . ')';
......@@ -238,7 +238,7 @@ class YiiRequirementChecker
* @param string $verboseSize verbose size representation.
* @return integer actual size in bytes.
*/
public function getByteSize($verboseSize)
function getByteSize($verboseSize)
{
if (empty($verboseSize)) {
return 0;
......@@ -277,7 +277,7 @@ class YiiRequirementChecker
* @param string|null $max verbose file size maximum required value, pass null to skip maximum check.
* @return boolean success.
*/
public function checkUploadMaxFileSize($min = null, $max = null)
function checkUploadMaxFileSize($min = null, $max = null)
{
$postMaxSize = ini_get('post_max_size');
$uploadMaxFileSize = ini_get('upload_max_filesize');
......@@ -305,7 +305,7 @@ class YiiRequirementChecker
* @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.
*/
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
if (is_array($_data_)) {
......@@ -330,7 +330,7 @@ class YiiRequirementChecker
* @param integer $requirementKey requirement key in the list.
* @return array normalized requirement.
*/
public function normalizeRequirement($requirement, $requirementKey = 0)
function normalizeRequirement($requirement, $requirementKey = 0)
{
if (!is_array($requirement)) {
$this->usageError('Requirement must be an array!');
......@@ -369,7 +369,7 @@ class YiiRequirementChecker
* This method will then terminate the execution of the current application.
* @param string $message the error message
*/
public function usageError($message)
function usageError($message)
{
echo "Error: $message\n\n";
exit(1);
......@@ -380,7 +380,7 @@ class YiiRequirementChecker
* @param string $expression a PHP expression to be evaluated.
* @return mixed the expression result.
*/
public function evaluateExpression($expression)
function evaluateExpression($expression)
{
return eval('return ' . $expression . ';');
}
......@@ -389,7 +389,7 @@ class YiiRequirementChecker
* Returns the server information.
* @return string server information.
*/
public function getServerInfo()
function getServerInfo()
{
$info = isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : '';
......@@ -400,7 +400,7 @@ class YiiRequirementChecker
* Returns the now date if possible in string representation.
* @return string now date.
*/
public function getNowDate()
function getNowDate()
{
$nowDate = @strftime('%Y-%m-%d %H:%M', time());
......
......@@ -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}}.');
}
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)) {
$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 @@
echo "<?php\n";
?>
use yii\db\Schema;
class <?= $className ?> extends \yii\db\Migration
{
public function up()
......
......@@ -265,6 +265,7 @@ class User extends Component
* This will remove authentication-related session data.
* If `$destroySession` is true, all session data will be removed.
* @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)
{
......@@ -279,24 +280,31 @@ class User extends Component
}
$this->afterLogout($identity);
}
return $this->getIsGuest();
}
/**
* 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.
*/
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.
* @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.
*/
public function getId()
public function getId($checkSession = true)
{
$identity = $this->getIdentity();
$identity = $this->getIdentity($checkSession);
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