From fedc38fdb61554f161aaf46ed41f718f7e72f4b7 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 1 Nov 2013 13:08:01 -0400 Subject: [PATCH 01/18] Fixes #1116. --- framework/yii/gii/assets/gii.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/yii/gii/assets/gii.js b/framework/yii/gii/assets/gii.js index b581d3b..a95221e 100644 --- a/framework/yii/gii/assets/gii.js +++ b/framework/yii/gii/assets/gii.js @@ -14,7 +14,7 @@ yii.gii = (function ($) { }; var initStickyInputs = function () { - $('.sticky:not(.error) input[type="text"],select,textarea').each(function () { + $('.sticky:not(.error)').find('input[type="text"],select,textarea').each(function () { var value; if (this.tagName === 'SELECT') { value = this.options[this.selectedIndex].text; From 4b42d78f4ef38666137dd883c1f18fa44c264c32 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 1 Nov 2013 21:43:33 -0400 Subject: [PATCH 02/18] Fixes #1117: added support to map a single view directory to multiple themed view directories. --- framework/yii/base/Theme.php | 51 +++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/framework/yii/base/Theme.php b/framework/yii/base/Theme.php index ff6780c..b864412 100644 --- a/framework/yii/base/Theme.php +++ b/framework/yii/base/Theme.php @@ -13,17 +13,38 @@ use yii\helpers\FileHelper; /** * Theme represents an application theme. * - * A theme is directory consisting of view and layout files which are meant to replace their - * non-themed counterparts. + * When [[View]] renders a view file, it will check the [[Application::theme|active theme]] + * to see if there is a themed version of the view file exists. If so, the themed version will be rendered instead. * - * Theme uses [[pathMap]] to achieve the file replacement. A view or layout file will be replaced - * with its themed version if part of its path matches one of the keys in [[pathMap]]. - * Then the matched part will be replaced with the corresponding array value. + * A theme is directory consisting of view files which are meant to replace their non-themed counterparts. + * + * Theme uses [[pathMap]] to achieve the view file replacement: + * + * 1. It first looks for a key in [[pathMap]] that is a substring of the given view file path; + * 2. If such a key exists, the corresponding value will be used to replace the corresponding part + * in the view file path; + * 3. It will then check if the updated view file exists or not. If so, that file will be used + * to replace the original view file. + * 4. If Step 2 or 3 fails, the original view file will be used. * * For example, if [[pathMap]] is `['/web/views' => '/web/themes/basic']`, * then the themed version for a view file `/web/views/site/index.php` will be * `/web/themes/basic/site/index.php`. * + * It is possible to map a single path to multiple paths. For example, + * + * ~~~ + * 'pathMap' => [ + * '/web/views' => [ + * '/web/themes/christmas', + * '/web/themes/basic', + * ], + * ] + * ~~~ + * + * In this case, the themed version could be either `/web/themes/christmas/site/index.php` or + * `/web/themes/basic/site/index.php`. The former has precedence over the latter if both files exist. + * * To use a theme, you should configure the [[View::theme|theme]] property of the "view" application * component like the following: * @@ -75,16 +96,18 @@ class Theme extends Component if (empty($this->pathMap)) { if ($this->basePath !== null) { $this->basePath = Yii::getAlias($this->basePath); - $this->pathMap = [Yii::$app->getBasePath() => $this->basePath]; + $this->pathMap = [Yii::$app->getBasePath() => [$this->basePath]]; } else { throw new InvalidConfigException('The "basePath" property must be set.'); } } $paths = []; - foreach ($this->pathMap as $from => $to) { + foreach ($this->pathMap as $from => $tos) { $from = FileHelper::normalizePath(Yii::getAlias($from)); - $to = FileHelper::normalizePath(Yii::getAlias($to)); - $paths[$from . DIRECTORY_SEPARATOR] = $to . DIRECTORY_SEPARATOR; + foreach ((array)$tos as $to) { + $to = FileHelper::normalizePath(Yii::getAlias($to)); + $paths[$from . DIRECTORY_SEPARATOR][] = $to . DIRECTORY_SEPARATOR; + } } $this->pathMap = $paths; if ($this->baseUrl === null) { @@ -103,12 +126,14 @@ class Theme extends Component public function applyTo($path) { $path = FileHelper::normalizePath($path); - foreach ($this->pathMap as $from => $to) { + foreach ($this->pathMap as $from => $tos) { if (strpos($path, $from) === 0) { $n = strlen($from); - $file = $to . substr($path, $n); - if (is_file($file)) { - return $file; + foreach ($tos as $to) { + $file = $to . substr($path, $n); + if (is_file($file)) { + return $file; + } } } } From 64641cbd766366941c3da0b059efc42859d09fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD=20=D0=91=D0=B0=D0=B3=D0=B0=D0=B5?= =?UTF-8?q?=D0=B2?= Date: Sat, 2 Nov 2013 10:42:14 +0500 Subject: [PATCH 03/18] Add batchInsert method to yii\db\Migration --- framework/yii/db/Migration.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/framework/yii/db/Migration.php b/framework/yii/db/Migration.php index 307b02a..37fdf3f 100644 --- a/framework/yii/db/Migration.php +++ b/framework/yii/db/Migration.php @@ -158,6 +158,21 @@ class Migration extends \yii\base\Component } /** + * Creates and executes an batch INSERT SQL statement. + * The method will properly escape the column names, and bind the values to be inserted. + * @param string $table the table that new rows will be inserted into. + * @param array $columns the column names. + * @param array $rows the rows to be batch inserted into the table + */ + public function batchInsert($table, $columns, $rows) + { + echo " > insert into $table ..."; + $time = microtime(true); + $this->db->createCommand()->batchInsert($table, $columns, $rows)->execute(); + echo " done (time: " . sprintf('%.3f', microtime(true) - $time) . "s)\n"; + } + + /** * Creates and executes an UPDATE SQL statement. * The method will properly escape the column names and bind the values to be updated. * @param string $table the table to be updated. From cc5fe76c9ee421fe75d4e7bd8976ab109deee4a1 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sat, 2 Nov 2013 16:31:30 +0400 Subject: [PATCH 04/18] Added ability to get all GET, POST, PUT, DELETE or PATCH parameters to Request --- framework/yii/web/Request.php | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/framework/yii/web/Request.php b/framework/yii/web/Request.php index 610e907..a6a92fa 100644 --- a/framework/yii/web/Request.php +++ b/framework/yii/web/Request.php @@ -290,59 +290,74 @@ class Request extends \yii\base\Request /** * Returns the named GET parameter value. * If the GET parameter does not exist, the second parameter to this method will be returned. - * @param string $name the GET parameter name + * @param string $name the GET parameter name. If not specified, whole $_GET is returned. * @param mixed $defaultValue the default parameter value if the GET parameter does not exist. * @return mixed the GET parameter value * @see getPost */ - public function get($name, $defaultValue = null) + public function get($name = null, $defaultValue = null) { + if ($name === null) { + return $_GET; + } return isset($_GET[$name]) ? $_GET[$name] : $defaultValue; } /** * Returns the named POST parameter value. * If the POST parameter does not exist, the second parameter to this method will be returned. - * @param string $name the POST parameter name + * @param string $name the POST parameter name. If not specified, whole $_POST is returned. * @param mixed $defaultValue the default parameter value if the POST parameter does not exist. * @return mixed the POST parameter value * @see getParam */ - public function getPost($name, $defaultValue = null) + public function getPost($name = null, $defaultValue = null) { + if ($name === null) { + return $_POST; + } return isset($_POST[$name]) ? $_POST[$name] : $defaultValue; } /** * Returns the named DELETE parameter value. - * @param string $name the DELETE parameter name + * @param string $name the DELETE parameter name. If not specified, an array of DELETE parameters is returned. * @param mixed $defaultValue the default parameter value if the DELETE parameter does not exist. * @return mixed the DELETE parameter value */ - public function getDelete($name, $defaultValue = null) + public function getDelete($name = null, $defaultValue = null) { + if ($name === null) { + return $this->getRestParams(); + } return $this->getIsDelete() ? $this->getRestParam($name, $defaultValue) : null; } /** * Returns the named PUT parameter value. - * @param string $name the PUT parameter name + * @param string $name the PUT parameter name. If not specified, an array of PUT parameters is returned. * @param mixed $defaultValue the default parameter value if the PUT parameter does not exist. * @return mixed the PUT parameter value */ - public function getPut($name, $defaultValue = null) + public function getPut($name = null, $defaultValue = null) { + if ($name === null) { + return $this->getRestParams(); + } return $this->getIsPut() ? $this->getRestParam($name, $defaultValue) : null; } /** * Returns the named PATCH parameter value. - * @param string $name the PATCH parameter name + * @param string $name the PATCH parameter name. If not specified, an array of PATCH parameters is returned. * @param mixed $defaultValue the default parameter value if the PATCH parameter does not exist. * @return mixed the PATCH parameter value */ - public function getPatch($name, $defaultValue = null) + public function getPatch($name = null, $defaultValue = null) { + if ($name === null) { + return $this->getRestParams(); + } return $this->getIsPatch() ? $this->getRestParam($name, $defaultValue) : null; } From 62148a2e33ea372198fb3b5b8e2604d25a2487fc Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Sat, 2 Nov 2013 16:39:24 +0400 Subject: [PATCH 05/18] Changed php-diff dependency to use code from master (they haven't tagged changes we need yet) --- framework/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/composer.json b/framework/composer.json index 419b4b7..05c4360 100644 --- a/framework/composer.json +++ b/framework/composer.json @@ -68,7 +68,7 @@ "yiisoft/yii2-composer": "*", "ext-mbstring": "*", "lib-pcre": "*", - "phpspec/php-diff": "1.0.*", + "phpspec/php-diff": "dev-master", "ezyang/htmlpurifier": "4.5.*" }, "autoload": { From 18fbd7510a1f5c01ece1079f7346dc957812888e Mon Sep 17 00:00:00 2001 From: Alexander Mohorev Date: Sat, 2 Nov 2013 16:12:28 +0300 Subject: [PATCH 06/18] Missing return statement --- framework/yii/db/ActiveRecord.php | 2 ++ framework/yii/db/mssql/Schema.php | 2 ++ framework/yii/i18n/GettextMoFile.php | 2 ++ 3 files changed, 6 insertions(+) diff --git a/framework/yii/db/ActiveRecord.php b/framework/yii/db/ActiveRecord.php index 79d5146..2c1689c 100644 --- a/framework/yii/db/ActiveRecord.php +++ b/framework/yii/db/ActiveRecord.php @@ -1266,6 +1266,8 @@ class ActiveRecord extends Model $relation = $this->$getter(); if ($relation instanceof ActiveRelation) { return $relation; + } else { + return null; } } catch (UnknownMethodException $e) { throw new InvalidParamException(get_class($this) . ' has no relation named "' . $name . '".', 0, $e); diff --git a/framework/yii/db/mssql/Schema.php b/framework/yii/db/mssql/Schema.php index 0bb5924..deb92f9 100644 --- a/framework/yii/db/mssql/Schema.php +++ b/framework/yii/db/mssql/Schema.php @@ -118,6 +118,8 @@ class Schema extends \yii\db\Schema if ($this->findColumns($table)) { $this->findForeignKeys($table); return $table; + } else { + return null; } } diff --git a/framework/yii/i18n/GettextMoFile.php b/framework/yii/i18n/GettextMoFile.php index a92293c..4a0a93c 100644 --- a/framework/yii/i18n/GettextMoFile.php +++ b/framework/yii/i18n/GettextMoFile.php @@ -203,6 +203,8 @@ class GettextMoFile extends GettextFile { if ($byteCount > 0) { return fread($fileHandle, $byteCount); + } else { + return null; } } From 5860599ef7fc6788203348579c5cb8ca133a7760 Mon Sep 17 00:00:00 2001 From: Alexander Mohorev Date: Sat, 2 Nov 2013 17:03:37 +0300 Subject: [PATCH 07/18] PhpDoc comment --- framework/yii/db/sqlite/QueryBuilder.php | 1 + framework/yii/i18n/GettextMoFile.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/framework/yii/db/sqlite/QueryBuilder.php b/framework/yii/db/sqlite/QueryBuilder.php index 2a6f345..4a5407f 100644 --- a/framework/yii/db/sqlite/QueryBuilder.php +++ b/framework/yii/db/sqlite/QueryBuilder.php @@ -80,6 +80,7 @@ class QueryBuilder extends \yii\db\QueryBuilder * @param boolean $check whether to turn on or off the integrity check. * @param string $schema the schema of the tables. Meaningless for SQLite. * @param string $table the table name. Meaningless for SQLite. + * @return string the SQL statement for checking integrity * @throws NotSupportedException this is not supported by SQLite */ public function checkIntegrity($check = true, $schema = '', $table = '') diff --git a/framework/yii/i18n/GettextMoFile.php b/framework/yii/i18n/GettextMoFile.php index 4a0a93c..b4a016d 100644 --- a/framework/yii/i18n/GettextMoFile.php +++ b/framework/yii/i18n/GettextMoFile.php @@ -54,6 +54,7 @@ class GettextMoFile extends GettextFile * @param string $context message context * @return array message translations. Array keys are source messages and array values are translated messages: * source message => translated message. + * @throws Exception if unable to read the MO file */ public function load($filePath, $context) { @@ -128,6 +129,7 @@ class GettextMoFile extends GettextFile * @param array $messages message translations. Array keys are source messages and array values are * translated messages: source message => translated message. Note if the message has a context, * the message ID must be prefixed with the context with chr(4) as the separator. + * @throws Exception if unable to save the MO file */ public function save($filePath, $messages) { From eee63f172114970a9fd59801ff8b8d074e9f47e2 Mon Sep 17 00:00:00 2001 From: Alexander Mohorev Date: Sat, 2 Nov 2013 17:53:48 +0300 Subject: [PATCH 08/18] Small typos --- docs/api/db/ActiveRecord.md | 2 +- docs/guide/authorization.md | 2 +- docs/guide/i18n.md | 2 +- docs/guide/query-builder.md | 2 +- docs/guide/validation.md | 2 +- docs/guide/view.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/api/db/ActiveRecord.md b/docs/api/db/ActiveRecord.md index 70f171b..ef050d0 100644 --- a/docs/api/db/ActiveRecord.md +++ b/docs/api/db/ActiveRecord.md @@ -1,6 +1,6 @@ ActiveRecord implements the [Active Record design pattern](http://en.wikipedia.org/wiki/Active_record). The idea is that an ActiveRecord object is associated with a row in a database table -so object properties are mapped to colums of the corresponding database row. +so object properties are mapped to columns of the corresponding database row. For example, a `Customer` object is associated with a row in the `tbl_customer` table. Instead of writing raw SQL statements to access the data in the table, you can call intuitive methods available in the corresponding ActiveRecord class diff --git a/docs/guide/authorization.md b/docs/guide/authorization.md index 47b9409..b49f1af 100644 --- a/docs/guide/authorization.md +++ b/docs/guide/authorization.md @@ -7,7 +7,7 @@ of controlling it. Access control basics --------------------- -Basic acces control is very simple to implement using [[\yii\web\AccessControl]]: +Basic access control is very simple to implement using [[\yii\web\AccessControl]]: ```php class SiteController extends Controller diff --git a/docs/guide/i18n.md b/docs/guide/i18n.md index 33f7758..6524801 100644 --- a/docs/guide/i18n.md +++ b/docs/guide/i18n.md @@ -121,7 +121,7 @@ extension. After installing and enabling it you will be able to use extended syn that allows you to specify formatting style. Full reference is [available at ICU website](http://icu-project.org/apiref/icu4c/classMessageFormat.html) but since it's -a bit crypric we have our own reference below. +a bit cryptic we have our own reference below. ### Numbers diff --git a/docs/guide/query-builder.md b/docs/guide/query-builder.md index ffc9871..7625c0b 100644 --- a/docs/guide/query-builder.md +++ b/docs/guide/query-builder.md @@ -45,7 +45,7 @@ $query->select(['tbl_user.name AS author', 'tbl_post.title as title']) // <-- sp ->leftJoin('tbl_post', 'tbl_post.user_id = tbl_user.id'); // <-- join with another table ``` -In the code above we've used `leftJoin` method to select from two related tables at the same time. Firsrt parameter +In the code above we've used `leftJoin` method to select from two related tables at the same time. First parameter specifies table name and the second is the join condition. Query builder has the following methods to join tables: - `innerJoin` diff --git a/docs/guide/validation.md b/docs/guide/validation.md index c8c8674..59242f5 100644 --- a/docs/guide/validation.md +++ b/docs/guide/validation.md @@ -8,7 +8,7 @@ Standard Yii validators ----------------------- Standard Yii validators could be specified using aliases instead of referring to class names. Here's the list of all -validators budled with Yii with their most useful properties: +validators bundled with Yii with their most useful properties: ### `boolean`: [[BooleanValidator]] diff --git a/docs/guide/view.md b/docs/guide/view.md index ee469e6..1069e89 100644 --- a/docs/guide/view.md +++ b/docs/guide/view.md @@ -38,7 +38,7 @@ Widgets Widgets are a self-contained building blocks for your views. A widget may contain advanced logic, typically takes some configuration and data and returns HTML. There is a good number of widgets bundled with Yii such as [active form](form.md), -breadcrumbs, menu or [wrappers around bootstrap component framework](boostrap-widgets.md). Additionally there are +breadcrumbs, menu or [wrappers around bootstrap component framework](bootstrap-widgets.md). Additionally there are extensions providing additional widgets such as official one for jQueryUI components. In order to use widget you need to do the following: From 5d17dd06d12a2702a6faeb0e8710c4c88b88a4de Mon Sep 17 00:00:00 2001 From: Alexander Mohorev Date: Sat, 2 Nov 2013 17:57:37 +0300 Subject: [PATCH 09/18] Specify the exact type of the exception. --- framework/yii/base/Module.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/yii/base/Module.php b/framework/yii/base/Module.php index 4bc5351..b3e28f6 100644 --- a/framework/yii/base/Module.php +++ b/framework/yii/base/Module.php @@ -241,7 +241,7 @@ abstract class Module extends Component * Sets the directory that contains the controller classes. * @param string $path the directory that contains the controller classes. * This can be either a directory name or a path alias. - * @throws Exception if the directory is invalid + * @throws InvalidParamException if the directory is invalid */ public function setControllerPath($path) { @@ -264,7 +264,7 @@ abstract class Module extends Component /** * Sets the directory that contains the view files. * @param string $path the root directory of view files. - * @throws Exception if the directory is invalid + * @throws InvalidParamException if the directory is invalid */ public function setViewPath($path) { @@ -287,7 +287,7 @@ abstract class Module extends Component /** * Sets the directory that contains the layout files. * @param string $path the root directory of layout files. - * @throws Exception if the directory is invalid + * @throws InvalidParamException if the directory is invalid */ public function setLayoutPath($path) { From 1d092d17555fe76d2656dd5557bfc7bd828d0f35 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 2 Nov 2013 13:06:04 -0400 Subject: [PATCH 10/18] Changed the exit status to normal. --- apps/advanced/init | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/advanced/init b/apps/advanced/init index c8f7f73..4015748 100755 --- a/apps/advanced/init +++ b/apps/advanced/init @@ -18,7 +18,7 @@ if (empty($params['env'])) { if (!ctype_digit($answer) || !in_array($answer, range(0, count($envs) - 1))) { echo "\n Quit initialization.\n"; - exit(1); + exit(0); } if (isset($envNames[$answer])) { @@ -42,7 +42,7 @@ if (empty($params['env'])) { $answer = trim(fgets(STDIN)); if (strncasecmp($answer, 'y', 1)) { echo "\n Quit initialization.\n"; - exit(1); + exit(0); } } From 13c3123ca8fbfe832c46ae3bf449f2b0eedc1cad Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 2 Nov 2013 14:16:38 -0400 Subject: [PATCH 11/18] moved mutex back from extensions. --- extensions/mutex/LICENSE.md | 32 --------- extensions/mutex/README.md | 42 ------------ extensions/mutex/composer.json | 27 -------- extensions/mutex/yii/mutex/DbMutex.php | 41 ------------ extensions/mutex/yii/mutex/FileMutex.php | 104 ------------------------------ extensions/mutex/yii/mutex/Mutex.php | 95 --------------------------- extensions/mutex/yii/mutex/MysqlMutex.php | 57 ---------------- framework/yii/mutex/DbMutex.php | 41 ++++++++++++ framework/yii/mutex/FileMutex.php | 104 ++++++++++++++++++++++++++++++ framework/yii/mutex/Mutex.php | 95 +++++++++++++++++++++++++++ framework/yii/mutex/MysqlMutex.php | 57 ++++++++++++++++ 11 files changed, 297 insertions(+), 398 deletions(-) delete mode 100644 extensions/mutex/LICENSE.md delete mode 100644 extensions/mutex/README.md delete mode 100644 extensions/mutex/composer.json delete mode 100644 extensions/mutex/yii/mutex/DbMutex.php delete mode 100644 extensions/mutex/yii/mutex/FileMutex.php delete mode 100644 extensions/mutex/yii/mutex/Mutex.php delete mode 100644 extensions/mutex/yii/mutex/MysqlMutex.php create mode 100644 framework/yii/mutex/DbMutex.php create mode 100644 framework/yii/mutex/FileMutex.php create mode 100644 framework/yii/mutex/Mutex.php create mode 100644 framework/yii/mutex/MysqlMutex.php diff --git a/extensions/mutex/LICENSE.md b/extensions/mutex/LICENSE.md deleted file mode 100644 index 0bb1a8d..0000000 --- a/extensions/mutex/LICENSE.md +++ /dev/null @@ -1,32 +0,0 @@ -The Yii framework is free software. It is released under the terms of -the following BSD License. - -Copyright © 2008-2013 by Yii Software LLC (http://www.yiisoft.com) -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Yii Software LLC nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/extensions/mutex/README.md b/extensions/mutex/README.md deleted file mode 100644 index 161ee8a..0000000 --- a/extensions/mutex/README.md +++ /dev/null @@ -1,42 +0,0 @@ -Yii 2.0 Public Preview - Mutex Extension -======================================== - -Thank you for choosing Yii - a high-performance component-based PHP framework. - -If you are looking for a production-ready PHP framework, please use -[Yii v1.1](https://github.com/yiisoft/yii). - -Yii 2.0 is still under heavy development. We may make significant changes -without prior notices. **Yii 2.0 is not ready for production use yet.** - -[![Build Status](https://secure.travis-ci.org/yiisoft/yii2.png)](http://travis-ci.org/yiisoft/yii2) - -This is the yii2-mutex extension. - - -Installation ------------- - -The prefered way to install this extension is through [composer](http://getcomposer.org/download/). - -Either run -``` -php composer.phar require yiisoft/yii2-mutex "*" -``` - -or add -``` -"yiisoft/yii2-mutex": "*" -``` -to the require section of your composer.json. - - -*Note: You might have to run `php composer.phar selfupdate`* - - -Usage & Documentation ---------------------- - -This component can be used to perform actions similar to the concept of [mutual exclusion](http://en.wikipedia.org/wiki/Mutual_exclusion). - -For concrete examples and advanced usage refer to the yii guide. diff --git a/extensions/mutex/composer.json b/extensions/mutex/composer.json deleted file mode 100644 index e0079ef..0000000 --- a/extensions/mutex/composer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "yiisoft/yii2-mutex", - "description": "Mutual exclusion extension for the Yii framework", - "keywords": ["yii", "mutex"], - "type": "yii2-extension", - "license": "BSD-3-Clause", - "support": { - "issues": "https://github.com/yiisoft/yii2/issues?state=open", - "forum": "http://www.yiiframework.com/forum/", - "wiki": "http://www.yiiframework.com/wiki/", - "irc": "irc://irc.freenode.net/yii", - "source": "https://github.com/yiisoft/yii2" - }, - "authors": [ - { - "name": "resurtm", - "email": "resurtm@gmail.com" - } - ], - "minimum-stability": "dev", - "require": { - "yiisoft/yii2": "*" - }, - "autoload": { - "psr-0": { "yii\\mutex\\": "" } - } -} diff --git a/extensions/mutex/yii/mutex/DbMutex.php b/extensions/mutex/yii/mutex/DbMutex.php deleted file mode 100644 index 3699c36..0000000 --- a/extensions/mutex/yii/mutex/DbMutex.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @since 2.0 - */ -abstract class DbMutex extends Mutex -{ - /** - * @var Connection|string the DB connection object or the application component ID of the DB connection. - * After the Mutex object is created, if you want to change this property, you should only assign - * it with a DB connection object. - */ - public $db = 'db'; - - /** - * Initializes generic database table based mutex implementation. - * @throws InvalidConfigException if [[db]] is invalid. - */ - public function init() - { - parent::init(); - if (is_string($this->db)) { - $this->db = Yii::$app->getComponent($this->db); - } - if (!$this->db instanceof Connection) { - throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); - } - } -} diff --git a/extensions/mutex/yii/mutex/FileMutex.php b/extensions/mutex/yii/mutex/FileMutex.php deleted file mode 100644 index fd5cb00..0000000 --- a/extensions/mutex/yii/mutex/FileMutex.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @since 2.0 - */ -class FileMutex extends Mutex -{ - /** - * @var string the directory to store mutex files. You may use path alias here. - * Defaults to the "mutex" subdirectory under the application runtime path. - */ - public $mutexPath = '@runtime/mutex'; - /** - * @var integer the permission to be set for newly created mutex files. - * This value will be used by PHP chmod() function. No umask will be applied. - * If not set, the permission will be determined by the current environment. - */ - public $fileMode; - /** - * @var integer the permission to be set for newly created directories. - * This value will be used by PHP chmod() function. No umask will be applied. - * Defaults to 0775, meaning the directory is read-writable by owner and group, - * but read-only for other users. - */ - public $dirMode = 0775; - /** - * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. - */ - private $_files = []; - - - /** - * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like - * operating systems. - * @throws InvalidConfigException - */ - public function init() - { - if (stripos(php_uname('s'), 'win') === 0) { - throw new InvalidConfigException('FileMutex does not have MS Windows operating system support.'); - } - $this->mutexPath = Yii::getAlias($this->mutexPath); - if (!is_dir($this->mutexPath)) { - FileHelper::createDirectory($this->mutexPath, $this->dirMode, true); - } - } - - /** - * Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - protected function acquireLock($name, $timeout = 0) - { - $fileName = $this->mutexPath . '/' . md5($name) . '.lock'; - $file = fopen($fileName, 'w+'); - if ($file === false) { - return false; - } - if ($this->fileMode !== null) { - @chmod($fileName, $this->fileMode); - } - $waitTime = 0; - while (!flock($file, LOCK_EX | LOCK_NB)) { - $waitTime++; - if ($waitTime > $timeout) { - fclose($file); - return false; - } - sleep(1); - } - $this->_files[$name] = $file; - return true; - } - - /** - * Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - protected function releaseLock($name) - { - if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { - return false; - } else { - fclose($this->_files[$name]); - unset($this->_files[$name]); - return true; - } - } -} diff --git a/extensions/mutex/yii/mutex/Mutex.php b/extensions/mutex/yii/mutex/Mutex.php deleted file mode 100644 index 611e725..0000000 --- a/extensions/mutex/yii/mutex/Mutex.php +++ /dev/null @@ -1,95 +0,0 @@ - - * @since 2.0 - */ -abstract class Mutex extends Component -{ - /** - * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically - * before finishing script execution. Defaults to true. Setting this property to true means that all locks - * acquire in this process must be released in any case (regardless any kind of errors or exceptions). - */ - public $autoRelease = true; - /** - * @var string[] names of the locks acquired in the current PHP process. - */ - private $_locks = []; - - - /** - * Initializes the mutex component. - */ - public function init() - { - if ($this->autoRelease) { - $locks = &$this->_locks; - register_shutdown_function(function () use (&$locks) { - foreach ($locks as $lock) { - $this->release($lock); - } - }); - } - } - - /** - * Acquires lock by given name. - * @param string $name of the lock to be acquired. Must be unique. - * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return - * false immediately in case lock was already acquired. - * @return boolean lock acquiring result. - */ - public function acquire($name, $timeout = 0) - { - if ($this->acquireLock($name, $timeout)) { - $this->_locks[] = $name; - return true; - } else { - return false; - } - } - - /** - * Release acquired lock. This method will return false in case named lock was not found. - * @param string $name of the lock to be released. This lock must be already created. - * @return boolean lock release result: false in case named lock was not found.. - */ - public function release($name) - { - if ($this->releaseLock($name)) { - $index = array_search($name, $this->_locks); - if ($index !== false) { - unset($this->_locks[$index]); - } - return true; - } else { - return false; - } - } - - /** - * This method should be extended by concrete mutex implementations. Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - */ - abstract protected function acquireLock($name, $timeout = 0); - - /** - * This method should be extended by concrete mutex implementations. Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - */ - abstract protected function releaseLock($name); -} diff --git a/extensions/mutex/yii/mutex/MysqlMutex.php b/extensions/mutex/yii/mutex/MysqlMutex.php deleted file mode 100644 index af05b9c..0000000 --- a/extensions/mutex/yii/mutex/MysqlMutex.php +++ /dev/null @@ -1,57 +0,0 @@ - - * @since 2.0 - */ -class MysqlMutex extends Mutex -{ - /** - * Initializes MySQL specific mutex component implementation. - * @throws InvalidConfigException if [[db]] is not MySQL connection. - */ - public function init() - { - parent::init(); - if ($this->db->driverName !== 'mysql') { - throw new InvalidConfigException('In order to use MysqlMutex connection must be configured to use MySQL database.'); - } - } - - /** - * Acquires lock by given name. - * @param string $name of the lock to be acquired. - * @param integer $timeout to wait for lock to become released. - * @return boolean acquiring result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock - */ - protected function acquireLock($name, $timeout = 0) - { - return (boolean)$this->db - ->createCommand('SELECT GET_LOCK(:name, :timeout)', [':name' => $name, ':timeout' => $timeout]) - ->queryScalar(); - } - - /** - * Releases lock by given name. - * @param string $name of the lock to be released. - * @return boolean release result. - * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock - */ - protected function releaseLock($name) - { - return (boolean)$this->db - ->createCommand('SELECT RELEASE_LOCK(:name)', [':name' => $name]) - ->queryScalar(); - } -} diff --git a/framework/yii/mutex/DbMutex.php b/framework/yii/mutex/DbMutex.php new file mode 100644 index 0000000..3699c36 --- /dev/null +++ b/framework/yii/mutex/DbMutex.php @@ -0,0 +1,41 @@ + + * @since 2.0 + */ +abstract class DbMutex extends Mutex +{ + /** + * @var Connection|string the DB connection object or the application component ID of the DB connection. + * After the Mutex object is created, if you want to change this property, you should only assign + * it with a DB connection object. + */ + public $db = 'db'; + + /** + * Initializes generic database table based mutex implementation. + * @throws InvalidConfigException if [[db]] is invalid. + */ + public function init() + { + parent::init(); + if (is_string($this->db)) { + $this->db = Yii::$app->getComponent($this->db); + } + if (!$this->db instanceof Connection) { + throw new InvalidConfigException('Mutex::db must be either a DB connection instance or the application component ID of a DB connection.'); + } + } +} diff --git a/framework/yii/mutex/FileMutex.php b/framework/yii/mutex/FileMutex.php new file mode 100644 index 0000000..fd5cb00 --- /dev/null +++ b/framework/yii/mutex/FileMutex.php @@ -0,0 +1,104 @@ + + * @since 2.0 + */ +class FileMutex extends Mutex +{ + /** + * @var string the directory to store mutex files. You may use path alias here. + * Defaults to the "mutex" subdirectory under the application runtime path. + */ + public $mutexPath = '@runtime/mutex'; + /** + * @var integer the permission to be set for newly created mutex files. + * This value will be used by PHP chmod() function. No umask will be applied. + * If not set, the permission will be determined by the current environment. + */ + public $fileMode; + /** + * @var integer the permission to be set for newly created directories. + * This value will be used by PHP chmod() function. No umask will be applied. + * Defaults to 0775, meaning the directory is read-writable by owner and group, + * but read-only for other users. + */ + public $dirMode = 0775; + /** + * @var resource[] stores all opened lock files. Keys are lock names and values are file handles. + */ + private $_files = []; + + + /** + * Initializes mutex component implementation dedicated for UNIX, GNU/Linux, Mac OS X, and other UNIX-like + * operating systems. + * @throws InvalidConfigException + */ + public function init() + { + if (stripos(php_uname('s'), 'win') === 0) { + throw new InvalidConfigException('FileMutex does not have MS Windows operating system support.'); + } + $this->mutexPath = Yii::getAlias($this->mutexPath); + if (!is_dir($this->mutexPath)) { + FileHelper::createDirectory($this->mutexPath, $this->dirMode, true); + } + } + + /** + * Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ + protected function acquireLock($name, $timeout = 0) + { + $fileName = $this->mutexPath . '/' . md5($name) . '.lock'; + $file = fopen($fileName, 'w+'); + if ($file === false) { + return false; + } + if ($this->fileMode !== null) { + @chmod($fileName, $this->fileMode); + } + $waitTime = 0; + while (!flock($file, LOCK_EX | LOCK_NB)) { + $waitTime++; + if ($waitTime > $timeout) { + fclose($file); + return false; + } + sleep(1); + } + $this->_files[$name] = $file; + return true; + } + + /** + * Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ + protected function releaseLock($name) + { + if (!isset($this->_files[$name]) || !flock($this->_files[$name], LOCK_UN)) { + return false; + } else { + fclose($this->_files[$name]); + unset($this->_files[$name]); + return true; + } + } +} diff --git a/framework/yii/mutex/Mutex.php b/framework/yii/mutex/Mutex.php new file mode 100644 index 0000000..611e725 --- /dev/null +++ b/framework/yii/mutex/Mutex.php @@ -0,0 +1,95 @@ + + * @since 2.0 + */ +abstract class Mutex extends Component +{ + /** + * @var boolean whether all locks acquired in this process (i.e. local locks) must be released automagically + * before finishing script execution. Defaults to true. Setting this property to true means that all locks + * acquire in this process must be released in any case (regardless any kind of errors or exceptions). + */ + public $autoRelease = true; + /** + * @var string[] names of the locks acquired in the current PHP process. + */ + private $_locks = []; + + + /** + * Initializes the mutex component. + */ + public function init() + { + if ($this->autoRelease) { + $locks = &$this->_locks; + register_shutdown_function(function () use (&$locks) { + foreach ($locks as $lock) { + $this->release($lock); + } + }); + } + } + + /** + * Acquires lock by given name. + * @param string $name of the lock to be acquired. Must be unique. + * @param integer $timeout to wait for lock to be released. Defaults to zero meaning that method will return + * false immediately in case lock was already acquired. + * @return boolean lock acquiring result. + */ + public function acquire($name, $timeout = 0) + { + if ($this->acquireLock($name, $timeout)) { + $this->_locks[] = $name; + return true; + } else { + return false; + } + } + + /** + * Release acquired lock. This method will return false in case named lock was not found. + * @param string $name of the lock to be released. This lock must be already created. + * @return boolean lock release result: false in case named lock was not found.. + */ + public function release($name) + { + if ($this->releaseLock($name)) { + $index = array_search($name, $this->_locks); + if ($index !== false) { + unset($this->_locks[$index]); + } + return true; + } else { + return false; + } + } + + /** + * This method should be extended by concrete mutex implementations. Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + */ + abstract protected function acquireLock($name, $timeout = 0); + + /** + * This method should be extended by concrete mutex implementations. Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + */ + abstract protected function releaseLock($name); +} diff --git a/framework/yii/mutex/MysqlMutex.php b/framework/yii/mutex/MysqlMutex.php new file mode 100644 index 0000000..af05b9c --- /dev/null +++ b/framework/yii/mutex/MysqlMutex.php @@ -0,0 +1,57 @@ + + * @since 2.0 + */ +class MysqlMutex extends Mutex +{ + /** + * Initializes MySQL specific mutex component implementation. + * @throws InvalidConfigException if [[db]] is not MySQL connection. + */ + public function init() + { + parent::init(); + if ($this->db->driverName !== 'mysql') { + throw new InvalidConfigException('In order to use MysqlMutex connection must be configured to use MySQL database.'); + } + } + + /** + * Acquires lock by given name. + * @param string $name of the lock to be acquired. + * @param integer $timeout to wait for lock to become released. + * @return boolean acquiring result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock + */ + protected function acquireLock($name, $timeout = 0) + { + return (boolean)$this->db + ->createCommand('SELECT GET_LOCK(:name, :timeout)', [':name' => $name, ':timeout' => $timeout]) + ->queryScalar(); + } + + /** + * Releases lock by given name. + * @param string $name of the lock to be released. + * @return boolean release result. + * @see http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_release-lock + */ + protected function releaseLock($name) + { + return (boolean)$this->db + ->createCommand('SELECT RELEASE_LOCK(:name)', [':name' => $name]) + ->queryScalar(); + } +} From baf6de3c0caa2ee8525e43e3c26d0d8b0be798c4 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Sat, 2 Nov 2013 14:52:24 -0400 Subject: [PATCH 12/18] Adjusted jui directories. --- extensions/jui/Accordion.php | 121 ++ extensions/jui/AccordionAsset.php | 26 + extensions/jui/AutoComplete.php | 66 + extensions/jui/AutoCompleteAsset.php | 25 + extensions/jui/ButtonAsset.php | 24 + extensions/jui/CoreAsset.php | 27 + extensions/jui/DatePicker.php | 110 + extensions/jui/DatePickerAsset.php | 25 + extensions/jui/DatePickerRegionalAsset.php | 24 + extensions/jui/Dialog.php | 52 + extensions/jui/DialogAsset.php | 27 + extensions/jui/Draggable.php | 50 + extensions/jui/DraggableAsset.php | 24 + extensions/jui/Droppable.php | 50 + extensions/jui/DroppableAsset.php | 24 + extensions/jui/EffectAsset.php | 24 + extensions/jui/Extension.php | 27 + extensions/jui/InputWidget.php | 59 + extensions/jui/Menu.php | 78 + extensions/jui/MenuAsset.php | 24 + extensions/jui/ProgressBar.php | 60 + extensions/jui/ProgressBarAsset.php | 24 + extensions/jui/Resizable.php | 52 + extensions/jui/ResizableAsset.php | 24 + extensions/jui/Selectable.php | 116 + extensions/jui/SelectableAsset.php | 24 + extensions/jui/Slider.php | 68 + extensions/jui/SliderAsset.php | 24 + extensions/jui/Sortable.php | 106 + extensions/jui/SortableAsset.php | 24 + extensions/jui/Spinner.php | 62 + extensions/jui/SpinnerAsset.php | 25 + extensions/jui/Tabs.php | 145 ++ extensions/jui/TabsAsset.php | 25 + extensions/jui/ThemeAsset.php | 21 + extensions/jui/TooltipAsset.php | 25 + extensions/jui/Widget.php | 87 + extensions/jui/assets.php | 23 + extensions/jui/assets/UPGRADE.md | 14 + extensions/jui/assets/jquery.ui.accordion.js | 572 +++++ extensions/jui/assets/jquery.ui.autocomplete.js | 610 ++++++ extensions/jui/assets/jquery.ui.button.js | 419 ++++ extensions/jui/assets/jquery.ui.core.js | 320 +++ extensions/jui/assets/jquery.ui.datepicker-i18n.js | 1793 ++++++++++++++++ extensions/jui/assets/jquery.ui.datepicker.js | 2038 ++++++++++++++++++ extensions/jui/assets/jquery.ui.dialog.js | 808 +++++++ extensions/jui/assets/jquery.ui.draggable.js | 958 +++++++++ extensions/jui/assets/jquery.ui.droppable.js | 372 ++++ extensions/jui/assets/jquery.ui.effect-all.js | 2261 ++++++++++++++++++++ extensions/jui/assets/jquery.ui.menu.js | 621 ++++++ extensions/jui/assets/jquery.ui.mouse.js | 169 ++ extensions/jui/assets/jquery.ui.position.js | 497 +++++ extensions/jui/assets/jquery.ui.progressbar.js | 145 ++ extensions/jui/assets/jquery.ui.resizable.js | 968 +++++++++ extensions/jui/assets/jquery.ui.selectable.js | 277 +++ extensions/jui/assets/jquery.ui.slider.js | 672 ++++++ extensions/jui/assets/jquery.ui.sortable.js | 1285 +++++++++++ extensions/jui/assets/jquery.ui.spinner.js | 493 +++++ extensions/jui/assets/jquery.ui.tabs.js | 846 ++++++++ extensions/jui/assets/jquery.ui.tooltip.js | 402 ++++ extensions/jui/assets/jquery.ui.widget.js | 521 +++++ .../jui/assets/theme/images/animated-overlay.gif | Bin 0 -> 1738 bytes .../theme/images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 0 -> 212 bytes .../theme/images/ui-bg_flat_75_ffffff_40x100.png | Bin 0 -> 208 bytes .../theme/images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 0 -> 335 bytes .../theme/images/ui-bg_glass_65_ffffff_1x400.png | Bin 0 -> 207 bytes .../theme/images/ui-bg_glass_75_dadada_1x400.png | Bin 0 -> 262 bytes .../theme/images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 0 -> 262 bytes .../theme/images/ui-bg_glass_95_fef1ec_1x400.png | Bin 0 -> 332 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 0 -> 280 bytes .../theme/images/ui-icons_222222_256x240.png | Bin 0 -> 6922 bytes .../theme/images/ui-icons_2e83ff_256x240.png | Bin 0 -> 4549 bytes .../theme/images/ui-icons_454545_256x240.png | Bin 0 -> 6992 bytes .../theme/images/ui-icons_888888_256x240.png | Bin 0 -> 6999 bytes .../theme/images/ui-icons_cd0a0a_256x240.png | Bin 0 -> 4549 bytes extensions/jui/assets/theme/jquery.ui.css | 1177 ++++++++++ extensions/jui/composer.json | 1 + extensions/jui/yii/jui/Accordion.php | 121 -- extensions/jui/yii/jui/AccordionAsset.php | 26 - extensions/jui/yii/jui/AutoComplete.php | 66 - extensions/jui/yii/jui/AutoCompleteAsset.php | 25 - extensions/jui/yii/jui/ButtonAsset.php | 24 - extensions/jui/yii/jui/CoreAsset.php | 27 - extensions/jui/yii/jui/DatePicker.php | 110 - extensions/jui/yii/jui/DatePickerAsset.php | 25 - extensions/jui/yii/jui/DatePickerRegionalAsset.php | 24 - extensions/jui/yii/jui/Dialog.php | 52 - extensions/jui/yii/jui/DialogAsset.php | 27 - extensions/jui/yii/jui/Draggable.php | 50 - extensions/jui/yii/jui/DraggableAsset.php | 24 - extensions/jui/yii/jui/Droppable.php | 50 - extensions/jui/yii/jui/DroppableAsset.php | 24 - extensions/jui/yii/jui/EffectAsset.php | 24 - extensions/jui/yii/jui/Extension.php | 27 - extensions/jui/yii/jui/InputWidget.php | 59 - extensions/jui/yii/jui/Menu.php | 78 - extensions/jui/yii/jui/MenuAsset.php | 24 - extensions/jui/yii/jui/ProgressBar.php | 60 - extensions/jui/yii/jui/ProgressBarAsset.php | 24 - extensions/jui/yii/jui/Resizable.php | 52 - extensions/jui/yii/jui/ResizableAsset.php | 24 - extensions/jui/yii/jui/Selectable.php | 116 - extensions/jui/yii/jui/SelectableAsset.php | 24 - extensions/jui/yii/jui/Slider.php | 68 - extensions/jui/yii/jui/SliderAsset.php | 24 - extensions/jui/yii/jui/Sortable.php | 106 - extensions/jui/yii/jui/SortableAsset.php | 24 - extensions/jui/yii/jui/Spinner.php | 62 - extensions/jui/yii/jui/SpinnerAsset.php | 25 - extensions/jui/yii/jui/Tabs.php | 145 -- extensions/jui/yii/jui/TabsAsset.php | 25 - extensions/jui/yii/jui/ThemeAsset.php | 21 - extensions/jui/yii/jui/TooltipAsset.php | 25 - extensions/jui/yii/jui/Widget.php | 87 - extensions/jui/yii/jui/assets.php | 23 - extensions/jui/yii/jui/assets/UPGRADE.md | 14 - .../jui/yii/jui/assets/jquery.ui.accordion.js | 572 ----- .../jui/yii/jui/assets/jquery.ui.autocomplete.js | 610 ------ extensions/jui/yii/jui/assets/jquery.ui.button.js | 419 ---- extensions/jui/yii/jui/assets/jquery.ui.core.js | 320 --- .../yii/jui/assets/jquery.ui.datepicker-i18n.js | 1793 ---------------- .../jui/yii/jui/assets/jquery.ui.datepicker.js | 2038 ------------------ extensions/jui/yii/jui/assets/jquery.ui.dialog.js | 808 ------- .../jui/yii/jui/assets/jquery.ui.draggable.js | 958 --------- .../jui/yii/jui/assets/jquery.ui.droppable.js | 372 ---- .../jui/yii/jui/assets/jquery.ui.effect-all.js | 2261 -------------------- extensions/jui/yii/jui/assets/jquery.ui.menu.js | 621 ------ extensions/jui/yii/jui/assets/jquery.ui.mouse.js | 169 -- .../jui/yii/jui/assets/jquery.ui.position.js | 497 ----- .../jui/yii/jui/assets/jquery.ui.progressbar.js | 145 -- .../jui/yii/jui/assets/jquery.ui.resizable.js | 968 --------- .../jui/yii/jui/assets/jquery.ui.selectable.js | 277 --- extensions/jui/yii/jui/assets/jquery.ui.slider.js | 672 ------ .../jui/yii/jui/assets/jquery.ui.sortable.js | 1285 ----------- extensions/jui/yii/jui/assets/jquery.ui.spinner.js | 493 ----- extensions/jui/yii/jui/assets/jquery.ui.tabs.js | 846 -------- extensions/jui/yii/jui/assets/jquery.ui.tooltip.js | 402 ---- extensions/jui/yii/jui/assets/jquery.ui.widget.js | 521 ----- .../jui/assets/theme/images/animated-overlay.gif | Bin 1738 -> 0 bytes .../theme/images/ui-bg_flat_0_aaaaaa_40x100.png | Bin 212 -> 0 bytes .../theme/images/ui-bg_flat_75_ffffff_40x100.png | Bin 208 -> 0 bytes .../theme/images/ui-bg_glass_55_fbf9ee_1x400.png | Bin 335 -> 0 bytes .../theme/images/ui-bg_glass_65_ffffff_1x400.png | Bin 207 -> 0 bytes .../theme/images/ui-bg_glass_75_dadada_1x400.png | Bin 262 -> 0 bytes .../theme/images/ui-bg_glass_75_e6e6e6_1x400.png | Bin 262 -> 0 bytes .../theme/images/ui-bg_glass_95_fef1ec_1x400.png | Bin 332 -> 0 bytes .../ui-bg_highlight-soft_75_cccccc_1x100.png | Bin 280 -> 0 bytes .../theme/images/ui-icons_222222_256x240.png | Bin 6922 -> 0 bytes .../theme/images/ui-icons_2e83ff_256x240.png | Bin 4549 -> 0 bytes .../theme/images/ui-icons_454545_256x240.png | Bin 6992 -> 0 bytes .../theme/images/ui-icons_888888_256x240.png | Bin 6999 -> 0 bytes .../theme/images/ui-icons_cd0a0a_256x240.png | Bin 4549 -> 0 bytes extensions/jui/yii/jui/assets/theme/jquery.ui.css | 1177 ---------- 153 files changed, 20061 insertions(+), 20060 deletions(-) create mode 100644 extensions/jui/Accordion.php create mode 100644 extensions/jui/AccordionAsset.php create mode 100644 extensions/jui/AutoComplete.php create mode 100644 extensions/jui/AutoCompleteAsset.php create mode 100644 extensions/jui/ButtonAsset.php create mode 100644 extensions/jui/CoreAsset.php create mode 100644 extensions/jui/DatePicker.php create mode 100644 extensions/jui/DatePickerAsset.php create mode 100644 extensions/jui/DatePickerRegionalAsset.php create mode 100644 extensions/jui/Dialog.php create mode 100644 extensions/jui/DialogAsset.php create mode 100644 extensions/jui/Draggable.php create mode 100644 extensions/jui/DraggableAsset.php create mode 100644 extensions/jui/Droppable.php create mode 100644 extensions/jui/DroppableAsset.php create mode 100644 extensions/jui/EffectAsset.php create mode 100644 extensions/jui/Extension.php create mode 100644 extensions/jui/InputWidget.php create mode 100644 extensions/jui/Menu.php create mode 100644 extensions/jui/MenuAsset.php create mode 100644 extensions/jui/ProgressBar.php create mode 100644 extensions/jui/ProgressBarAsset.php create mode 100644 extensions/jui/Resizable.php create mode 100644 extensions/jui/ResizableAsset.php create mode 100644 extensions/jui/Selectable.php create mode 100644 extensions/jui/SelectableAsset.php create mode 100644 extensions/jui/Slider.php create mode 100644 extensions/jui/SliderAsset.php create mode 100644 extensions/jui/Sortable.php create mode 100644 extensions/jui/SortableAsset.php create mode 100644 extensions/jui/Spinner.php create mode 100644 extensions/jui/SpinnerAsset.php create mode 100644 extensions/jui/Tabs.php create mode 100644 extensions/jui/TabsAsset.php create mode 100644 extensions/jui/ThemeAsset.php create mode 100644 extensions/jui/TooltipAsset.php create mode 100644 extensions/jui/Widget.php create mode 100644 extensions/jui/assets.php create mode 100644 extensions/jui/assets/UPGRADE.md create mode 100644 extensions/jui/assets/jquery.ui.accordion.js create mode 100644 extensions/jui/assets/jquery.ui.autocomplete.js create mode 100644 extensions/jui/assets/jquery.ui.button.js create mode 100644 extensions/jui/assets/jquery.ui.core.js create mode 100755 extensions/jui/assets/jquery.ui.datepicker-i18n.js create mode 100644 extensions/jui/assets/jquery.ui.datepicker.js create mode 100644 extensions/jui/assets/jquery.ui.dialog.js create mode 100644 extensions/jui/assets/jquery.ui.draggable.js create mode 100644 extensions/jui/assets/jquery.ui.droppable.js create mode 100755 extensions/jui/assets/jquery.ui.effect-all.js create mode 100644 extensions/jui/assets/jquery.ui.menu.js create mode 100644 extensions/jui/assets/jquery.ui.mouse.js create mode 100644 extensions/jui/assets/jquery.ui.position.js create mode 100644 extensions/jui/assets/jquery.ui.progressbar.js create mode 100644 extensions/jui/assets/jquery.ui.resizable.js create mode 100644 extensions/jui/assets/jquery.ui.selectable.js create mode 100644 extensions/jui/assets/jquery.ui.slider.js create mode 100644 extensions/jui/assets/jquery.ui.sortable.js create mode 100644 extensions/jui/assets/jquery.ui.spinner.js create mode 100644 extensions/jui/assets/jquery.ui.tabs.js create mode 100644 extensions/jui/assets/jquery.ui.tooltip.js create mode 100644 extensions/jui/assets/jquery.ui.widget.js create mode 100755 extensions/jui/assets/theme/images/animated-overlay.gif create mode 100755 extensions/jui/assets/theme/images/ui-bg_flat_0_aaaaaa_40x100.png create mode 100755 extensions/jui/assets/theme/images/ui-bg_flat_75_ffffff_40x100.png create mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_55_fbf9ee_1x400.png create mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_65_ffffff_1x400.png create mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_75_dadada_1x400.png create mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_75_e6e6e6_1x400.png create mode 100755 extensions/jui/assets/theme/images/ui-bg_glass_95_fef1ec_1x400.png create mode 100755 extensions/jui/assets/theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png create mode 100755 extensions/jui/assets/theme/images/ui-icons_222222_256x240.png create mode 100755 extensions/jui/assets/theme/images/ui-icons_2e83ff_256x240.png create mode 100755 extensions/jui/assets/theme/images/ui-icons_454545_256x240.png create mode 100755 extensions/jui/assets/theme/images/ui-icons_888888_256x240.png create mode 100755 extensions/jui/assets/theme/images/ui-icons_cd0a0a_256x240.png create mode 100755 extensions/jui/assets/theme/jquery.ui.css delete mode 100644 extensions/jui/yii/jui/Accordion.php delete mode 100644 extensions/jui/yii/jui/AccordionAsset.php delete mode 100644 extensions/jui/yii/jui/AutoComplete.php delete mode 100644 extensions/jui/yii/jui/AutoCompleteAsset.php delete mode 100644 extensions/jui/yii/jui/ButtonAsset.php delete mode 100644 extensions/jui/yii/jui/CoreAsset.php delete mode 100644 extensions/jui/yii/jui/DatePicker.php delete mode 100644 extensions/jui/yii/jui/DatePickerAsset.php delete mode 100644 extensions/jui/yii/jui/DatePickerRegionalAsset.php delete mode 100644 extensions/jui/yii/jui/Dialog.php delete mode 100644 extensions/jui/yii/jui/DialogAsset.php delete mode 100644 extensions/jui/yii/jui/Draggable.php delete mode 100644 extensions/jui/yii/jui/DraggableAsset.php delete mode 100644 extensions/jui/yii/jui/Droppable.php delete mode 100644 extensions/jui/yii/jui/DroppableAsset.php delete mode 100644 extensions/jui/yii/jui/EffectAsset.php delete mode 100644 extensions/jui/yii/jui/Extension.php delete mode 100644 extensions/jui/yii/jui/InputWidget.php delete mode 100644 extensions/jui/yii/jui/Menu.php delete mode 100644 extensions/jui/yii/jui/MenuAsset.php delete mode 100644 extensions/jui/yii/jui/ProgressBar.php delete mode 100644 extensions/jui/yii/jui/ProgressBarAsset.php delete mode 100644 extensions/jui/yii/jui/Resizable.php delete mode 100644 extensions/jui/yii/jui/ResizableAsset.php delete mode 100644 extensions/jui/yii/jui/Selectable.php delete mode 100644 extensions/jui/yii/jui/SelectableAsset.php delete mode 100644 extensions/jui/yii/jui/Slider.php delete mode 100644 extensions/jui/yii/jui/SliderAsset.php delete mode 100644 extensions/jui/yii/jui/Sortable.php delete mode 100644 extensions/jui/yii/jui/SortableAsset.php delete mode 100644 extensions/jui/yii/jui/Spinner.php delete mode 100644 extensions/jui/yii/jui/SpinnerAsset.php delete mode 100644 extensions/jui/yii/jui/Tabs.php delete mode 100644 extensions/jui/yii/jui/TabsAsset.php delete mode 100644 extensions/jui/yii/jui/ThemeAsset.php delete mode 100644 extensions/jui/yii/jui/TooltipAsset.php delete mode 100644 extensions/jui/yii/jui/Widget.php delete mode 100644 extensions/jui/yii/jui/assets.php delete mode 100644 extensions/jui/yii/jui/assets/UPGRADE.md delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.accordion.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.autocomplete.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.button.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.core.js delete mode 100755 extensions/jui/yii/jui/assets/jquery.ui.datepicker-i18n.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.datepicker.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.dialog.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.draggable.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.droppable.js delete mode 100755 extensions/jui/yii/jui/assets/jquery.ui.effect-all.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.menu.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.mouse.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.position.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.progressbar.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.resizable.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.selectable.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.slider.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.sortable.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.spinner.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.tabs.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.tooltip.js delete mode 100644 extensions/jui/yii/jui/assets/jquery.ui.widget.js delete mode 100755 extensions/jui/yii/jui/assets/theme/images/animated-overlay.gif delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-bg_flat_0_aaaaaa_40x100.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-bg_flat_75_ffffff_40x100.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-bg_glass_55_fbf9ee_1x400.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-bg_glass_65_ffffff_1x400.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-bg_glass_75_dadada_1x400.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-bg_glass_75_e6e6e6_1x400.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-bg_glass_95_fef1ec_1x400.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-bg_highlight-soft_75_cccccc_1x100.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-icons_222222_256x240.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-icons_2e83ff_256x240.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-icons_454545_256x240.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-icons_888888_256x240.png delete mode 100755 extensions/jui/yii/jui/assets/theme/images/ui-icons_cd0a0a_256x240.png delete mode 100755 extensions/jui/yii/jui/assets/theme/jquery.ui.css diff --git a/extensions/jui/Accordion.php b/extensions/jui/Accordion.php new file mode 100644 index 0000000..42897a9 --- /dev/null +++ b/extensions/jui/Accordion.php @@ -0,0 +1,121 @@ + [ + * [ + * 'header' => 'Section 1', + * 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...', + * ], + * [ + * 'header' => 'Section 2', + * 'headerOptions' => ['tag' => 'h3'], + * 'content' => 'Sed non urna. Phasellus eu ligula. Vestibulum sit amet purus...', + * 'options' => ['tag' => 'div'], + * ], + * ], + * 'options' => ['tag' => 'div'], + * 'itemOptions' => ['tag' => 'div'], + * 'headerOptions' => ['tag' => 'h3'], + * 'clientOptions' => ['collapsible' => false], + * ]); + * ``` + * + * @see http://api.jqueryui.com/accordion/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Accordion extends Widget +{ + /** + * @var array the HTML attributes for the widget container tag. The following special options are recognized: + * + * - tag: string, defaults to "div", the tag name of the container tag of this widget + */ + public $options = []; + /** + * @var array list of collapsible items. Each item can be an array of the following structure: + * + * ~~~ + * [ + * 'header' => 'Item header', + * 'content' => 'Item content', + * // the HTML attributes of the item header container tag. This will overwrite "headerOptions". + * 'headerOptions' => [], + * // the HTML attributes of the item container tag. This will overwrite "itemOptions". + * 'options' => [], + * ] + * ~~~ + */ + public $items = []; + /** + * @var array list of HTML attributes for the item container tags. This will be overwritten + * by the "options" set in individual [[items]]. The following special options are recognized: + * + * - tag: string, defaults to "div", the tag name of the item container tags. + */ + public $itemOptions = []; + /** + * @var array list of HTML attributes for the item header container tags. This will be overwritten + * by the "headerOptions" set in individual [[items]]. The following special options are recognized: + * + * - tag: string, defaults to "h3", the tag name of the item container tags. + */ + public $headerOptions = []; + + + /** + * Renders the widget. + */ + public function run() + { + $options = $this->options; + $tag = ArrayHelper::remove($options, 'tag', 'div'); + echo Html::beginTag($tag, $options) . "\n"; + echo $this->renderItems() . "\n"; + echo Html::endTag($tag) . "\n"; + $this->registerWidget('accordion', AccordionAsset::className()); + } + + /** + * Renders collapsible items as specified on [[items]]. + * @return string the rendering result. + * @throws InvalidConfigException. + */ + protected function renderItems() + { + $items = []; + foreach ($this->items as $item) { + if (!isset($item['header'])) { + throw new InvalidConfigException("The 'header' option is required."); + } + if (!isset($item['content'])) { + throw new InvalidConfigException("The 'content' option is required."); + } + $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); + $headerTag = ArrayHelper::remove($headerOptions, 'tag', 'h3'); + $items[] = Html::tag($headerTag, $item['header'], $headerOptions); + $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); + $tag = ArrayHelper::remove($options, 'tag', 'div'); + $items[] = Html::tag($tag, $item['content'], $options); + } + + return implode("\n", $items); + } +} diff --git a/extensions/jui/AccordionAsset.php b/extensions/jui/AccordionAsset.php new file mode 100644 index 0000000..05c1e20 --- /dev/null +++ b/extensions/jui/AccordionAsset.php @@ -0,0 +1,26 @@ + + * @since 2.0 + */ +class AccordionAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.accordion.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + 'yii\jui\EffectAsset', + ]; +} diff --git a/extensions/jui/AutoComplete.php b/extensions/jui/AutoComplete.php new file mode 100644 index 0000000..ac0c997 --- /dev/null +++ b/extensions/jui/AutoComplete.php @@ -0,0 +1,66 @@ + $model, + * 'attribute' => 'country', + * 'clientOptions' => [ + * 'source' => ['USA', 'RUS'], + * ], + * ]); + * ``` + * + * The following example will use the name property instead: + * + * ```php + * echo AutoComplete::widget([ + * 'name' => 'country', + * 'clientOptions' => [ + * 'source' => ['USA', 'RUS'], + * ], + * ]); + *``` + * + * @see http://api.jqueryui.com/autocomplete/ + * @author Alexander Kochetov + * @since 2.0 + */ +class AutoComplete extends InputWidget +{ + /** + * Renders the widget. + */ + public function run() + { + echo $this->renderWidget(); + $this->registerWidget('autocomplete', AutoCompleteAsset::className()); + } + + /** + * Renders the AutoComplete widget. + * @return string the rendering result. + */ + public function renderWidget() + { + if ($this->hasModel()) { + return Html::activeTextInput($this->model, $this->attribute, $this->options); + } else { + return Html::textInput($this->name, $this->value, $this->options); + } + } +} diff --git a/extensions/jui/AutoCompleteAsset.php b/extensions/jui/AutoCompleteAsset.php new file mode 100644 index 0000000..f48e064 --- /dev/null +++ b/extensions/jui/AutoCompleteAsset.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class AutoCompleteAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.autocomplete.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + 'yii\jui\MenuAsset', + ]; +} diff --git a/extensions/jui/ButtonAsset.php b/extensions/jui/ButtonAsset.php new file mode 100644 index 0000000..6616b34 --- /dev/null +++ b/extensions/jui/ButtonAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class ButtonAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.button.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + ]; +} diff --git a/extensions/jui/CoreAsset.php b/extensions/jui/CoreAsset.php new file mode 100644 index 0000000..d77a25f --- /dev/null +++ b/extensions/jui/CoreAsset.php @@ -0,0 +1,27 @@ + + * @since 2.0 + */ +class CoreAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.core.js', + 'jquery.ui.widget.js', + 'jquery.ui.position.js', + 'jquery.ui.mouse.js', + ]; + public $depends = [ + 'yii\web\JqueryAsset', + ]; +} diff --git a/extensions/jui/DatePicker.php b/extensions/jui/DatePicker.php new file mode 100644 index 0000000..06ca356 --- /dev/null +++ b/extensions/jui/DatePicker.php @@ -0,0 +1,110 @@ + 'ru', + * 'model' => $model, + * 'attribute' => 'country', + * 'clientOptions' => [ + * 'dateFormat' => 'yy-mm-dd', + * ], + * ]); + * ``` + * + * The following example will use the name property instead: + * + * ```php + * echo DatePicker::widget([ + * 'language' => 'ru', + * 'name' => 'country', + * 'clientOptions' => [ + * 'dateFormat' => 'yy-mm-dd', + * ], + * ]); + *``` + * + * @see http://api.jqueryui.com/datepicker/ + * @author Alexander Kochetov + * @since 2.0 + */ +class DatePicker extends InputWidget +{ + /** + * @var string the locale ID (eg 'fr', 'de') for the language to be used by the date picker. + * If this property set to false, I18N will not be involved. That is, the date picker will show in English. + */ + public $language = false; + /** + * @var boolean If true, shows the widget as an inline calendar and the input as a hidden field. + */ + public $inline = false; + + + /** + * Renders the widget. + */ + public function run() + { + echo $this->renderWidget() . "\n"; + if ($this->language !== false) { + $view = $this->getView(); + DatePickerRegionalAsset::register($view); + + $options = Json::encode($this->clientOptions); + $view->registerJs("$('#{$this->options['id']}').datepicker($.extend({}, $.datepicker.regional['{$this->language}'], $options));"); + + $options = $this->clientOptions; + $this->clientOptions = false; // the datepicker js widget is already registered + $this->registerWidget('datepicker', DatePickerAsset::className()); + $this->clientOptions = $options; + } else { + $this->registerWidget('datepicker', DatePickerAsset::className()); + } + } + + /** + * Renders the DatePicker widget. + * @return string the rendering result. + */ + protected function renderWidget() + { + $contents = []; + + if ($this->inline === false) { + if ($this->hasModel()) { + $contents[] = Html::activeTextInput($this->model, $this->attribute, $this->options); + } else { + $contents[] = Html::textInput($this->name, $this->value, $this->options); + } + } else { + if ($this->hasModel()) { + $contents[] = Html::activeHiddenInput($this->model, $this->attribute, $this->options); + $this->clientOptions['defaultDate'] = $this->model->{$this->attribute}; + } else { + $contents[] = Html::hiddenInput($this->name, $this->value, $this->options); + $this->clientOptions['defaultDate'] = $this->value; + } + $this->clientOptions['altField'] = '#' . $this->options['id']; + $this->options['id'] .= '-container'; + $contents[] = Html::tag('div', null, $this->options); + } + + return implode("\n", $contents); + } +} diff --git a/extensions/jui/DatePickerAsset.php b/extensions/jui/DatePickerAsset.php new file mode 100644 index 0000000..fddd8df --- /dev/null +++ b/extensions/jui/DatePickerAsset.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class DatePickerAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.datepicker.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + 'yii\jui\EffectAsset', + ]; +} diff --git a/extensions/jui/DatePickerRegionalAsset.php b/extensions/jui/DatePickerRegionalAsset.php new file mode 100644 index 0000000..249373a --- /dev/null +++ b/extensions/jui/DatePickerRegionalAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class DatePickerRegionalAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.datepicker-i18n.js', + ]; + public $depends = [ + 'yii\jui\DatePickerAsset', + ]; +} diff --git a/extensions/jui/Dialog.php b/extensions/jui/Dialog.php new file mode 100644 index 0000000..a5cbaf2 --- /dev/null +++ b/extensions/jui/Dialog.php @@ -0,0 +1,52 @@ + [ + * 'modal' => true, + * ], + * ]); + * + * echo 'Dialog contents here...'; + * + * Dialog::end(); + * ``` + * + * @see http://api.jqueryui.com/dialog/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Dialog extends Widget +{ + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + echo Html::beginTag('div', $this->options) . "\n"; + } + + /** + * Renders the widget. + */ + public function run() + { + echo Html::endTag('div') . "\n"; + $this->registerWidget('dialog', DialogAsset::className()); + } +} diff --git a/extensions/jui/DialogAsset.php b/extensions/jui/DialogAsset.php new file mode 100644 index 0000000..109243e --- /dev/null +++ b/extensions/jui/DialogAsset.php @@ -0,0 +1,27 @@ + + * @since 2.0 + */ +class DialogAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.dialog.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + 'yii\jui\ButtonAsset', + 'yii\jui\DraggableAsset', + 'yii\jui\ResizableAsset', + ]; +} diff --git a/extensions/jui/Draggable.php b/extensions/jui/Draggable.php new file mode 100644 index 0000000..02e4973 --- /dev/null +++ b/extensions/jui/Draggable.php @@ -0,0 +1,50 @@ + ['grid' => [50, 20]], + * ]); + * + * echo 'Draggable contents here...'; + * + * Draggable::end(); + * ``` + * + * @see http://api.jqueryui.com/draggable/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Draggable extends Widget +{ + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + echo Html::beginTag('div', $this->options) . "\n"; + } + + /** + * Renders the widget. + */ + public function run() + { + echo Html::endTag('div') . "\n"; + $this->registerWidget('draggable', DraggableAsset::className()); + } +} diff --git a/extensions/jui/DraggableAsset.php b/extensions/jui/DraggableAsset.php new file mode 100644 index 0000000..f3286a5 --- /dev/null +++ b/extensions/jui/DraggableAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class DraggableAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.draggable.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + ]; +} diff --git a/extensions/jui/Droppable.php b/extensions/jui/Droppable.php new file mode 100644 index 0000000..530e736 --- /dev/null +++ b/extensions/jui/Droppable.php @@ -0,0 +1,50 @@ + ['accept' => '.special'], + * ]); + * + * echo 'Droppable body here...'; + * + * Droppable::end(); + * ``` + * + * @see http://api.jqueryui.com/droppable/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Droppable extends Widget +{ + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + echo Html::beginTag('div', $this->options) . "\n"; + } + + /** + * Renders the widget. + */ + public function run() + { + echo Html::endTag('div') . "\n"; + $this->registerWidget('droppable', DroppableAsset::className()); + } +} diff --git a/extensions/jui/DroppableAsset.php b/extensions/jui/DroppableAsset.php new file mode 100644 index 0000000..84b64b8 --- /dev/null +++ b/extensions/jui/DroppableAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class DroppableAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.droppable.js', + ]; + public $depends = [ + 'yii\jui\DraggableAsset', + ]; +} diff --git a/extensions/jui/EffectAsset.php b/extensions/jui/EffectAsset.php new file mode 100644 index 0000000..79c5aaa --- /dev/null +++ b/extensions/jui/EffectAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class EffectAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.effect-all.js', + ]; + public $depends = [ + 'yii\web\JqueryAsset', + ]; +} diff --git a/extensions/jui/Extension.php b/extensions/jui/Extension.php new file mode 100644 index 0000000..4b680ce --- /dev/null +++ b/extensions/jui/Extension.php @@ -0,0 +1,27 @@ + + * @since 2.0 + */ +class Extension extends \yii\base\Extension +{ + /** + * @inheritdoc + */ + public static function init() + { + Yii::setAlias('@yii/jui', __DIR__); + } +} diff --git a/extensions/jui/InputWidget.php b/extensions/jui/InputWidget.php new file mode 100644 index 0000000..e100d6c --- /dev/null +++ b/extensions/jui/InputWidget.php @@ -0,0 +1,59 @@ + + * @since 2.0 + */ +class InputWidget extends Widget +{ + /** + * @var Model the data model that this widget is associated with. + */ + public $model; + /** + * @var string the model attribute that this widget is associated with. + */ + public $attribute; + /** + * @var string the input name. This must be set if [[model]] and [[attribute]] are not set. + */ + public $name; + /** + * @var string the input value. + */ + public $value; + + + /** + * Initializes the widget. + * If you override this method, make sure you call the parent implementation first. + */ + public function init() + { + if (!$this->hasModel() && $this->name === null) { + throw new InvalidConfigException("Either 'name' or 'model' and 'attribute' properties must be specified."); + } + parent::init(); + } + + /** + * @return boolean whether this widget is associated with a data model. + */ + protected function hasModel() + { + return $this->model instanceof Model && $this->attribute !== null; + } +} diff --git a/extensions/jui/Menu.php b/extensions/jui/Menu.php new file mode 100644 index 0000000..46c7ee0 --- /dev/null +++ b/extensions/jui/Menu.php @@ -0,0 +1,78 @@ + + * @since 2.0 + */ +class Menu extends \yii\widgets\Menu +{ + /** + * @var array the options for the underlying jQuery UI widget. + * Please refer to the corresponding jQuery UI widget Web page for possible options. + * For example, [this page](http://api.jqueryui.com/accordion/) shows + * how to use the "Accordion" widget and the supported options (e.g. "header"). + */ + public $clientOptions = []; + /** + * @var array the event handlers for the underlying jQuery UI widget. + * Please refer to the corresponding jQuery UI widget Web page for possible events. + * For example, [this page](http://api.jqueryui.com/accordion/) shows + * how to use the "Accordion" widget and the supported events (e.g. "create"). + */ + public $clientEvents = []; + + + /** + * Initializes the widget. + * If you override this method, make sure you call the parent implementation first. + */ + public function init() + { + parent::init(); + if (!isset($this->options['id'])) { + $this->options['id'] = $this->getId(); + } + } + + /** + * Renders the widget. + */ + public function run() + { + parent::run(); + + $view = $this->getView(); + MenuAsset::register($view); + /** @var \yii\web\AssetBundle $themeAsset */ + $themeAsset = Widget::$theme; + $themeAsset::register($view); + + $id = $this->options['id']; + if ($this->clientOptions !== false) { + $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); + $js = "jQuery('#$id').menu($options);"; + $view->registerJs($js); + } + + if (!empty($this->clientEvents)) { + $js = []; + foreach ($this->clientEvents as $event => $handler) { + $js[] = "jQuery('#$id').on('menu$event', $handler);"; + } + $view->registerJs(implode("\n", $js)); + } + } +} diff --git a/extensions/jui/MenuAsset.php b/extensions/jui/MenuAsset.php new file mode 100644 index 0000000..8b840a8 --- /dev/null +++ b/extensions/jui/MenuAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class MenuAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.menu.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + ]; +} diff --git a/extensions/jui/ProgressBar.php b/extensions/jui/ProgressBar.php new file mode 100644 index 0000000..1c555f1 --- /dev/null +++ b/extensions/jui/ProgressBar.php @@ -0,0 +1,60 @@ + [ + * 'value' => 75, + * ], + * ]); + * ``` + * + * The following example will show the content enclosed between the [[begin()]] + * and [[end()]] calls within the widget container: + * + * ~~~php + * ProgressBar::widget([ + * 'clientOptions' => ['value' => 75], + * ]); + * + * echo '
Loading...
'; + * + * ProgressBar::end(); + * ~~~ + * @see http://api.jqueryui.com/progressbar/ + * @author Alexander Kochetov + * @since 2.0 + */ +class ProgressBar extends Widget +{ + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + echo Html::beginTag('div', $this->options) . "\n"; + } + + /** + * Renders the widget. + */ + public function run() + { + echo Html::endTag('div') . "\n"; + $this->registerWidget('progressbar', ProgressBarAsset::className()); + } +} diff --git a/extensions/jui/ProgressBarAsset.php b/extensions/jui/ProgressBarAsset.php new file mode 100644 index 0000000..d485fbd --- /dev/null +++ b/extensions/jui/ProgressBarAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class ProgressBarAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.progressbar.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + ]; +} diff --git a/extensions/jui/Resizable.php b/extensions/jui/Resizable.php new file mode 100644 index 0000000..bcff9a8 --- /dev/null +++ b/extensions/jui/Resizable.php @@ -0,0 +1,52 @@ + [ + * 'grid' => [20, 10], + * ], + * ]); + * + * echo 'Resizable contents here...'; + * + * Resizable::end(); + * ``` + * + * @see http://api.jqueryui.com/resizable/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Resizable extends Widget +{ + /** + * Initializes the widget. + */ + public function init() + { + parent::init(); + echo Html::beginTag('div', $this->options) . "\n"; + } + + /** + * Renders the widget. + */ + public function run() + { + echo Html::endTag('div') . "\n"; + $this->registerWidget('resizable', ResizableAsset::className()); + } +} diff --git a/extensions/jui/ResizableAsset.php b/extensions/jui/ResizableAsset.php new file mode 100644 index 0000000..acf4c73 --- /dev/null +++ b/extensions/jui/ResizableAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class ResizableAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.resizable.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + ]; +} diff --git a/extensions/jui/Selectable.php b/extensions/jui/Selectable.php new file mode 100644 index 0000000..94e4faf --- /dev/null +++ b/extensions/jui/Selectable.php @@ -0,0 +1,116 @@ + [ + * 'Item 1', + * [ + * 'content' => 'Item2', + * ], + * [ + * 'content' => 'Item3', + * 'options' => [ + * 'tag' => 'li', + * ], + * ], + * ), + * 'options' => [ + * 'tag' => 'ul', + * ], + * 'itemOptions' => [ + * 'tag' => 'li', + * ], + * 'clientOptions' => [ + * 'tolerance' => 'fit', + * ], + * ]); + * ``` + * + * @see http://api.jqueryui.com/selectable/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Selectable extends Widget +{ + /** + * @var array the HTML attributes for the widget container tag. The following special options are recognized: + * + * - tag: string, defaults to "ul", the tag name of the container tag of this widget + */ + public $options = []; + /** + * @var array list of selectable items. Each item can be a string representing the item content + * or an array of the following structure: + * + * ~~~ + * [ + * 'content' => 'item content', + * // the HTML attributes of the item container tag. This will overwrite "itemOptions". + * 'options' => [], + * ] + * ~~~ + */ + public $items = []; + /** + * @var array list of HTML attributes for the item container tags. This will be overwritten + * by the "options" set in individual [[items]]. The following special options are recognized: + * + * - tag: string, defaults to "li", the tag name of the item container tags. + */ + public $itemOptions = []; + + + /** + * Renders the widget. + */ + public function run() + { + $options = $this->options; + $tag = ArrayHelper::remove($options, 'tag', 'ul'); + echo Html::beginTag($tag, $options) . "\n"; + echo $this->renderItems() . "\n"; + echo Html::endTag($tag) . "\n"; + $this->registerWidget('selectable', SelectableAsset::className()); + } + + /** + * Renders selectable items as specified on [[items]]. + * @return string the rendering result. + * @throws InvalidConfigException. + */ + public function renderItems() + { + $items = []; + foreach ($this->items as $item) { + $options = $this->itemOptions; + $tag = ArrayHelper::remove($options, 'tag', 'li'); + if (is_array($item)) { + if (!isset($item['content'])) { + throw new InvalidConfigException("The 'content' option is required."); + } + $options = array_merge($options, ArrayHelper::getValue($item, 'options', [])); + $tag = ArrayHelper::remove($options, 'tag', $tag); + $items[] = Html::tag($tag, $item['content'], $options); + } else { + $items[] = Html::tag($tag, $item, $options); + } + } + return implode("\n", $items); + } +} diff --git a/extensions/jui/SelectableAsset.php b/extensions/jui/SelectableAsset.php new file mode 100644 index 0000000..61f405f --- /dev/null +++ b/extensions/jui/SelectableAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class SelectableAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.selectable.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + ]; +} diff --git a/extensions/jui/Slider.php b/extensions/jui/Slider.php new file mode 100644 index 0000000..c19f2db --- /dev/null +++ b/extensions/jui/Slider.php @@ -0,0 +1,68 @@ + $model, + * 'attribute' => 'amount', + * 'clientOptions' => [ + * 'min' => 1, + * 'max' => 10, + * ], + * ]); + * ``` + * + * The following example will use the name property instead: + * + * ```php + * echo Slider::widget([ + * 'name' => 'amount', + * 'clientOptions' => [ + * 'min' => 1, + * 'max' => 10, + * ], + * ]); + *``` + * + * @see http://api.jqueryui.com/slider/ + * @author Alexander Makarov + * @since 2.0 + */ +class Slider extends InputWidget +{ + /** + * Renders the widget. + */ + public function run() + { + echo $this->renderWidget(); + $this->registerWidget('slider', SliderAsset::className()); + } + + /** + * Renders the Slider widget. + * @return string the rendering result. + */ + public function renderWidget() + { + if ($this->hasModel()) { + return Html::activeTextInput($this->model, $this->attribute, $this->options); + } else { + return Html::textInput($this->name, $this->value, $this->options); + } + } +} diff --git a/extensions/jui/SliderAsset.php b/extensions/jui/SliderAsset.php new file mode 100644 index 0000000..56c2451 --- /dev/null +++ b/extensions/jui/SliderAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class SliderAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.slider.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + ]; +} diff --git a/extensions/jui/Sortable.php b/extensions/jui/Sortable.php new file mode 100644 index 0000000..6209cb6 --- /dev/null +++ b/extensions/jui/Sortable.php @@ -0,0 +1,106 @@ + [ + * 'Item 1', + * ['content' => 'Item2'], + * [ + * 'content' => 'Item3', + * 'options' => ['tag' => 'li'], + * ], + * ], + * 'options' => ['tag' => 'ul'], + * 'itemOptions' => ['tag' => 'li'], + * 'clientOptions' => ['cursor' => 'move'], + * )); + * ``` + * + * @see http://api.jqueryui.com/sortable/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Sortable extends Widget +{ + /** + * @var array the HTML attributes for the widget container tag. The following special options are recognized: + * + * - tag: string, defaults to "ul", the tag name of the container tag of this widget + */ + public $options = []; + /** + * @var array list of sortable items. Each item can be a string representing the item content + * or an array of the following structure: + * + * ~~~ + * [ + * 'content' => 'item content', + * // the HTML attributes of the item container tag. This will overwrite "itemOptions". + * 'options' => [], + * ] + * ~~~ + */ + public $items = []; + /** + * @var array list of HTML attributes for the item container tags. This will be overwritten + * by the "options" set in individual [[items]]. The following special options are recognized: + * + * - tag: string, defaults to "li", the tag name of the item container tags. + */ + public $itemOptions = []; + + + /** + * Renders the widget. + */ + public function run() + { + $options = $this->options; + $tag = ArrayHelper::remove($options, 'tag', 'ul'); + echo Html::beginTag($tag, $options) . "\n"; + echo $this->renderItems() . "\n"; + echo Html::endTag($tag) . "\n"; + $this->registerWidget('sortable', SortableAsset::className()); + } + + /** + * Renders sortable items as specified on [[items]]. + * @return string the rendering result. + * @throws InvalidConfigException. + */ + public function renderItems() + { + $items = []; + foreach ($this->items as $item) { + $options = $this->itemOptions; + $tag = ArrayHelper::remove($options, 'tag', 'li'); + if (is_array($item)) { + if (!isset($item['content'])) { + throw new InvalidConfigException("The 'content' option is required."); + } + $options = array_merge($options, ArrayHelper::getValue($item, 'options', [])); + $tag = ArrayHelper::remove($options, 'tag', $tag); + $items[] = Html::tag($tag, $item['content'], $options); + } else { + $items[] = Html::tag($tag, $item, $options); + } + } + return implode("\n", $items); + } +} diff --git a/extensions/jui/SortableAsset.php b/extensions/jui/SortableAsset.php new file mode 100644 index 0000000..69c9ba3 --- /dev/null +++ b/extensions/jui/SortableAsset.php @@ -0,0 +1,24 @@ + + * @since 2.0 + */ +class SortableAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.sortable.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + ]; +} diff --git a/extensions/jui/Spinner.php b/extensions/jui/Spinner.php new file mode 100644 index 0000000..caf73f3 --- /dev/null +++ b/extensions/jui/Spinner.php @@ -0,0 +1,62 @@ + $model, + * 'attribute' => 'country', + * 'clientOptions' => ['step' => 2], + * ]); + * ``` + * + * The following example will use the name property instead: + * + * ```php + * echo Spinner::widget([ + * 'name' => 'country', + * 'clientOptions' => ['step' => 2], + * ]); + *``` + * + * @see http://api.jqueryui.com/spinner/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Spinner extends InputWidget +{ + /** + * Renders the widget. + */ + public function run() + { + echo $this->renderWidget(); + $this->registerWidget('spinner', SpinnerAsset::className()); + } + + /** + * Renders the Spinner widget. + * @return string the rendering result. + */ + public function renderWidget() + { + if ($this->hasModel()) { + return Html::activeTextInput($this->model, $this->attribute, $this->options); + } else { + return Html::textInput($this->name, $this->value, $this->options); + } + } +} diff --git a/extensions/jui/SpinnerAsset.php b/extensions/jui/SpinnerAsset.php new file mode 100644 index 0000000..89a8c59 --- /dev/null +++ b/extensions/jui/SpinnerAsset.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class SpinnerAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.spinner.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + 'yii\jui\ButtonAsset', + ]; +} diff --git a/extensions/jui/Tabs.php b/extensions/jui/Tabs.php new file mode 100644 index 0000000..9d2a2be --- /dev/null +++ b/extensions/jui/Tabs.php @@ -0,0 +1,145 @@ + [ + * [ + * 'label' => 'Tab one', + * 'content' => 'Mauris mauris ante, blandit et, ultrices a, suscipit eget...', + * ], + * [ + * 'label' => 'Tab two', + * 'content' => 'Sed non urna. Phasellus eu ligula. Vestibulum sit amet purus...', + * 'options' => ['tag' => 'div'], + * 'headerOptions' => ['class' => 'my-class'], + * ], + * [ + * 'label' => 'Tab with custom id', + * 'content' => 'Morbi tincidunt, dui sit amet facilisis feugiat...', + * 'options' => ['id' => 'my-tab'], + * ], + * [ + * 'label' => 'Ajax tab', + * 'url' => ['ajax/content'], + * ], + * ), + * 'options' => ['tag' => 'div'], + * 'itemOptions' => ['tag' => 'div'], + * 'headerOptions' => ['class' => 'my-class'], + * 'clientOptions' => ['collapsible' => false], + * ]); + * ``` + * + * @see http://api.jqueryui.com/tabs/ + * @author Alexander Kochetov + * @since 2.0 + */ +class Tabs extends Widget +{ + /** + * @var array the HTML attributes for the widget container tag. The following special options are recognized: + * + * - tag: string, defaults to "div", the tag name of the container tag of this widget + */ + public $options = []; + /** + * @var array list of tab items. Each item can be an array of the following structure: + * + * - label: string, required, specifies the header link label. When [[encodeLabels]] is true, the label + * will be HTML-encoded. + * - content: string, the content to show when corresponding tab is clicked. Can be omitted if url is specified. + * - url: mixed, mixed, optional, the url to load tab contents via AJAX. It is required if no content is specified. + * - template: string, optional, the header link template to render the header link. If none specified + * [[linkTemplate]] will be used instead. + * - options: array, optional, the HTML attributes of the header. + * - headerOptions: array, optional, the HTML attributes for the header container tag. + */ + public $items = []; + /** + * @var array list of HTML attributes for the item container tags. This will be overwritten + * by the "options" set in individual [[items]]. The following special options are recognized: + * + * - tag: string, defaults to "div", the tag name of the item container tags. + */ + public $itemOptions = []; + /** + * @var array list of HTML attributes for the header container tags. This will be overwritten + * by the "headerOptions" set in individual [[items]]. + */ + public $headerOptions = []; + /** + * @var string the default header template to render the link. + */ + public $linkTemplate = '{label}'; + /** + * @var boolean whether the labels for header items should be HTML-encoded. + */ + public $encodeLabels = true; + + + /** + * Renders the widget. + */ + public function run() + { + $options = $this->options; + $tag = ArrayHelper::remove($options, 'tag', 'div'); + echo Html::beginTag($tag, $options) . "\n"; + echo $this->renderItems() . "\n"; + echo Html::endTag($tag) . "\n"; + $this->registerWidget('tabs', TabsAsset::className()); + } + + /** + * Renders tab items as specified on [[items]]. + * @return string the rendering result. + * @throws InvalidConfigException. + */ + protected function renderItems() + { + $headers = []; + $items = []; + foreach ($this->items as $n => $item) { + if (!isset($item['label'])) { + throw new InvalidConfigException("The 'label' option is required."); + } + if (isset($item['url'])) { + $url = Html::url($item['url']); + } else { + if (!isset($item['content'])) { + throw new InvalidConfigException("The 'content' or 'url' option is required."); + } + $options = array_merge($this->itemOptions, ArrayHelper::getValue($item, 'options', [])); + $tag = ArrayHelper::remove($options, 'tag', 'div'); + if (!isset($options['id'])) { + $options['id'] = $this->options['id'] . '-tab' . $n; + } + $url = '#' . $options['id']; + $items[] = Html::tag($tag, $item['content'], $options); + } + $headerOptions = array_merge($this->headerOptions, ArrayHelper::getValue($item, 'headerOptions', [])); + $template = ArrayHelper::getValue($item, 'template', $this->linkTemplate); + $headers[] = Html::tag('li', strtr($template, [ + '{label}' => $this->encodeLabels ? Html::encode($item['label']) : $item['label'], + '{url}' => $url, + ]), $headerOptions); + } + return Html::tag('ul', implode("\n", $headers)) . "\n" . implode("\n", $items); + } +} diff --git a/extensions/jui/TabsAsset.php b/extensions/jui/TabsAsset.php new file mode 100644 index 0000000..5bef4c0 --- /dev/null +++ b/extensions/jui/TabsAsset.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class TabsAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.tabs.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + 'yii\jui\EffectAsset', + ]; +} diff --git a/extensions/jui/ThemeAsset.php b/extensions/jui/ThemeAsset.php new file mode 100644 index 0000000..dedcb00 --- /dev/null +++ b/extensions/jui/ThemeAsset.php @@ -0,0 +1,21 @@ + + * @since 2.0 + */ +class ThemeAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $css = [ + 'theme/jquery.ui.css', + ]; +} diff --git a/extensions/jui/TooltipAsset.php b/extensions/jui/TooltipAsset.php new file mode 100644 index 0000000..1fa4490 --- /dev/null +++ b/extensions/jui/TooltipAsset.php @@ -0,0 +1,25 @@ + + * @since 2.0 + */ +class TooltipAsset extends AssetBundle +{ + public $sourcePath = '@yii/jui/assets'; + public $js = [ + 'jquery.ui.tooltip.js', + ]; + public $depends = [ + 'yii\jui\CoreAsset', + 'yii\jui\EffectAsset', + ]; +} diff --git a/extensions/jui/Widget.php b/extensions/jui/Widget.php new file mode 100644 index 0000000..2bbc9e4 --- /dev/null +++ b/extensions/jui/Widget.php @@ -0,0 +1,87 @@ + + * @since 2.0 + */ +class Widget extends \yii\base\Widget +{ + /** + * @var string the jQuery UI theme. This refers to an asset bundle class + * representing the JUI theme. The default theme is the official "Smoothness" theme. + */ + public static $theme = 'yii\jui\ThemeAsset'; + /** + * @var array the HTML attributes for the widget container tag. + */ + public $options = []; + /** + * @var array the options for the underlying jQuery UI widget. + * Please refer to the corresponding jQuery UI widget Web page for possible options. + * For example, [this page](http://api.jqueryui.com/accordion/) shows + * how to use the "Accordion" widget and the supported options (e.g. "header"). + */ + public $clientOptions = []; + /** + * @var array the event handlers for the underlying jQuery UI widget. + * Please refer to the corresponding jQuery UI widget Web page for possible events. + * For example, [this page](http://api.jqueryui.com/accordion/) shows + * how to use the "Accordion" widget and the supported events (e.g. "create"). + */ + public $clientEvents = []; + + + /** + * Initializes the widget. + * If you override this method, make sure you call the parent implementation first. + */ + public function init() + { + parent::init(); + if (!isset($this->options['id'])) { + $this->options['id'] = $this->getId(); + } + } + + /** + * Registers a specific jQuery UI widget and the related events + * @param string $name the name of the jQuery UI widget + * @param string $assetBundle the asset bundle for the widget + */ + protected function registerWidget($name, $assetBundle) + { + $view = $this->getView(); + /** @var \yii\web\AssetBundle $assetBundle */ + $assetBundle::register($view); + /** @var \yii\web\AssetBundle $themeAsset */ + $themeAsset = self::$theme; + $themeAsset::register($view); + + $id = $this->options['id']; + if ($this->clientOptions !== false) { + $options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions); + $js = "jQuery('#$id').$name($options);"; + $view->registerJs($js); + } + + if (!empty($this->clientEvents)) { + $js = []; + foreach ($this->clientEvents as $event => $handler) { + $js[] = "jQuery('#$id').on('$name$event', $handler);"; + } + $view->registerJs(implode("\n", $js)); + } + } +} diff --git a/extensions/jui/assets.php b/extensions/jui/assets.php new file mode 100644 index 0000000..ab4c930 --- /dev/null +++ b/extensions/jui/assets.php @@ -0,0 +1,23 @@ + li > :first-child,> :not(li):even", + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // callbacks + activate: null, + beforeActivate: null + }, + + _create: function() { + var options = this.options; + this.prevShow = this.prevHide = $(); + this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) + // ARIA + .attr( "role", "tablist" ); + + // don't allow collapsible: false and active: false / null + if ( !options.collapsible && (options.active === false || options.active == null) ) { + options.active = 0; + } + + this._processPanels(); + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this._refresh(); + }, + + _getCreateEventData: function() { + return { + header: this.active, + panel: !this.active.length ? $() : this.active.next(), + content: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icons = this.options.icons; + if ( icons ) { + $( "" ) + .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) + .prependTo( this.headers ); + this.active.children( ".ui-accordion-header-icon" ) + .removeClass( icons.header ) + .addClass( icons.activeHeader ); + this.headers.addClass( "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this.headers + .removeClass( "ui-accordion-icons" ) + .children( ".ui-accordion-header-icon" ) + .remove(); + }, + + _destroy: function() { + var contents; + + // clean up main element + this.element + .removeClass( "ui-accordion ui-widget ui-helper-reset" ) + .removeAttr( "role" ); + + // clean up headers + this.headers + .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) + .removeAttr( "role" ) + .removeAttr( "aria-selected" ) + .removeAttr( "aria-controls" ) + .removeAttr( "tabIndex" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + this._destroyIcons(); + + // clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role" ) + .removeAttr( "aria-expanded" ) + .removeAttr( "aria-hidden" ) + .removeAttr( "aria-labelledby" ) + .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) + .each(function() { + if ( /^ui-accordion/.test( this.id ) ) { + this.removeAttribute( "id" ); + } + }); + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + + // #5332 - opacity doesn't cascade to positioned elements in IE + // so we need to add the disabled class to the headers and panels + if ( key === "disabled" ) { + this.headers.add( this.headers.next() ) + .toggleClass( "ui-state-disabled", !!value ); + } + }, + + _keydown: function( event ) { + /*jshint maxcomplexity:15*/ + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + toFocus.focus(); + event.preventDefault(); + } + }, + + _panelKeyDown : function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().focus(); + } + }, + + refresh: function() { + var options = this.options; + this._processPanels(); + + // was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { + options.active = false; + this.active = $(); + // active false only when collapsible is true + } else if ( options.active === false ) { + this._activate( 0 ); + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + // all remaining panel are disabled + if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { + options.active = false; + this.active = $(); + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); + } + // was active, active panel still exists + } else { + // make sure active index is correct + options.active = this.headers.index( this.active ); + } + + this._destroyIcons(); + + this._refresh(); + }, + + _processPanels: function() { + this.headers = this.element.find( this.options.header ) + .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); + + this.headers.next() + .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) + .filter(":not(.ui-accordion-content-active)") + .hide(); + }, + + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(), + accordionId = this.accordionId = "ui-accordion-" + + (this.element.attr( "id" ) || ++uid); + + this.active = this._findActive( options.active ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) + .removeClass( "ui-corner-all" ); + this.active.next() + .addClass( "ui-accordion-content-active" ) + .show(); + + this.headers + .attr( "role", "tab" ) + .each(function( i ) { + var header = $( this ), + headerId = header.attr( "id" ), + panel = header.next(), + panelId = panel.attr( "id" ); + if ( !headerId ) { + headerId = accordionId + "-header-" + i; + header.attr( "id", headerId ); + } + if ( !panelId ) { + panelId = accordionId + "-panel-" + i; + panel.attr( "id", panelId ); + } + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + }) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr({ + "aria-selected": "false", + tabIndex: -1 + }) + .next() + .attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }) + .hide(); + + // make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr({ + "aria-selected": "true", + tabIndex: 0 + }) + .next() + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each(function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + }); + + this.headers.each(function() { + maxHeight -= $( this ).outerHeight( true ); + }); + + this.headers.next() + .each(function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + }) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each(function() { + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + }) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler({ + target: active, + currentTarget: active, + preventDefault: $.noop + }); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split(" "), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + }); + } + + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" }); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // when the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // switch classes + // corner classes on the previously active header stay after the animation + active.removeClass( "ui-accordion-header-active ui-state-active" ); + if ( options.icons ) { + active.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.activeHeader ) + .addClass( options.icons.header ); + } + + if ( !clickedIsActive ) { + clicked + .removeClass( "ui-corner-all" ) + .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); + if ( options.icons ) { + clicked.children( ".ui-accordion-header-icon" ) + .removeClass( options.icons.header ) + .addClass( options.icons.activeHeader ); + } + + clicked + .next() + .addClass( "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr({ + "aria-expanded": "false", + "aria-hidden": "true" + }); + toHide.prev().attr( "aria-selected", "false" ); + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.headers.filter(function() { + return $( this ).attr( "tabIndex" ) === 0; + }) + .attr( "tabIndex", -1 ); + } + + toShow + .attr({ + "aria-expanded": "true", + "aria-hidden": "false" + }) + .prev() + .attr({ + "aria-selected": "true", + tabIndex: 0 + }); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + }); + toShow + .hide() + .animate( showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + adjust += fx.now; + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + }); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel; + + toHide + .removeClass( "ui-accordion-content-active" ) + .prev() + .removeClass( "ui-corner-top" ) + .addClass( "ui-corner-all" ); + + // Work around for rendering bug in IE (#5421) + if ( toHide.length ) { + toHide.parent()[0].className = toHide.parent()[0].className; + } + + this._trigger( "activate", null, data ); + } +}); + +})( jQuery ); diff --git a/extensions/jui/assets/jquery.ui.autocomplete.js b/extensions/jui/assets/jquery.ui.autocomplete.js new file mode 100644 index 0000000..ca53d2c --- /dev/null +++ b/extensions/jui/assets/jquery.ui.autocomplete.js @@ -0,0 +1,610 @@ +/*! + * jQuery UI Autocomplete 1.10.3 + * http://jqueryui.com + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/autocomplete/ + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + * jquery.ui.position.js + * jquery.ui.menu.js + */ +(function( $, undefined ) { + +// used to prevent race conditions with remote data sources +var requestIndex = 0; + +$.widget( "ui.autocomplete", { + version: "1.10.3", + defaultElement: "", + options: { + appendTo: null, + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, + + pending: 0, + + _create: function() { + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput, + nodeName = this.element[0].nodeName.toLowerCase(), + isTextarea = nodeName === "textarea", + isInput = nodeName === "input"; + + this.isMultiLine = + // Textareas are always multi-line + isTextarea ? true : + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + isInput ? false : + // All other element types are determined by whether or not they're contentEditable + this.element.prop( "isContentEditable" ); + + this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; + this.isNewMenu = true; + + this.element + .addClass( "ui-autocomplete-input" ) + .attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + /*jshint maxcomplexity:15*/ + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; + } + + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + case keyCode.NUMPAD_ENTER: + // when menu is open and has focus + if ( this.menu.active ) { + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + this._value( this.term ); + this.close( event ); + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + // Double press in IE means clear the whole form + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + event.preventDefault(); + } + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + if ( this.cancelBlur ) { + delete this.cancelBlur; + return; + } + + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } + }); + + this._initSource(); + this.menu = $( "