├── .gitignore ├── Bootstrap.php ├── CHANGELOG.md ├── ExchangeEvent.php ├── ExchangeModule.php ├── README.md ├── UrlRule.php ├── assets ├── AppAsset.php ├── LuminoAsset.php ├── css │ ├── bootstrap-table.css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ ├── datepicker.css │ ├── datepicker3.css │ ├── default.css │ └── styles.css ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── js │ ├── bootstrap-datepicker.js │ ├── bootstrap-table.js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── chart-data.js │ ├── chart.min.js │ ├── easypiechart-data.js │ ├── easypiechart.js │ ├── highlight.pack.js │ ├── html5shiv.min.js │ ├── jquery-1.11.1.min.js │ ├── lumino.glyphs.js │ └── respond.min.js └── other │ └── favicon.ico ├── behaviors └── BomBehavior.php ├── components └── Breadcrumbs.php ├── composer.json ├── controllers ├── ApiController.php ├── ArticleController.php ├── Controller.php ├── DefaultController.php ├── FileController.php ├── InterfaceController.php └── TestingController.php ├── exchange.db ├── files ├── articles │ └── 100 │ │ ├── 0489d0ae5b-requisite.png │ │ ├── 30d7d0869c-property.png │ │ ├── 30de0bdc18-slide2.png │ │ ├── 47e17f3950-pricetype.png │ │ ├── 79d570a828-order.png │ │ ├── adc45161dd-properties.png │ │ ├── b10bbf4908-specifications.png │ │ ├── c2818da962-slide1.png │ │ ├── dcf36639b2-2018-02-2619-55-41.png │ │ └── f4ca0f06dc-prices.png ├── doc │ ├── changes commerceML 2.09-2.10.pdf │ ├── commerceML 2.09.pdf │ ├── commerceML 2.09.xsd │ ├── commerceML 2.10.pdf │ └── commerceML 2.10.xsd └── xml │ ├── from.xml │ ├── import.xml │ ├── offers.xml │ └── to.xml ├── helpers ├── ByteHelper.php ├── ClassHelper.php ├── ModuleHelper.php ├── NodeHelper.php └── SerializeHelper.php ├── interfaces ├── DocumentInterface.php ├── ExportFieldsInterface.php ├── GroupInterface.php ├── IdentifierInterface.php ├── OfferInterface.php ├── PartnerInterface.php ├── ProductInterface.php ├── RawInterface.php └── WarehouseInterface.php ├── models ├── Article.php ├── InterfaceModel.php ├── InterfaceTest.php ├── Monitor.php ├── Testing.php ├── TestingClass.php ├── TestingDocumentClass.php ├── TestingGroupClass.php ├── TestingPartnerClass.php ├── TestingProductClass.php ├── base │ ├── Article.php │ └── Monitor.php └── query │ ├── ArticleQuery.php │ ├── MonitorQuery.php │ └── base │ ├── ArticleQuery.php │ └── MonitorQuery.php ├── views ├── article │ ├── index.php │ ├── partial │ │ └── nav.php │ ├── update.php │ └── view.php ├── default │ ├── documentation.php │ ├── export.php │ ├── files.php │ ├── import.php │ ├── index.php │ ├── interfaces.php │ ├── list.php │ ├── monitor.php │ └── settings.php ├── interface │ └── check.php ├── layouts │ └── main.php ├── partial │ └── find-model.php ├── testing │ └── index.php └── widgets │ └── panel.php └── widgets ├── Menu.php ├── Panel.php └── TestingGridView.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /vendor/ 3 | /composer.lock 4 | -------------------------------------------------------------------------------- /Bootstrap.php: -------------------------------------------------------------------------------- 1 | getModule($id); 27 | if ($module && $module->bootstrapUrlRule) { 28 | Yii::$app->urlManager->enablePrettyUrl = true; 29 | Yii::$app->urlManager->addRules([new UrlRule], $module->appendRule); 30 | } 31 | } 32 | } 33 | 34 | public function __construct() 35 | { 36 | } 37 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 0.3.0 2 | ===== 3 | * При запросе init от 1С, существующие файлы *.xml будут удалены или заменены на *.bak, в зависимости от настройки debug 4 | * При получении файла не как архива, будет проверяться на существование папки, и создаваться при необходимости, т.к. если uzeZip=false, будут передаваться картинки в теле запроса 5 | 6 | 0.2.9 7 | ===== 8 | * При добавлении UrlRule в urlManager правило теперь по умолчанию добавляется в начало, влиять на настройку можно через module->appendRule 9 | 10 | 0.2.8 11 | ===== 12 | * Обновлен пакет carono/commerceml, исправлена ошибка при поиске свойств у продукта 13 | * Распаковка архива добавлена в момент получения файла, а не при парсинге -------------------------------------------------------------------------------- /ExchangeEvent.php: -------------------------------------------------------------------------------- 1 | redactorModuleName; 125 | if (class_exists($redactorClass) && !Yii::$app->getModule($moduleRedactorName)) { 126 | $routeName = Inflector::camel2id($moduleRedactorName); 127 | \Yii::$app->setModule($moduleRedactorName, [ 128 | 'class' => 'yii\redactor\RedactorModule', 129 | 'uploadDir' => '@vendor/carono/yii2-1c-exchange/files/articles', 130 | 'imageUploadRoute' => ["/$routeName/upload/image"], 131 | 'fileUploadRoute' => ["/$routeName/upload/file"], 132 | 'imageManagerJsonRoute' => ["/$routeName/upload/image-json"], 133 | 'fileManagerJsonRoute' => ["/$routeName/upload/file-json"], 134 | 'imageAllowExtensions' => ['jpg', 'png', 'gif'], 135 | 'on beforeAction' => function () use ($moduleRedactorName) { 136 | $redactor = \Yii::$app->getModule($moduleRedactorName); 137 | $redactor->uploadUrl = '../file/article?file='; 138 | \Yii::$app->setModule($moduleRedactorName, $redactor); 139 | } 140 | ]); 141 | } 142 | } 143 | 144 | /** 145 | * @return null|\yii\base\Module 146 | */ 147 | public function getRedactor() 148 | { 149 | return Yii::$app->getModule($this->redactorModuleName); 150 | } 151 | 152 | /** 153 | * @inheritdoc 154 | */ 155 | public function init() 156 | { 157 | if (!isset(\Yii::$app->i18n->translations['models'])) { 158 | \Yii::$app->i18n->translations['models'] = [ 159 | 'class' => 'yii\i18n\PhpMessageSource', 160 | 'basePath' => '@app/messages', 161 | 'sourceLanguage' => 'en', 162 | ]; 163 | } 164 | $this->loadRedactorModule(); 165 | parent::init(); 166 | } 167 | 168 | public function getTmpDir($part = null) 169 | { 170 | $dir = \Yii::getAlias($this->tmpDir); 171 | if (!is_dir($dir)) { 172 | FileHelper::createDirectory($dir, 0777, true); 173 | } 174 | return $dir . ($part ? DIRECTORY_SEPARATOR . trim($part, '/\\') : ''); 175 | } 176 | 177 | /** 178 | * @param $login 179 | * @param $password 180 | * @return null|IdentityInterface 181 | */ 182 | public function auth($login, $password) 183 | { 184 | /** 185 | * @var $class \yii\web\IdentityInterface 186 | * @var IdentityInterface $user 187 | */ 188 | $class = \Yii::$app->user->identityClass; 189 | if (method_exists($class, 'findByUsername')) { 190 | $user = $class::findByUsername($login); 191 | if ($user && method_exists($user, 'validatePassword') && $user->validatePassword($password)) { 192 | return $user; 193 | } 194 | } 195 | return null; 196 | } 197 | } -------------------------------------------------------------------------------- /UrlRule.php: -------------------------------------------------------------------------------- 1 | '; 12 | public $pattern = '1c_exchange.php'; 13 | 14 | public function init() 15 | { 16 | $this->route = ModuleHelper::getModuleNameByClass('carono\exchange1c\ExchangeModule', 'exchange') . '/api/'; 17 | parent::init(); 18 | } 19 | 20 | public function parseRequest($manager, $request) 21 | { 22 | $this->defaults = ['mode' => \Yii::$app->request->get('mode', 'error')]; 23 | return parent::parseRequest($manager, $request); 24 | } 25 | } -------------------------------------------------------------------------------- /assets/AppAsset.php: -------------------------------------------------------------------------------- 1 | true 26 | ]; 27 | } -------------------------------------------------------------------------------- /assets/css/bootstrap-table.css: -------------------------------------------------------------------------------- 1 | .table { 2 | margin-bottom: 0 !important; 3 | border-bottom: 1px solid #dddddd; 4 | border-collapse: collapse !important; 5 | border-radius: 1px; 6 | } 7 | 8 | .fixed-table-container { 9 | position: relative; 10 | clear: both; 11 | border: 1px solid #dddddd; 12 | border-radius: 4px; 13 | -webkit-border-radius: 4px; 14 | -moz-border-radius: 4px; 15 | } 16 | 17 | .fixed-table-header { 18 | overflow: hidden; 19 | border-radius: 4px 4px 0 0; 20 | -webkit-border-radius: 4px 4px 0 0; 21 | -moz-border-radius: 4px 4px 0 0; 22 | } 23 | 24 | .fixed-table-body { 25 | overflow-x: auto; 26 | overflow-y: auto; 27 | height: 100%; 28 | } 29 | 30 | .fixed-table-container table { 31 | width: 100%; 32 | } 33 | 34 | .fixed-table-container thead th { 35 | height: 0; 36 | padding: 0; 37 | margin: 0; 38 | border-left: 1px solid #dddddd; 39 | } 40 | 41 | .fixed-table-container thead th:first-child { 42 | border-left: none; 43 | } 44 | 45 | .fixed-table-container thead th .th-inner { 46 | padding: 8px; 47 | line-height: 24px; 48 | vertical-align: top; 49 | overflow: hidden; 50 | text-overflow: ellipsis; 51 | white-space: nowrap; 52 | } 53 | 54 | .fixed-table-container thead th .sortable { 55 | cursor: pointer; 56 | } 57 | 58 | .fixed-table-container tbody td { 59 | border-left: 1px solid #dddddd; 60 | } 61 | 62 | .fixed-table-container tbody tr:first-child td { 63 | border-top: none; 64 | } 65 | 66 | .fixed-table-container tbody td:first-child { 67 | border-left: none; 68 | } 69 | 70 | /* the same color with .active */ 71 | .fixed-table-container tbody .selected td { 72 | background-color: #f5f5f5; 73 | } 74 | 75 | .fixed-table-container .bs-checkbox { 76 | text-align: center; 77 | } 78 | 79 | .fixed-table-container .bs-checkbox .th-inner { 80 | padding: 8px 0; 81 | } 82 | 83 | .fixed-table-container input[type="radio"], 84 | .fixed-table-container input[type="checkbox"] { 85 | margin: 0 auto !important; 86 | } 87 | 88 | .fixed-table-container .no-records-found { 89 | text-align: center; 90 | } 91 | 92 | 93 | .fixed-table-pagination .pagination, 94 | .fixed-table-pagination .pagination-detail { 95 | margin-top: 10px; 96 | margin-bottom: 10px; 97 | } 98 | 99 | .fixed-table-pagination .pagination a { 100 | padding: 6px 12px; 101 | line-height: 1.428571429; 102 | } 103 | 104 | .fixed-table-pagination .pagination-info { 105 | line-height: 34px; 106 | margin-right: 5px; 107 | } 108 | 109 | .fixed-table-pagination .btn-group { 110 | position: relative; 111 | display: inline-block; 112 | vertical-align: middle; 113 | } 114 | 115 | .fixed-table-pagination .dropup .dropdown-menu { 116 | margin-bottom: 0; 117 | } 118 | 119 | .fixed-table-pagination .page-list { 120 | display: inline-block; 121 | } 122 | 123 | .fixed-table-toolbar .columns { 124 | margin-left: 5px; 125 | } 126 | 127 | .fixed-table-toolbar .columns label { 128 | display: block; 129 | padding: 3px 20px; 130 | clear: both; 131 | font-weight: normal; 132 | line-height: 1.428571429; 133 | } 134 | 135 | .fixed-table-toolbar .bars, 136 | .fixed-table-toolbar .search, 137 | .fixed-table-toolbar .columns { 138 | position: relative; 139 | margin-top: 10px; 140 | margin-bottom: 10px; 141 | line-height: 34px; 142 | } 143 | 144 | .fixed-table-pagination li.disabled a { 145 | pointer-events: none; 146 | cursor: default; 147 | } 148 | 149 | .fixed-table-loading { 150 | display: none; 151 | position: absolute; 152 | top: 42px; 153 | right: 0; 154 | bottom: 0; 155 | left: 0; 156 | z-index: 99; 157 | background-color: #fff; 158 | text-align: center; 159 | } 160 | 161 | .fixed-table-body .card-view .title { 162 | font-weight: bold; 163 | display: inline-block; 164 | min-width: 30%; 165 | text-align: left !important; 166 | } 167 | 168 | /* support bootstrap 2 */ 169 | .fixed-table-body thead th .th-inner { 170 | box-sizing: border-box; 171 | } 172 | 173 | .table th, .table td { 174 | vertical-align: middle; 175 | box-sizing: border-box; 176 | } 177 | 178 | .fixed-table-toolbar .dropdown-menu { 179 | text-align: left; 180 | max-height: 300px; 181 | overflow: auto; 182 | } 183 | 184 | .fixed-table-toolbar .btn-group>.btn-group { 185 | display: inline-block; 186 | margin-left: -1px !important; 187 | } 188 | 189 | .fixed-table-toolbar .btn-group>.btn-group>.btn { 190 | border-radius: 0; 191 | } 192 | 193 | .fixed-table-toolbar .btn-group>.btn-group:first-child>.btn { 194 | border-top-left-radius: 4px; 195 | border-bottom-left-radius: 4px; 196 | } 197 | 198 | .fixed-table-toolbar .btn-group>.btn-group:last-child>.btn { 199 | border-top-right-radius: 4px; 200 | border-bottom-right-radius: 4px; 201 | } 202 | 203 | .table>thead>tr>th { 204 | vertical-align: bottom; 205 | border-bottom: 2px solid #ddd; 206 | } 207 | 208 | /* support bootstrap 3 */ 209 | .table thead>tr>th { 210 | padding: 0; 211 | margin: 0; 212 | } 213 | 214 | .pull-right .dropdown-menu { 215 | right: 0; 216 | left: auto; 217 | } 218 | 219 | /* calculate scrollbar width */ 220 | p.fixed-table-scroll-inner { 221 | width: 100%; 222 | height: 200px; 223 | } 224 | 225 | div.fixed-table-scroll-outer { 226 | top: 0; 227 | left: 0; 228 | visibility: hidden; 229 | width: 200px; 230 | height: 150px; 231 | overflow: hidden; 232 | } -------------------------------------------------------------------------------- /assets/css/bootstrap-theme.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"bootstrap-theme.css","sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAeA;;;;;;EAME,0CAAA;EC+CA,6FAAA;EACQ,qFAAA;EC5DT;AFiBC;;;;;;;;;;;;EC0CA,0DAAA;EACQ,kDAAA;EC7CT;AFqCC;;EAEE,wBAAA;EEnCH;AFwCD;EG/CI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EA+B2C,2BAAA;EAA2B,oBAAA;EE7BvE;AFAC;;EAEE,2BAAA;EACA,8BAAA;EEEH;AFCC;;EAEE,2BAAA;EACA,uBAAA;EECH;AFEC;;EAEE,2BAAA;EACA,wBAAA;EEAH;AFeD;EGhDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0BD;AFxBC;;EAEE,2BAAA;EACA,8BAAA;EE0BH;AFvBC;;EAEE,2BAAA;EACA,uBAAA;EEyBH;AFtBC;;EAEE,2BAAA;EACA,wBAAA;EEwBH;AFRD;EGjDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EEkDD;AFhDC;;EAEE,2BAAA;EACA,8BAAA;EEkDH;AF/CC;;EAEE,2BAAA;EACA,uBAAA;EEiDH;AF9CC;;EAEE,2BAAA;EACA,wBAAA;EEgDH;AF/BD;EGlDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0ED;AFxEC;;EAEE,2BAAA;EACA,8BAAA;EE0EH;AFvEC;;EAEE,2BAAA;EACA,uBAAA;EEyEH;AFtEC;;EAEE,2BAAA;EACA,wBAAA;EEwEH;AFtDD;EGnDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EEkGD;AFhGC;;EAEE,2BAAA;EACA,8BAAA;EEkGH;AF/FC;;EAEE,2BAAA;EACA,uBAAA;EEiGH;AF9FC;;EAEE,2BAAA;EACA,wBAAA;EEgGH;AF7ED;EGpDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0HD;AFxHC;;EAEE,2BAAA;EACA,8BAAA;EE0HH;AFvHC;;EAEE,2BAAA;EACA,uBAAA;EEyHH;AFtHC;;EAEE,2BAAA;EACA,wBAAA;EEwHH;AF7FD;;ECbE,oDAAA;EACQ,4CAAA;EC8GT;AFvFD;;EGvEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHsEF,2BAAA;EE6FD;AF3FD;;;EG5EI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4EF,2BAAA;EEiGD;AFvFD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EJ4GA,oBAAA;EC9CA,6FAAA;EACQ,qFAAA;EC4IT;AFlGD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,0DAAA;EACQ,kDAAA;ECqJT;AF/FD;;EAEE,gDAAA;EEiGD;AF7FD;EG5GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EFgOD;AFrGD;EG5GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,yDAAA;EACQ,iDAAA;EC0KT;AF9GD;;EAWI,2CAAA;EEuGH;AFlGD;;;EAGE,kBAAA;EEoGD;AF1FD;EACE,+CAAA;EC3FA,4FAAA;EACQ,oFAAA;ECwLT;AFlFD;EGtJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EE8FD;AFzFD;EGvJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EEsGD;AFhGD;EGxJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EE8GD;AFvGD;EGzJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EEsHD;AFtGD;EGlKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED2QH;AFnGD;EG5KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDkRH;AFzGD;EG7KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDyRH;AF/GD;EG9KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDgSH;AFrHD;EG/KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDuSH;AF3HD;EGhLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8SH;AF9HD;EGnJI,+MAAA;EACA,0MAAA;EACA,uMAAA;EDoRH;AF1HD;EACE,oBAAA;EC/IA,oDAAA;EACQ,4CAAA;EC4QT;AF3HD;;;EAGE,+BAAA;EGpME,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHkMF,uBAAA;EEiID;AFvHD;ECjKE,mDAAA;EACQ,2CAAA;EC2RT;AFjHD;EG1NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8UH;AFvHD;EG3NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDqVH;AF7HD;EG5NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED4VH;AFnID;EG7NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDmWH;AFzID;EG9NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED0WH;AF/ID;EG/NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDiXH;AF9ID;EGvOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHqOF,uBAAA;EC1LA,2FAAA;EACQ,mFAAA;EC+UT","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &:disabled,\n &[disabled] {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n",null,"// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} -------------------------------------------------------------------------------- /assets/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-primary:disabled,.btn-primary[disabled]{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f3f3f3));background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-o-linear-gradient(top,#222 0,#282828 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#222),to(#282828));background-image:linear-gradient(to bottom,#222 0,#282828 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /assets/css/datepicker.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Datepicker for Bootstrap 3 | * 4 | * Copyright 2012 Stefan Petre 5 | * Improvements by Andrew Rowls 6 | * Licensed under the Apache License v2.0 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | */ 10 | .datepicker { 11 | padding: 4px; 12 | -webkit-border-radius: 4px; 13 | -moz-border-radius: 4px; 14 | border-radius: 4px; 15 | direction: ltr; 16 | /*.dow { 17 | border-top: 1px solid #ddd !important; 18 | }*/ 19 | } 20 | .datepicker-inline { 21 | width: 220px; 22 | } 23 | .datepicker.datepicker-rtl { 24 | direction: rtl; 25 | } 26 | .datepicker.datepicker-rtl table tr td span { 27 | float: right; 28 | } 29 | .datepicker-dropdown { 30 | top: 0; 31 | left: 0; 32 | } 33 | .datepicker-dropdown:before { 34 | content: ''; 35 | display: inline-block; 36 | border-left: 7px solid transparent; 37 | border-right: 7px solid transparent; 38 | border-bottom: 7px solid #ccc; 39 | border-top: 0; 40 | border-bottom-color: rgba(0, 0, 0, 0.2); 41 | position: absolute; 42 | } 43 | .datepicker-dropdown:after { 44 | content: ''; 45 | display: inline-block; 46 | border-left: 6px solid transparent; 47 | border-right: 6px solid transparent; 48 | border-bottom: 6px solid #ffffff; 49 | border-top: 0; 50 | position: absolute; 51 | } 52 | .datepicker-dropdown.datepicker-orient-left:before { 53 | left: 6px; 54 | } 55 | .datepicker-dropdown.datepicker-orient-left:after { 56 | left: 7px; 57 | } 58 | .datepicker-dropdown.datepicker-orient-right:before { 59 | right: 6px; 60 | } 61 | .datepicker-dropdown.datepicker-orient-right:after { 62 | right: 7px; 63 | } 64 | .datepicker-dropdown.datepicker-orient-top:before { 65 | top: -7px; 66 | } 67 | .datepicker-dropdown.datepicker-orient-top:after { 68 | top: -6px; 69 | } 70 | .datepicker-dropdown.datepicker-orient-bottom:before { 71 | bottom: -7px; 72 | border-bottom: 0; 73 | border-top: 7px solid #999; 74 | } 75 | .datepicker-dropdown.datepicker-orient-bottom:after { 76 | bottom: -6px; 77 | border-bottom: 0; 78 | border-top: 6px solid #ffffff; 79 | } 80 | .datepicker > div { 81 | display: none; 82 | } 83 | .datepicker.days div.datepicker-days { 84 | display: block; 85 | } 86 | .datepicker.months div.datepicker-months { 87 | display: block; 88 | } 89 | .datepicker.years div.datepicker-years { 90 | display: block; 91 | } 92 | .datepicker table { 93 | margin: 0; 94 | -webkit-touch-callout: none; 95 | -webkit-user-select: none; 96 | -khtml-user-select: none; 97 | -moz-user-select: none; 98 | -ms-user-select: none; 99 | user-select: none; 100 | } 101 | .datepicker td, 102 | .datepicker th { 103 | text-align: center; 104 | width: 20px; 105 | height: 20px; 106 | -webkit-border-radius: 4px; 107 | -moz-border-radius: 4px; 108 | border-radius: 4px; 109 | border: none; 110 | } 111 | .table-striped .datepicker table tr td, 112 | .table-striped .datepicker table tr th { 113 | background-color: transparent; 114 | } 115 | .datepicker table tr td.day:hover, 116 | .datepicker table tr td.day.focused { 117 | background: #eeeeee; 118 | cursor: pointer; 119 | } 120 | .datepicker table tr td.old, 121 | .datepicker table tr td.new { 122 | color: #999999; 123 | } 124 | .datepicker table tr td.disabled, 125 | .datepicker table tr td.disabled:hover { 126 | background: none; 127 | color: #999999; 128 | cursor: default; 129 | } 130 | .datepicker table tr td.today, 131 | .datepicker table tr td.today:hover, 132 | .datepicker table tr td.today.disabled, 133 | .datepicker table tr td.today.disabled:hover { 134 | background-color: #fde19a; 135 | background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); 136 | background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); 137 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); 138 | background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); 139 | background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); 140 | background-image: linear-gradient(top, #fdd49a, #fdf59a); 141 | background-repeat: repeat-x; 142 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); 143 | border-color: #fdf59a #fdf59a #fbed50; 144 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 145 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 146 | color: #000; 147 | } 148 | .datepicker table tr td.today:hover, 149 | .datepicker table tr td.today:hover:hover, 150 | .datepicker table tr td.today.disabled:hover, 151 | .datepicker table tr td.today.disabled:hover:hover, 152 | .datepicker table tr td.today:active, 153 | .datepicker table tr td.today:hover:active, 154 | .datepicker table tr td.today.disabled:active, 155 | .datepicker table tr td.today.disabled:hover:active, 156 | .datepicker table tr td.today.active, 157 | .datepicker table tr td.today:hover.active, 158 | .datepicker table tr td.today.disabled.active, 159 | .datepicker table tr td.today.disabled:hover.active, 160 | .datepicker table tr td.today.disabled, 161 | .datepicker table tr td.today:hover.disabled, 162 | .datepicker table tr td.today.disabled.disabled, 163 | .datepicker table tr td.today.disabled:hover.disabled, 164 | .datepicker table tr td.today[disabled], 165 | .datepicker table tr td.today:hover[disabled], 166 | .datepicker table tr td.today.disabled[disabled], 167 | .datepicker table tr td.today.disabled:hover[disabled] { 168 | background-color: #fdf59a; 169 | } 170 | .datepicker table tr td.today:active, 171 | .datepicker table tr td.today:hover:active, 172 | .datepicker table tr td.today.disabled:active, 173 | .datepicker table tr td.today.disabled:hover:active, 174 | .datepicker table tr td.today.active, 175 | .datepicker table tr td.today:hover.active, 176 | .datepicker table tr td.today.disabled.active, 177 | .datepicker table tr td.today.disabled:hover.active { 178 | background-color: #fbf069 \9; 179 | } 180 | .datepicker table tr td.today:hover:hover { 181 | color: #000; 182 | } 183 | .datepicker table tr td.today.active:hover { 184 | color: #fff; 185 | } 186 | .datepicker table tr td.range, 187 | .datepicker table tr td.range:hover, 188 | .datepicker table tr td.range.disabled, 189 | .datepicker table tr td.range.disabled:hover { 190 | background: #eeeeee; 191 | -webkit-border-radius: 0; 192 | -moz-border-radius: 0; 193 | border-radius: 0; 194 | } 195 | .datepicker table tr td.range.today, 196 | .datepicker table tr td.range.today:hover, 197 | .datepicker table tr td.range.today.disabled, 198 | .datepicker table tr td.range.today.disabled:hover { 199 | background-color: #f3d17a; 200 | background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a); 201 | background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a); 202 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); 203 | background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a); 204 | background-image: -o-linear-gradient(top, #f3c17a, #f3e97a); 205 | background-image: linear-gradient(top, #f3c17a, #f3e97a); 206 | background-repeat: repeat-x; 207 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); 208 | border-color: #f3e97a #f3e97a #edde34; 209 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 210 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 211 | -webkit-border-radius: 0; 212 | -moz-border-radius: 0; 213 | border-radius: 0; 214 | } 215 | .datepicker table tr td.range.today:hover, 216 | .datepicker table tr td.range.today:hover:hover, 217 | .datepicker table tr td.range.today.disabled:hover, 218 | .datepicker table tr td.range.today.disabled:hover:hover, 219 | .datepicker table tr td.range.today:active, 220 | .datepicker table tr td.range.today:hover:active, 221 | .datepicker table tr td.range.today.disabled:active, 222 | .datepicker table tr td.range.today.disabled:hover:active, 223 | .datepicker table tr td.range.today.active, 224 | .datepicker table tr td.range.today:hover.active, 225 | .datepicker table tr td.range.today.disabled.active, 226 | .datepicker table tr td.range.today.disabled:hover.active, 227 | .datepicker table tr td.range.today.disabled, 228 | .datepicker table tr td.range.today:hover.disabled, 229 | .datepicker table tr td.range.today.disabled.disabled, 230 | .datepicker table tr td.range.today.disabled:hover.disabled, 231 | .datepicker table tr td.range.today[disabled], 232 | .datepicker table tr td.range.today:hover[disabled], 233 | .datepicker table tr td.range.today.disabled[disabled], 234 | .datepicker table tr td.range.today.disabled:hover[disabled] { 235 | background-color: #f3e97a; 236 | } 237 | .datepicker table tr td.range.today:active, 238 | .datepicker table tr td.range.today:hover:active, 239 | .datepicker table tr td.range.today.disabled:active, 240 | .datepicker table tr td.range.today.disabled:hover:active, 241 | .datepicker table tr td.range.today.active, 242 | .datepicker table tr td.range.today:hover.active, 243 | .datepicker table tr td.range.today.disabled.active, 244 | .datepicker table tr td.range.today.disabled:hover.active { 245 | background-color: #efe24b \9; 246 | } 247 | .datepicker table tr td.selected, 248 | .datepicker table tr td.selected:hover, 249 | .datepicker table tr td.selected.disabled, 250 | .datepicker table tr td.selected.disabled:hover { 251 | background-color: #9e9e9e; 252 | background-image: -moz-linear-gradient(top, #b3b3b3, #808080); 253 | background-image: -ms-linear-gradient(top, #b3b3b3, #808080); 254 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); 255 | background-image: -webkit-linear-gradient(top, #b3b3b3, #808080); 256 | background-image: -o-linear-gradient(top, #b3b3b3, #808080); 257 | background-image: linear-gradient(top, #b3b3b3, #808080); 258 | background-repeat: repeat-x; 259 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); 260 | border-color: #808080 #808080 #595959; 261 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 262 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 263 | color: #fff; 264 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 265 | } 266 | .datepicker table tr td.selected:hover, 267 | .datepicker table tr td.selected:hover:hover, 268 | .datepicker table tr td.selected.disabled:hover, 269 | .datepicker table tr td.selected.disabled:hover:hover, 270 | .datepicker table tr td.selected:active, 271 | .datepicker table tr td.selected:hover:active, 272 | .datepicker table tr td.selected.disabled:active, 273 | .datepicker table tr td.selected.disabled:hover:active, 274 | .datepicker table tr td.selected.active, 275 | .datepicker table tr td.selected:hover.active, 276 | .datepicker table tr td.selected.disabled.active, 277 | .datepicker table tr td.selected.disabled:hover.active, 278 | .datepicker table tr td.selected.disabled, 279 | .datepicker table tr td.selected:hover.disabled, 280 | .datepicker table tr td.selected.disabled.disabled, 281 | .datepicker table tr td.selected.disabled:hover.disabled, 282 | .datepicker table tr td.selected[disabled], 283 | .datepicker table tr td.selected:hover[disabled], 284 | .datepicker table tr td.selected.disabled[disabled], 285 | .datepicker table tr td.selected.disabled:hover[disabled] { 286 | background-color: #808080; 287 | } 288 | .datepicker table tr td.selected:active, 289 | .datepicker table tr td.selected:hover:active, 290 | .datepicker table tr td.selected.disabled:active, 291 | .datepicker table tr td.selected.disabled:hover:active, 292 | .datepicker table tr td.selected.active, 293 | .datepicker table tr td.selected:hover.active, 294 | .datepicker table tr td.selected.disabled.active, 295 | .datepicker table tr td.selected.disabled:hover.active { 296 | background-color: #666666 \9; 297 | } 298 | .datepicker table tr td.active, 299 | .datepicker table tr td.active:hover, 300 | .datepicker table tr td.active.disabled, 301 | .datepicker table tr td.active.disabled:hover { 302 | background-color: #006dcc; 303 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc); 304 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc); 305 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 306 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); 307 | background-image: -o-linear-gradient(top, #0088cc, #0044cc); 308 | background-image: linear-gradient(top, #0088cc, #0044cc); 309 | background-repeat: repeat-x; 310 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 311 | border-color: #0044cc #0044cc #002a80; 312 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 313 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 314 | color: #fff; 315 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 316 | } 317 | .datepicker table tr td.active:hover, 318 | .datepicker table tr td.active:hover:hover, 319 | .datepicker table tr td.active.disabled:hover, 320 | .datepicker table tr td.active.disabled:hover:hover, 321 | .datepicker table tr td.active:active, 322 | .datepicker table tr td.active:hover:active, 323 | .datepicker table tr td.active.disabled:active, 324 | .datepicker table tr td.active.disabled:hover:active, 325 | .datepicker table tr td.active.active, 326 | .datepicker table tr td.active:hover.active, 327 | .datepicker table tr td.active.disabled.active, 328 | .datepicker table tr td.active.disabled:hover.active, 329 | .datepicker table tr td.active.disabled, 330 | .datepicker table tr td.active:hover.disabled, 331 | .datepicker table tr td.active.disabled.disabled, 332 | .datepicker table tr td.active.disabled:hover.disabled, 333 | .datepicker table tr td.active[disabled], 334 | .datepicker table tr td.active:hover[disabled], 335 | .datepicker table tr td.active.disabled[disabled], 336 | .datepicker table tr td.active.disabled:hover[disabled] { 337 | background-color: #0044cc; 338 | } 339 | .datepicker table tr td.active:active, 340 | .datepicker table tr td.active:hover:active, 341 | .datepicker table tr td.active.disabled:active, 342 | .datepicker table tr td.active.disabled:hover:active, 343 | .datepicker table tr td.active.active, 344 | .datepicker table tr td.active:hover.active, 345 | .datepicker table tr td.active.disabled.active, 346 | .datepicker table tr td.active.disabled:hover.active { 347 | background-color: #003399 \9; 348 | } 349 | .datepicker table tr td span { 350 | display: block; 351 | width: 23%; 352 | height: 54px; 353 | line-height: 54px; 354 | float: left; 355 | margin: 1%; 356 | cursor: pointer; 357 | -webkit-border-radius: 4px; 358 | -moz-border-radius: 4px; 359 | border-radius: 4px; 360 | } 361 | .datepicker table tr td span:hover { 362 | background: #eeeeee; 363 | } 364 | .datepicker table tr td span.disabled, 365 | .datepicker table tr td span.disabled:hover { 366 | background: none; 367 | color: #999999; 368 | cursor: default; 369 | } 370 | .datepicker table tr td span.active, 371 | .datepicker table tr td span.active:hover, 372 | .datepicker table tr td span.active.disabled, 373 | .datepicker table tr td span.active.disabled:hover { 374 | background-color: #006dcc; 375 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc); 376 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc); 377 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 378 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); 379 | background-image: -o-linear-gradient(top, #0088cc, #0044cc); 380 | background-image: linear-gradient(top, #0088cc, #0044cc); 381 | background-repeat: repeat-x; 382 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 383 | border-color: #0044cc #0044cc #002a80; 384 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 385 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 386 | color: #fff; 387 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 388 | } 389 | .datepicker table tr td span.active:hover, 390 | .datepicker table tr td span.active:hover:hover, 391 | .datepicker table tr td span.active.disabled:hover, 392 | .datepicker table tr td span.active.disabled:hover:hover, 393 | .datepicker table tr td span.active:active, 394 | .datepicker table tr td span.active:hover:active, 395 | .datepicker table tr td span.active.disabled:active, 396 | .datepicker table tr td span.active.disabled:hover:active, 397 | .datepicker table tr td span.active.active, 398 | .datepicker table tr td span.active:hover.active, 399 | .datepicker table tr td span.active.disabled.active, 400 | .datepicker table tr td span.active.disabled:hover.active, 401 | .datepicker table tr td span.active.disabled, 402 | .datepicker table tr td span.active:hover.disabled, 403 | .datepicker table tr td span.active.disabled.disabled, 404 | .datepicker table tr td span.active.disabled:hover.disabled, 405 | .datepicker table tr td span.active[disabled], 406 | .datepicker table tr td span.active:hover[disabled], 407 | .datepicker table tr td span.active.disabled[disabled], 408 | .datepicker table tr td span.active.disabled:hover[disabled] { 409 | background-color: #0044cc; 410 | } 411 | .datepicker table tr td span.active:active, 412 | .datepicker table tr td span.active:hover:active, 413 | .datepicker table tr td span.active.disabled:active, 414 | .datepicker table tr td span.active.disabled:hover:active, 415 | .datepicker table tr td span.active.active, 416 | .datepicker table tr td span.active:hover.active, 417 | .datepicker table tr td span.active.disabled.active, 418 | .datepicker table tr td span.active.disabled:hover.active { 419 | background-color: #003399 \9; 420 | } 421 | .datepicker table tr td span.old, 422 | .datepicker table tr td span.new { 423 | color: #999999; 424 | } 425 | .datepicker th.datepicker-switch { 426 | width: 145px; 427 | } 428 | .datepicker thead tr:first-child th, 429 | .datepicker tfoot tr th { 430 | cursor: pointer; 431 | } 432 | .datepicker thead tr:first-child th:hover, 433 | .datepicker tfoot tr th:hover { 434 | background: #eeeeee; 435 | } 436 | .datepicker .cw { 437 | font-size: 10px; 438 | width: 12px; 439 | padding: 0 2px 0 5px; 440 | vertical-align: middle; 441 | } 442 | .datepicker thead tr:first-child th.cw { 443 | cursor: default; 444 | background-color: transparent; 445 | } 446 | .input-append.date .add-on i, 447 | .input-prepend.date .add-on i { 448 | cursor: pointer; 449 | width: 16px; 450 | height: 16px; 451 | } 452 | .input-daterange input { 453 | text-align: center; 454 | } 455 | .input-daterange input:first-child { 456 | -webkit-border-radius: 3px 0 0 3px; 457 | -moz-border-radius: 3px 0 0 3px; 458 | border-radius: 3px 0 0 3px; 459 | } 460 | .input-daterange input:last-child { 461 | -webkit-border-radius: 0 3px 3px 0; 462 | -moz-border-radius: 0 3px 3px 0; 463 | border-radius: 0 3px 3px 0; 464 | } 465 | .input-daterange .add-on { 466 | display: inline-block; 467 | width: auto; 468 | min-width: 16px; 469 | height: 20px; 470 | padding: 4px 5px; 471 | font-weight: normal; 472 | line-height: 20px; 473 | text-align: center; 474 | text-shadow: 0 1px 0 #ffffff; 475 | vertical-align: middle; 476 | background-color: #eeeeee; 477 | border: 1px solid #ccc; 478 | margin-left: -5px; 479 | margin-right: -5px; 480 | } 481 | .datepicker.dropdown-menu { 482 | position: absolute; 483 | top: 100%; 484 | left: 0; 485 | z-index: 1000; 486 | float: left; 487 | display: none; 488 | min-width: 160px; 489 | list-style: none; 490 | background-color: #ffffff; 491 | border: 1px solid #ccc; 492 | border: 1px solid rgba(0, 0, 0, 0.2); 493 | -webkit-border-radius: 5px; 494 | -moz-border-radius: 5px; 495 | border-radius: 5px; 496 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 497 | -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 498 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 499 | -webkit-background-clip: padding-box; 500 | -moz-background-clip: padding; 501 | background-clip: padding-box; 502 | *border-right-width: 2px; 503 | *border-bottom-width: 2px; 504 | color: #333333; 505 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 506 | font-size: 13px; 507 | line-height: 20px; 508 | } 509 | .datepicker.dropdown-menu th, 510 | .datepicker.datepicker-inline th, 511 | .datepicker.dropdown-menu td, 512 | .datepicker.datepicker-inline td { 513 | padding: 4px 5px; 514 | } 515 | -------------------------------------------------------------------------------- /assets/css/default.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Original highlight.js style (c) Ivan Sagalaev 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | background: #F0F0F0; 12 | } 13 | 14 | 15 | /* Base color: saturation 0; */ 16 | 17 | .hljs, 18 | .hljs-subst { 19 | color: #444; 20 | } 21 | 22 | .hljs-comment { 23 | color: #888888; 24 | } 25 | 26 | .hljs-keyword, 27 | .hljs-attribute, 28 | .hljs-selector-tag, 29 | .hljs-meta-keyword, 30 | .hljs-doctag, 31 | .hljs-name { 32 | font-weight: bold; 33 | } 34 | 35 | 36 | /* User color: hue: 0 */ 37 | 38 | .hljs-type, 39 | .hljs-string, 40 | .hljs-number, 41 | .hljs-selector-id, 42 | .hljs-selector-class, 43 | .hljs-quote, 44 | .hljs-template-tag, 45 | .hljs-deletion { 46 | color: #880000; 47 | } 48 | 49 | .hljs-title, 50 | .hljs-section { 51 | color: #880000; 52 | font-weight: bold; 53 | } 54 | 55 | .hljs-regexp, 56 | .hljs-symbol, 57 | .hljs-variable, 58 | .hljs-template-variable, 59 | .hljs-link, 60 | .hljs-selector-attr, 61 | .hljs-selector-pseudo { 62 | color: #BC6060; 63 | } 64 | 65 | 66 | /* Language color: hue: 90; */ 67 | 68 | .hljs-literal { 69 | color: #78A960; 70 | } 71 | 72 | .hljs-built_in, 73 | .hljs-bullet, 74 | .hljs-code, 75 | .hljs-addition { 76 | color: #397300; 77 | } 78 | 79 | 80 | /* Meta color: hue: 200 */ 81 | 82 | .hljs-meta { 83 | color: #1f7199; 84 | } 85 | 86 | .hljs-meta-string { 87 | color: #4d99bf; 88 | } 89 | 90 | 91 | /* Misc effects */ 92 | 93 | .hljs-emphasis { 94 | font-style: italic; 95 | } 96 | 97 | .hljs-strong { 98 | font-weight: bold; 99 | } 100 | -------------------------------------------------------------------------------- /assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /assets/js/chart-data.js: -------------------------------------------------------------------------------- 1 | var randomScalingFactor = function(){ return Math.round(Math.random()*1000)}; 2 | 3 | var lineChartData = { 4 | labels : ["January","February","March","April","May","June","July"], 5 | datasets : [ 6 | { 7 | label: "My First dataset", 8 | fillColor : "rgba(220,220,220,0.2)", 9 | strokeColor : "rgba(220,220,220,1)", 10 | pointColor : "rgba(220,220,220,1)", 11 | pointStrokeColor : "#fff", 12 | pointHighlightFill : "#fff", 13 | pointHighlightStroke : "rgba(220,220,220,1)", 14 | data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()] 15 | }, 16 | { 17 | label: "My Second dataset", 18 | fillColor : "rgba(48, 164, 255, 0.2)", 19 | strokeColor : "rgba(48, 164, 255, 1)", 20 | pointColor : "rgba(48, 164, 255, 1)", 21 | pointStrokeColor : "#fff", 22 | pointHighlightFill : "#fff", 23 | pointHighlightStroke : "rgba(48, 164, 255, 1)", 24 | data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()] 25 | } 26 | ] 27 | 28 | } 29 | 30 | var barChartData = { 31 | labels : ["January","February","March","April","May","June","July"], 32 | datasets : [ 33 | { 34 | fillColor : "rgba(220,220,220,0.5)", 35 | strokeColor : "rgba(220,220,220,0.8)", 36 | highlightFill: "rgba(220,220,220,0.75)", 37 | highlightStroke: "rgba(220,220,220,1)", 38 | data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()] 39 | }, 40 | { 41 | fillColor : "rgba(48, 164, 255, 0.2)", 42 | strokeColor : "rgba(48, 164, 255, 0.8)", 43 | highlightFill : "rgba(48, 164, 255, 0.75)", 44 | highlightStroke : "rgba(48, 164, 255, 1)", 45 | data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()] 46 | } 47 | ] 48 | 49 | } 50 | 51 | var pieData = [ 52 | { 53 | value: 300, 54 | color:"#30a5ff", 55 | highlight: "#62b9fb", 56 | label: "Blue" 57 | }, 58 | { 59 | value: 50, 60 | color: "#ffb53e", 61 | highlight: "#fac878", 62 | label: "Orange" 63 | }, 64 | { 65 | value: 100, 66 | color: "#1ebfae", 67 | highlight: "#3cdfce", 68 | label: "Teal" 69 | }, 70 | { 71 | value: 120, 72 | color: "#f9243f", 73 | highlight: "#f6495f", 74 | label: "Red" 75 | } 76 | 77 | ]; 78 | 79 | var doughnutData = [ 80 | { 81 | value: 300, 82 | color:"#30a5ff", 83 | highlight: "#62b9fb", 84 | label: "Blue" 85 | }, 86 | { 87 | value: 50, 88 | color: "#ffb53e", 89 | highlight: "#fac878", 90 | label: "Orange" 91 | }, 92 | { 93 | value: 100, 94 | color: "#1ebfae", 95 | highlight: "#3cdfce", 96 | label: "Teal" 97 | }, 98 | { 99 | value: 120, 100 | color: "#f9243f", 101 | highlight: "#f6495f", 102 | label: "Red" 103 | } 104 | 105 | ]; 106 | 107 | window.onload = function(){ 108 | var chart1 = document.getElementById("line-chart").getContext("2d"); 109 | window.myLine = new Chart(chart1).Line(lineChartData, { 110 | responsive: true 111 | }); 112 | var chart2 = document.getElementById("bar-chart").getContext("2d"); 113 | window.myBar = new Chart(chart2).Bar(barChartData, { 114 | responsive : true 115 | }); 116 | var chart3 = document.getElementById("doughnut-chart").getContext("2d"); 117 | window.myDoughnut = new Chart(chart3).Doughnut(doughnutData, {responsive : true 118 | }); 119 | var chart4 = document.getElementById("pie-chart").getContext("2d"); 120 | window.myPie = new Chart(chart4).Pie(pieData, {responsive : true 121 | }); 122 | 123 | }; -------------------------------------------------------------------------------- /assets/js/easypiechart-data.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | $('#easypiechart-teal').easyPieChart({ 3 | scaleColor: false, 4 | barColor: '#1ebfae' 5 | }); 6 | }); 7 | 8 | $(function() { 9 | $('#easypiechart-orange').easyPieChart({ 10 | scaleColor: false, 11 | barColor: '#ffb53e' 12 | }); 13 | }); 14 | 15 | $(function() { 16 | $('#easypiechart-red').easyPieChart({ 17 | scaleColor: false, 18 | barColor: '#f9243f' 19 | }); 20 | }); 21 | 22 | $(function() { 23 | $('#easypiechart-blue').easyPieChart({ 24 | scaleColor: false, 25 | barColor: '#30a5ff' 26 | }); 27 | }); 28 | 29 | $('#calendar').datepicker({ 30 | }); 31 | -------------------------------------------------------------------------------- /assets/js/easypiechart.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * easyPieChart 3 | * Lightweight plugin to render simple, animated and retina optimized pie charts 4 | * 5 | * @license 6 | * @author Robert Fleischmann (http://robert-fleischmann.de) 7 | * @version 2.1.5 8 | **/ 9 | 10 | (function(root, factory) { 11 | if(typeof exports === 'object') { 12 | module.exports = factory(require('jquery')); 13 | } 14 | else if(typeof define === 'function' && define.amd) { 15 | define(['jquery'], factory); 16 | } 17 | else { 18 | factory(root.jQuery); 19 | } 20 | }(this, function($) { 21 | 22 | /** 23 | * Renderer to render the chart on a canvas object 24 | * @param {DOMElement} el DOM element to host the canvas (root of the plugin) 25 | * @param {object} options options object of the plugin 26 | */ 27 | var CanvasRenderer = function(el, options) { 28 | var cachedBackground; 29 | var canvas = document.createElement('canvas'); 30 | 31 | el.appendChild(canvas); 32 | 33 | if (typeof(G_vmlCanvasManager) !== 'undefined') { 34 | G_vmlCanvasManager.initElement(canvas); 35 | } 36 | 37 | var ctx = canvas.getContext('2d'); 38 | 39 | canvas.width = canvas.height = options.size; 40 | 41 | // canvas on retina devices 42 | var scaleBy = 1; 43 | if (window.devicePixelRatio > 1) { 44 | scaleBy = window.devicePixelRatio; 45 | canvas.style.width = canvas.style.height = [options.size, 'px'].join(''); 46 | canvas.width = canvas.height = options.size * scaleBy; 47 | ctx.scale(scaleBy, scaleBy); 48 | } 49 | 50 | // move 0,0 coordinates to the center 51 | ctx.translate(options.size / 2, options.size / 2); 52 | 53 | // rotate canvas -90deg 54 | ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); 55 | 56 | var radius = (options.size - options.lineWidth) / 2; 57 | if (options.scaleColor && options.scaleLength) { 58 | radius -= options.scaleLength + 2; // 2 is the distance between scale and bar 59 | } 60 | 61 | // IE polyfill for Date 62 | Date.now = Date.now || function() { 63 | return +(new Date()); 64 | }; 65 | 66 | /** 67 | * Draw a circle around the center of the canvas 68 | * @param {strong} color Valid CSS color string 69 | * @param {number} lineWidth Width of the line in px 70 | * @param {number} percent Percentage to draw (float between -1 and 1) 71 | */ 72 | var drawCircle = function(color, lineWidth, percent) { 73 | percent = Math.min(Math.max(-1, percent || 0), 1); 74 | var isNegative = percent <= 0 ? true : false; 75 | 76 | ctx.beginPath(); 77 | ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative); 78 | 79 | ctx.strokeStyle = color; 80 | ctx.lineWidth = lineWidth; 81 | 82 | ctx.stroke(); 83 | }; 84 | 85 | /** 86 | * Draw the scale of the chart 87 | */ 88 | var drawScale = function() { 89 | var offset; 90 | var length; 91 | 92 | ctx.lineWidth = 1; 93 | ctx.fillStyle = options.scaleColor; 94 | 95 | ctx.save(); 96 | for (var i = 24; i > 0; --i) { 97 | if (i % 6 === 0) { 98 | length = options.scaleLength; 99 | offset = 0; 100 | } else { 101 | length = options.scaleLength * 0.6; 102 | offset = options.scaleLength - length; 103 | } 104 | ctx.fillRect(-options.size/2 + offset, 0, length, 1); 105 | ctx.rotate(Math.PI / 12); 106 | } 107 | ctx.restore(); 108 | }; 109 | 110 | /** 111 | * Request animation frame wrapper with polyfill 112 | * @return {function} Request animation frame method or timeout fallback 113 | */ 114 | var reqAnimationFrame = (function() { 115 | return window.requestAnimationFrame || 116 | window.webkitRequestAnimationFrame || 117 | window.mozRequestAnimationFrame || 118 | function(callback) { 119 | window.setTimeout(callback, 1000 / 60); 120 | }; 121 | }()); 122 | 123 | /** 124 | * Draw the background of the plugin including the scale and the track 125 | */ 126 | var drawBackground = function() { 127 | if(options.scaleColor) drawScale(); 128 | if(options.trackColor) drawCircle(options.trackColor, options.lineWidth, 1); 129 | }; 130 | 131 | /** 132 | * Canvas accessor 133 | */ 134 | this.getCanvas = function() { 135 | return canvas; 136 | }; 137 | 138 | /** 139 | * Canvas 2D context 'ctx' accessor 140 | */ 141 | this.getCtx = function() { 142 | return ctx; 143 | }; 144 | 145 | /** 146 | * Clear the complete canvas 147 | */ 148 | this.clear = function() { 149 | ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size); 150 | }; 151 | 152 | /** 153 | * Draw the complete chart 154 | * @param {number} percent Percent shown by the chart between -100 and 100 155 | */ 156 | this.draw = function(percent) { 157 | // do we need to render a background 158 | if (!!options.scaleColor || !!options.trackColor) { 159 | // getImageData and putImageData are supported 160 | if (ctx.getImageData && ctx.putImageData) { 161 | if (!cachedBackground) { 162 | drawBackground(); 163 | cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy); 164 | } else { 165 | ctx.putImageData(cachedBackground, 0, 0); 166 | } 167 | } else { 168 | this.clear(); 169 | drawBackground(); 170 | } 171 | } else { 172 | this.clear(); 173 | } 174 | 175 | ctx.lineCap = options.lineCap; 176 | 177 | // if barcolor is a function execute it and pass the percent as a value 178 | var color; 179 | if (typeof(options.barColor) === 'function') { 180 | color = options.barColor(percent); 181 | } else { 182 | color = options.barColor; 183 | } 184 | 185 | // draw bar 186 | drawCircle(color, options.lineWidth, percent / 100); 187 | }.bind(this); 188 | 189 | /** 190 | * Animate from some percent to some other percentage 191 | * @param {number} from Starting percentage 192 | * @param {number} to Final percentage 193 | */ 194 | this.animate = function(from, to) { 195 | var startTime = Date.now(); 196 | options.onStart(from, to); 197 | var animation = function() { 198 | var process = Math.min(Date.now() - startTime, options.animate.duration); 199 | var currentValue = options.easing(this, process, from, to - from, options.animate.duration); 200 | this.draw(currentValue); 201 | options.onStep(from, to, currentValue); 202 | if (process >= options.animate.duration) { 203 | options.onStop(from, to); 204 | } else { 205 | reqAnimationFrame(animation); 206 | } 207 | }.bind(this); 208 | 209 | reqAnimationFrame(animation); 210 | }.bind(this); 211 | }; 212 | 213 | var EasyPieChart = function(el, opts) { 214 | var defaultOptions = { 215 | barColor: '#ef1e25', 216 | trackColor: '#f9f9f9', 217 | scaleColor: '#dfe0e0', 218 | scaleLength: 5, 219 | lineCap: 'round', 220 | lineWidth: 3, 221 | size: 110, 222 | rotate: 0, 223 | animate: { 224 | duration: 1000, 225 | enabled: true 226 | }, 227 | easing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/ 228 | t = t / (d/2); 229 | if (t < 1) { 230 | return c / 2 * t * t + b; 231 | } 232 | return -c/2 * ((--t)*(t-2) - 1) + b; 233 | }, 234 | onStart: function(from, to) { 235 | return; 236 | }, 237 | onStep: function(from, to, currentValue) { 238 | return; 239 | }, 240 | onStop: function(from, to) { 241 | return; 242 | } 243 | }; 244 | 245 | // detect present renderer 246 | if (typeof(CanvasRenderer) !== 'undefined') { 247 | defaultOptions.renderer = CanvasRenderer; 248 | } else if (typeof(SVGRenderer) !== 'undefined') { 249 | defaultOptions.renderer = SVGRenderer; 250 | } else { 251 | throw new Error('Please load either the SVG- or the CanvasRenderer'); 252 | } 253 | 254 | var options = {}; 255 | var currentValue = 0; 256 | 257 | /** 258 | * Initialize the plugin by creating the options object and initialize rendering 259 | */ 260 | var init = function() { 261 | this.el = el; 262 | this.options = options; 263 | 264 | // merge user options into default options 265 | for (var i in defaultOptions) { 266 | if (defaultOptions.hasOwnProperty(i)) { 267 | options[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i]; 268 | if (typeof(options[i]) === 'function') { 269 | options[i] = options[i].bind(this); 270 | } 271 | } 272 | } 273 | 274 | // check for jQuery easing 275 | if (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) { 276 | options.easing = jQuery.easing[options.easing]; 277 | } else { 278 | options.easing = defaultOptions.easing; 279 | } 280 | 281 | // process earlier animate option to avoid bc breaks 282 | if (typeof(options.animate) === 'number') { 283 | options.animate = { 284 | duration: options.animate, 285 | enabled: true 286 | }; 287 | } 288 | 289 | if (typeof(options.animate) === 'boolean' && !options.animate) { 290 | options.animate = { 291 | duration: 1000, 292 | enabled: options.animate 293 | }; 294 | } 295 | 296 | // create renderer 297 | this.renderer = new options.renderer(el, options); 298 | 299 | // initial draw 300 | this.renderer.draw(currentValue); 301 | 302 | // initial update 303 | if (el.dataset && el.dataset.percent) { 304 | this.update(parseFloat(el.dataset.percent)); 305 | } else if (el.getAttribute && el.getAttribute('data-percent')) { 306 | this.update(parseFloat(el.getAttribute('data-percent'))); 307 | } 308 | }.bind(this); 309 | 310 | /** 311 | * Update the value of the chart 312 | * @param {number} newValue Number between 0 and 100 313 | * @return {object} Instance of the plugin for method chaining 314 | */ 315 | this.update = function(newValue) { 316 | newValue = parseFloat(newValue); 317 | if (options.animate.enabled) { 318 | this.renderer.animate(currentValue, newValue); 319 | } else { 320 | this.renderer.draw(newValue); 321 | } 322 | currentValue = newValue; 323 | return this; 324 | }.bind(this); 325 | 326 | /** 327 | * Disable animation 328 | * @return {object} Instance of the plugin for method chaining 329 | */ 330 | this.disableAnimation = function() { 331 | options.animate.enabled = false; 332 | return this; 333 | }; 334 | 335 | /** 336 | * Enable animation 337 | * @return {object} Instance of the plugin for method chaining 338 | */ 339 | this.enableAnimation = function() { 340 | options.animate.enabled = true; 341 | return this; 342 | }; 343 | 344 | init(); 345 | }; 346 | 347 | $.fn.easyPieChart = function(options) { 348 | return this.each(function() { 349 | var instanceOptions; 350 | 351 | if (!$.data(this, 'easyPieChart')) { 352 | instanceOptions = $.extend({}, options, $(this).data()); 353 | $.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions)); 354 | } 355 | }); 356 | }; 357 | 358 | 359 | })); 360 | -------------------------------------------------------------------------------- /assets/js/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document); -------------------------------------------------------------------------------- /assets/js/respond.min.js: -------------------------------------------------------------------------------- 1 | /*! Respond.js v1.4.2: min/max-width media query polyfill 2 | * Copyright 2014 Scott Jehl 3 | * Licensed under MIT 4 | * http://j.mp/respondjs */ 5 | 6 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){v(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))},g=function(a){return a.replace(c.regex.minmaxwh,"").match(c.regex.other)};if(c.ajax=f,c.queue=d,c.unsupportedmq=g,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,comments:/\/\*[^*]*\*+([^/][^*]*\*+)*\//gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,maxw:/\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/,minmaxwh:/\(\s*m(in|ax)\-(height|width)\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/gi,other:/\([^\)]*\)/g},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var h,i,j,k=a.document,l=k.documentElement,m=[],n=[],o=[],p={},q=30,r=k.getElementsByTagName("head")[0]||l,s=k.getElementsByTagName("base")[0],t=r.getElementsByTagName("link"),u=function(){var a,b=k.createElement("div"),c=k.body,d=l.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=k.createElement("body"),c.style.background="none"),l.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&l.insertBefore(c,l.firstChild),a=b.offsetWidth,f?l.removeChild(c):c.removeChild(b),l.style.fontSize=d,e&&(c.style.fontSize=e),a=j=parseFloat(a)},v=function(b){var c="clientWidth",d=l[c],e="CSS1Compat"===k.compatMode&&d||k.body[c]||d,f={},g=t[t.length-1],p=(new Date).getTime();if(b&&h&&q>p-h)return a.clearTimeout(i),i=a.setTimeout(v,q),void 0;h=p;for(var s in m)if(m.hasOwnProperty(s)){var w=m[s],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?j||u():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?j||u():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(n[w.rules]))}for(var C in o)o.hasOwnProperty(C)&&o[C]&&o[C].parentNode===r&&r.removeChild(o[C]);o.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=k.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,r.insertBefore(E,g.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(k.createTextNode(F)),o.push(E)}},w=function(a,b,d){var e=a.replace(c.regex.comments,"").replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var h=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},i=!f&&d;b.length&&(b+="/"),i&&(f=1);for(var j=0;f>j;j++){var k,l,o,p;i?(k=d,n.push(h(a))):(k=e[j].match(c.regex.findStyles)&&RegExp.$1,n.push(RegExp.$2&&h(RegExp.$2))),o=k.split(","),p=o.length;for(var q=0;p>q;q++)l=o[q],g(l)||m.push({media:l.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:n.length-1,hasquery:l.indexOf("(")>-1,minw:l.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:l.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}v()},x=function(){if(d.length){var b=d.shift();f(b.href,function(c){w(c,b.href,b.media),p[b.href]=!0,a.setTimeout(function(){x()},0)})}},y=function(){for(var b=0;bcontroller->id . '-' . $action->id); 21 | $class = get_called_class(); 22 | if (method_exists($class, $name)) { 23 | $reflectionMethod = new \ReflectionMethod($class, $name); 24 | $data = []; 25 | foreach ($reflectionMethod->getParameters() as $p) { 26 | $data[] = isset($params[$p->getName()]) ? $params[$p->getName()] : null; 27 | } 28 | $action->controller->getView()->params['breadcrumbs'] = call_user_func_array([$class, "$name"], $data); 29 | } 30 | } 31 | 32 | /** 33 | * @param $action 34 | * @param $params 35 | */ 36 | protected static function callButton($action, $params) 37 | { 38 | $name = 'button' . Inflector::camelize($action->controller->id . '-' . $action->id); 39 | $class = get_called_class(); 40 | if (method_exists($class, $name)) { 41 | $reflectionMethod = new \ReflectionMethod($class, $name); 42 | $data = []; 43 | foreach ($reflectionMethod->getParameters() as $p) { 44 | $data[] = isset($params[$p->getName()]) ? $params[$p->getName()] : null; 45 | } 46 | $action->controller->getView()->params['buttons'] = call_user_func_array([$class, $name], $data); 47 | } 48 | } 49 | 50 | /** 51 | * @param Action $action 52 | * @param $params 53 | */ 54 | public static function formCrumbs($action, $params) 55 | { 56 | self::callCrumb($action, $params); 57 | self::callButton($action, $params); 58 | } 59 | 60 | public static function buttonArticleIndex() 61 | { 62 | return [ 63 | [ 64 | 'label' => 'Добавить статью', 65 | 'url' => ['article/create'], 66 | 'linkOptions' => ['class' => 'btn-xs btn btn-primary'] 67 | ] 68 | ]; 69 | } 70 | 71 | /** 72 | * @param Article $article 73 | * @return array 74 | */ 75 | public static function buttonArticleView($article) 76 | { 77 | return [ 78 | [ 79 | 'label' => 'Редактировать', 80 | 'url' => ['article/update', 'id' => $article->id], 81 | 'linkOptions' => ['class' => 'btn-xs btn btn-primary'] 82 | ], 83 | [ 84 | 'label' => 'Добавить подстатью', 85 | 'url' => ['article/create', 'parent' => $article->id], 86 | 'linkOptions' => ['class' => 'btn-xs btn btn-primary'] 87 | ], 88 | [ 89 | 'label' => 'Удалить', 90 | 'url' => ['article/delete', 'id' => $article->id], 91 | 'options' => ['data-confirm' => 'Удалить статью?'], 92 | 'linkOptions' => ['class' => 'btn-xs btn btn-danger'] 93 | ] 94 | ]; 95 | } 96 | 97 | ############################################################################# 98 | 99 | public static function crumbTestingIndex() 100 | { 101 | return [ 102 | 'Тестирование модуля', 103 | ]; 104 | } 105 | 106 | /** 107 | * @param Article $article 108 | * @return array 109 | */ 110 | public static function crumbArticleView($article) 111 | { 112 | $items = [ 113 | ['label' => 'Старт', 'url' => ['article/index']] 114 | ]; 115 | $parent = $article; 116 | while ($parent = $parent->parent) { 117 | $items[] = ['label' => $parent->name, 'url' => ['article/view', 'id' => $parent->id]]; 118 | } 119 | $items[] = $article->name; 120 | return $items; 121 | } 122 | 123 | public static function crumbArticleUpdate($article) 124 | { 125 | $items = [ 126 | ['label' => 'Старт', 'url' => ['article/index']] 127 | ]; 128 | $parent = $article; 129 | while ($parent = $parent->parent) { 130 | $items[] = ['label' => $parent->name, 'url' => ['article/view', 'id' => $parent->id]]; 131 | } 132 | $items[] = ['label' => $article->name, 'url' => ['article/view', 'id' => $article->id]]; 133 | $items [] = 'Редактирование'; 134 | return $items; 135 | } 136 | 137 | 138 | public static function crumbInterfaceCheck($variable, $class, $interfaceTest) 139 | { 140 | return [ 141 | ['label' => 'Интерфейсы', 'url' => ['default/interfaces']], 142 | $class, 143 | ]; 144 | } 145 | 146 | public static function crumbDefaultInterfaces() 147 | { 148 | return [ 149 | 'Интерфейсы', 150 | ]; 151 | } 152 | 153 | public static function crumbDefaultFiles() 154 | { 155 | return [ 156 | 'Временные файлы', 157 | ]; 158 | } 159 | 160 | public static function crumbDefaultSettings() 161 | { 162 | return [ 163 | 'Настройки модуля', 164 | ]; 165 | } 166 | 167 | public static function crumbDefaultDocumentation() 168 | { 169 | return [ 170 | 'Документация по CommerceML', 171 | ]; 172 | } 173 | 174 | public static function crumbDefaultExport() 175 | { 176 | return [ 177 | 'Экспорт', 178 | ]; 179 | } 180 | 181 | 182 | public static function crumbDefaultImport() 183 | { 184 | return [ 185 | 'Импорт', 186 | ]; 187 | } 188 | 189 | public static function crumbArticleIndex() 190 | { 191 | return [ 192 | 'Старт', 193 | ]; 194 | } 195 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "carono/yii2-1c-exchange", 3 | "description": "Yii2 module for the exchange of goods and documents from 1C", 4 | "type": "yii2-extension", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Aleksandr Kasyanov", 9 | "email": "info@carono.ru", 10 | "homepage": "http://carono.ru" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.6", 15 | "yiisoft/yii2": "^2.0", 16 | "carono/commerceml": "^0.2.3", 17 | "ext-simplexml": "*", 18 | "ext-zip": "*" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "carono\\exchange1c\\": "" 23 | } 24 | }, 25 | "extra": { 26 | "bootstrap": "carono\\exchange1c\\Bootstrap" 27 | }, 28 | "require-dev": { 29 | "yiidoc/yii2-redactor": "^2.0" 30 | }, 31 | "repositories": [ 32 | { 33 | "type": "composer", 34 | "url": "https://asset-packagist.org" 35 | } 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /controllers/ArticleController.php: -------------------------------------------------------------------------------- 1 | pos = Article::find()->andWhere(['[[parent_id]]' => $parent])->max('pos') + 10; 23 | $article->parent_id = $parent; 24 | if ($article->load(\Yii::$app->request->post())) { 25 | if ($article->save()) { 26 | return $this->redirect(['article/index']); 27 | } 28 | 29 | \Yii::$app->session->setFlash('error', Html::errorSummary($article)); 30 | } 31 | return $this->render('update', ['article' => $article]); 32 | } 33 | 34 | public function actionUpdate($id) 35 | { 36 | $article = Article::findOne($id, true); 37 | if ($article->load(\Yii::$app->request->post())) { 38 | if ($article->save()) { 39 | return $this->redirect(['article/view', 'id' => $article->id]); 40 | } 41 | 42 | \Yii::$app->session->setFlash('error', Html::errorSummary($article)); 43 | } 44 | return $this->render('update', ['article' => $article]); 45 | } 46 | 47 | public function actionView($id) 48 | { 49 | Yii::$app->getView()->registerJs("$('pre').each(function(i, block) { hljs.highlightBlock(block); });"); 50 | $article = Article::findOne($id, true); 51 | return $this->render('view', ['article' => $article]); 52 | } 53 | 54 | public function actionDelete($id) 55 | { 56 | Article::findOne($id, true)->delete(); 57 | return $this->redirect(['article/index']); 58 | } 59 | 60 | public function actionIndex() 61 | { 62 | $dataProvider = Article::find()->orderBy(['{{%article}}.[[pos]]' => SORT_ASC])->search(); 63 | return $this->render('index', ['dataProvider' => $dataProvider]); 64 | } 65 | 66 | /** 67 | * Удаляем все реальные файлы, которые не используются в статьях 68 | */ 69 | public function actionDeleteUnusedImages() 70 | { 71 | $content = Article::find()->select(['content' => 'group_concat([[content]])'])->scalar(); 72 | $dir = Yii::getAlias(Yii::$app->controller->module->redactor->uploadDir); 73 | $files = Article::extractFilesFromString($content); 74 | $realFiles = FileHelper::findFiles($dir); 75 | array_walk($realFiles, function (&$item) use ($dir) { 76 | $item = str_replace('\\', '/', substr($item, strlen($dir))); 77 | }); 78 | foreach (array_diff($realFiles, $files) as $file) { 79 | unlink($dir . '/' . $file); 80 | }; 81 | return $this->redirect(['article/index']); 82 | } 83 | 84 | public function actionCreateReadme() 85 | { 86 | $badges = []; 87 | $lines = []; 88 | $titles = Article::formTitleItems(); 89 | 90 | $badges[] = '[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/carono/yii2-1c-exchange/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/carono/yii2-1c-exchange/?branch=master)'; 91 | $badges[] = '[![Latest Stable Version](https://poser.pugx.org/carono/yii2-1c-exchange/v/stable)](https://packagist.org/packages/carono/yii2-1c-exchange)'; 92 | $badges[] = '[![Total Downloads](https://poser.pugx.org/carono/yii2-1c-exchange/downloads)](https://packagist.org/packages/carono/yii2-1c-exchange)'; 93 | $badges[] = '[![License](https://poser.pugx.org/carono/yii2-1c-exchange/license)](https://packagist.org/packages/carono/yii2-1c-exchange)'; 94 | $badges[] = "\n"; 95 | $titles[] = "\n"; 96 | foreach (Article::formContentItems() as $item) { 97 | $titles[] = $item; 98 | } 99 | $titles[] = "\n"; 100 | $content = implode("\n", array_merge($badges, $titles, $lines)); 101 | file_put_contents(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'README.md', trim($content)); 102 | } 103 | } -------------------------------------------------------------------------------- /controllers/Controller.php: -------------------------------------------------------------------------------- 1 | 'yii\db\Connection', 27 | 'dsn' => 'sqlite:' . $dbPath, 28 | 'username' => '', 29 | 'password' => '', 30 | 'charset' => 'utf8', 31 | ]; 32 | \Yii::$app->set('exchangeDb', $config); 33 | } 34 | } 35 | 36 | public function render($view, $params = []) 37 | { 38 | if (!\Yii::$app->getView()->title) { 39 | \Yii::$app->getView()->title = $this->action->id; 40 | } 41 | Breadcrumbs::formCrumbs($this->action, $params); 42 | return parent::render($view, $params); 43 | } 44 | 45 | public function behaviors() 46 | { 47 | $behaviors = []; 48 | if (\Yii::$app->user->isGuest) { 49 | if ($this->module->auth) { 50 | $auth = $this->module->auth; 51 | } else { 52 | $auth = [$this->module, 'auth']; 53 | } 54 | $behaviors = [ 55 | 'basicAuth' => [ 56 | 'class' => HttpBasicAuth::class, 57 | 'auth' => $auth 58 | ], 59 | ]; 60 | } 61 | return $behaviors; 62 | } 63 | } -------------------------------------------------------------------------------- /controllers/DefaultController.php: -------------------------------------------------------------------------------- 1 | render('index'); 25 | } 26 | 27 | /** 28 | * @return string 29 | */ 30 | public function actionFiles() 31 | { 32 | $data = []; 33 | $dir = $this->module->getTmpDir(); 34 | foreach (FileHelper::findFiles($dir) as $file) { 35 | $data[] = ['filename' => substr($file, strlen($dir) + 1), 'size' => filesize($file)]; 36 | } 37 | $dataProvider = new ArrayDataProvider(['allModels' => $data]); 38 | return $this->render('files', ['dataProvider' => $dataProvider]); 39 | } 40 | 41 | /** 42 | * @return string 43 | */ 44 | public function actionImport() 45 | { 46 | return $this->render('import'); 47 | } 48 | 49 | /** 50 | * @return string 51 | */ 52 | public function actionExport() 53 | { 54 | return $this->render('export'); 55 | } 56 | 57 | /** 58 | * @return string 59 | */ 60 | public function actionMonitor() 61 | { 62 | $dataProvider = Monitor::find()->search(); 63 | $dataProvider->sort->defaultOrder = ['id' => SORT_DESC]; 64 | return $this->render('monitor', ['dataProvider' => $dataProvider]); 65 | } 66 | 67 | /** 68 | * @return string 69 | */ 70 | public function actionDocumentation() 71 | { 72 | $dir = \Yii::getAlias('@vendor/carono/yii2-1c-exchange/files/doc'); 73 | $data = []; 74 | foreach (FileHelper::findFiles($dir) as $file) { 75 | $data[] = ['filename' => substr($file, strlen($dir) + 1), 'size' => filesize($file)]; 76 | } 77 | $dataProvider = new ArrayDataProvider(['allModels' => $data]); 78 | return $this->render('documentation', ['dataProvider' => $dataProvider]); 79 | } 80 | 81 | /** 82 | * @return string 83 | */ 84 | public function actionInterfaces() 85 | { 86 | return $this->render('interfaces'); 87 | } 88 | 89 | /** 90 | * @param $file 91 | */ 92 | public function actionDownload($file) 93 | { 94 | $content = file_get_contents($this->module->getTmpDir($file)); 95 | \Yii::$app->response->sendContentAsFile($content, basename($file)); 96 | } 97 | 98 | /** 99 | * @return string 100 | */ 101 | public function actionSettings() 102 | { 103 | return $this->render('settings'); 104 | } 105 | 106 | /** 107 | * @return \yii\web\Response 108 | */ 109 | public function actionClearTmp() 110 | { 111 | foreach (FileHelper::findFiles($this->module->getTmpDir()) as $file) { 112 | unlink($file); 113 | } 114 | return $this->redirect(\Yii::$app->request->referrer); 115 | } 116 | 117 | /** 118 | * @return \yii\web\Response 119 | */ 120 | public function actionClearMonitor() 121 | { 122 | Yii::$app->exchangeDb->createCommand()->truncateTable('{{%monitor}}')->execute(); 123 | return $this->redirect(\Yii::$app->request->referrer); 124 | } 125 | } -------------------------------------------------------------------------------- /controllers/FileController.php: -------------------------------------------------------------------------------- 1 | response->sendContentAsFile($content, basename($filename), $options); 30 | } 31 | 32 | /** 33 | * @param $file 34 | */ 35 | protected function outAsFile($file) 36 | { 37 | $this->out($file); 38 | } 39 | 40 | /** 41 | * @param $file 42 | */ 43 | protected function outAsImage($file) 44 | { 45 | $options = [ 46 | 'inline' => true, 47 | 'mimeType' => FileHelper::getMimeType(self::getAlias($file)) 48 | ]; 49 | $this->out($file, $options); 50 | } 51 | 52 | /** 53 | * @param $file 54 | */ 55 | public function actionArticle($file) 56 | { 57 | $this->outAsImage("files/articles/$file"); 58 | } 59 | 60 | /** 61 | * @param $file 62 | */ 63 | public function actionDoc($file) 64 | { 65 | $path = "/files/doc/$file"; 66 | if (pathinfo($file, PATHINFO_EXTENSION) == 'xsd') { 67 | $this->outAsFile($path); 68 | } else { 69 | $this->outAsImage($path); 70 | } 71 | } 72 | 73 | /** 74 | * @param $file 75 | */ 76 | public function actionXml($file) 77 | { 78 | $this->outAsImage("/files/xml/$file"); 79 | } 80 | } -------------------------------------------------------------------------------- /controllers/InterfaceController.php: -------------------------------------------------------------------------------- 1 | controller->module->{$variable}; 22 | if (!$class) { 23 | throw new HttpException(401, "Значение '$variable' не установлено"); 24 | } 25 | $interfaceTest = InterfaceTest::findByClass($class); 26 | $interfaceClass = ModuleHelper::getPhpDocInterfaceProperty($variable); 27 | if ($interfaceTest->load(\Yii::$app->request->post())) { 28 | if ($interfaceTest->save()) { 29 | $this->refresh(); 30 | } else { 31 | \Yii::$app->session->setFlash('error', Html::errorSummary($interfaceTest)); 32 | } 33 | } 34 | return $this->render('check', [ 35 | 'variable' => $variable, 36 | 'class' => $class, 37 | 'interfaceTest' => $interfaceTest, 38 | 'interfaceClass' => $interfaceClass 39 | ]); 40 | } 41 | } -------------------------------------------------------------------------------- /controllers/TestingController.php: -------------------------------------------------------------------------------- 1 | hasErrors()) { 34 | throw new \Exception('Ошибки реализации интерфейсов.'); 35 | } 36 | 37 | if ($result) { 38 | $resultClass = new $className(['method' => $result]); 39 | } 40 | } 41 | return $this->render('index', ['testingClass' => $testingClass, 'resultClass' => $resultClass]); 42 | } 43 | } -------------------------------------------------------------------------------- /exchange.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/exchange.db -------------------------------------------------------------------------------- /files/articles/100/0489d0ae5b-requisite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/0489d0ae5b-requisite.png -------------------------------------------------------------------------------- /files/articles/100/30d7d0869c-property.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/30d7d0869c-property.png -------------------------------------------------------------------------------- /files/articles/100/30de0bdc18-slide2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/30de0bdc18-slide2.png -------------------------------------------------------------------------------- /files/articles/100/47e17f3950-pricetype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/47e17f3950-pricetype.png -------------------------------------------------------------------------------- /files/articles/100/79d570a828-order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/79d570a828-order.png -------------------------------------------------------------------------------- /files/articles/100/adc45161dd-properties.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/adc45161dd-properties.png -------------------------------------------------------------------------------- /files/articles/100/b10bbf4908-specifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/b10bbf4908-specifications.png -------------------------------------------------------------------------------- /files/articles/100/c2818da962-slide1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/c2818da962-slide1.png -------------------------------------------------------------------------------- /files/articles/100/dcf36639b2-2018-02-2619-55-41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/dcf36639b2-2018-02-2619-55-41.png -------------------------------------------------------------------------------- /files/articles/100/f4ca0f06dc-prices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/articles/100/f4ca0f06dc-prices.png -------------------------------------------------------------------------------- /files/doc/changes commerceML 2.09-2.10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/doc/changes commerceML 2.09-2.10.pdf -------------------------------------------------------------------------------- /files/doc/commerceML 2.09.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/doc/commerceML 2.09.pdf -------------------------------------------------------------------------------- /files/doc/commerceML 2.10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/doc/commerceML 2.10.pdf -------------------------------------------------------------------------------- /files/xml/from.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/xml/from.xml -------------------------------------------------------------------------------- /files/xml/offers.xml: -------------------------------------------------------------------------------- 1 |  2 | <КоммерческаяИнформация xmlns="urn:1C.ru:commerceml_2" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ВерсияСхемы="2.07" ДатаФормирования="2017-07-13T14:45:41"> 3 | <Классификатор> 4 | <Ид>07cfe53d-5145-4c4e-a81c-899be39cc5bd 5 | <Наименование>Классификатор (Каталог товаров 07CFE53D) 6 | <Владелец> 7 | <Ид>ef8f948c-8403-11da-9ae9-000d884f5d77 8 | <Наименование>Cтройснаб 9 | <ПолноеНаименование>Cтройснаб 10 | <КПП>772301001 11 | 12 | 13 | <ПакетПредложений СодержитТолькоИзменения="false"> 14 | <Ид>07cfe53d-5145-4c4e-a81c-899be39cc5bd# 15 | <Наименование>Пакет предложений ( Каталог товаров 07CFE53D ) 16 | <ИдКаталога>07cfe53d-5145-4c4e-a81c-899be39cc5bd 17 | <ИдКлассификатора>07cfe53d-5145-4c4e-a81c-899be39cc5bd 18 | <Владелец> 19 | <Ид>ef8f948c-8403-11da-9ae9-000d884f5d77 20 | <Наименование>Cтройснаб 21 | <ПолноеНаименование>Cтройснаб 22 | <КПП>772301001 23 | 24 | <ТипыЦен> 25 | <ТипЦены> 26 | <Ид>bb14a3a4-6b17-11e0-9819-e0cb4ed5eed4 27 | <Наименование>Розничная 28 | <Валюта>RUB 29 | <Налог> 30 | <Наименование>НДС 31 | <УчтеноВСумме>true 32 | <Акциз>false 33 | 34 | 35 | 36 | <Склады> 37 | <Склад> 38 | <Ид>b6112590-41ba-11dd-ac9d-0015e9b8c48d 39 | <Наименование>Магазин "Обувь" 40 | <Адрес> 41 | <Представление>РОССИЯ ,Москва г ,Москва г ,34 ,1 , 42 | <АдресноеПоле> 43 | <Тип>Страна 44 | <Значение>РОССИЯ 45 | 46 | <АдресноеПоле> 47 | <Тип>Регион 48 | <Значение>Москва г 49 | 50 | <АдресноеПоле> 51 | <Тип>Населенный пункт 52 | <Значение>Москва г 53 | 54 | <АдресноеПоле> 55 | <Тип>Дом 56 | <Значение>34 57 | 58 | <АдресноеПоле> 59 | <Тип>Корпус 60 | <Значение>1 61 | 62 | 63 | <Контакты> 64 | <Контакт> 65 | <Тип>Почта 66 | <Значение>Москва, Дмитровское шоссе, д.9 67 | 68 | 69 | 70 | <Склад> 71 | <Ид>b6112591-41ba-11dd-ac9d-0015e9b8c48d 72 | <Наименование>Магазин "Продукты" 73 | <Адрес> 74 | <Представление>РОССИЯ ,Москва г ,Москва г ,34 ,1 , 75 | <АдресноеПоле> 76 | <Тип>Страна 77 | <Значение>РОССИЯ 78 | 79 | <АдресноеПоле> 80 | <Тип>Регион 81 | <Значение>Москва г 82 | 83 | <АдресноеПоле> 84 | <Тип>Населенный пункт 85 | <Значение>Москва г 86 | 87 | <АдресноеПоле> 88 | <Тип>Дом 89 | <Значение>34 90 | 91 | <АдресноеПоле> 92 | <Тип>Корпус 93 | <Значение>1 94 | 95 | 96 | <Контакты> 97 | <Контакт> 98 | <Тип>Почта 99 | <Значение>Москва, Дмитровское шоссе, д.9 100 | 101 | 102 | 103 | <Склад> 104 | <Ид>b6112592-41ba-11dd-ac9d-0015e9b8c48d 105 | <Наименование>Магазин "Бытовая техника" 106 | <Адрес> 107 | <Представление>РОССИЯ ,Москва г ,Москва г ,34 ,1 , 108 | <АдресноеПоле> 109 | <Тип>Страна 110 | <Значение>РОССИЯ 111 | 112 | <АдресноеПоле> 113 | <Тип>Регион 114 | <Значение>Москва г 115 | 116 | <АдресноеПоле> 117 | <Тип>Населенный пункт 118 | <Значение>Москва г 119 | 120 | <АдресноеПоле> 121 | <Тип>Дом 122 | <Значение>34 123 | 124 | <АдресноеПоле> 125 | <Тип>Корпус 126 | <Значение>1 127 | 128 | 129 | <Контакты> 130 | <Контакт> 131 | <Тип>Почта 132 | <Значение>Москва, Дмитровское шоссе, д.9 133 | 134 | 135 | 136 | <Склад> 137 | <Ид>649efb01-6c6e-11de-b4b4-00195b6993ba 138 | <Наименование>Магазин "Детские товары". Воронеж 139 | <Адрес> 140 | <Представление>РОССИЯ ,Москва г ,Москва г ,34 ,1 , 141 | <АдресноеПоле> 142 | <Тип>Страна 143 | <Значение>РОССИЯ 144 | 145 | <АдресноеПоле> 146 | <Тип>Регион 147 | <Значение>Москва г 148 | 149 | <АдресноеПоле> 150 | <Тип>Населенный пункт 151 | <Значение>Москва г 152 | 153 | <АдресноеПоле> 154 | <Тип>Дом 155 | <Значение>34 156 | 157 | <АдресноеПоле> 158 | <Тип>Корпус 159 | <Значение>1 160 | 161 | 162 | <Контакты> 163 | <Контакт> 164 | <Тип>Почта 165 | <Значение>Москва, Дмитровское шоссе, д.9 166 | 167 | 168 | 169 | <Склад> 170 | <Ид>649efb02-6c6e-11de-b4b4-00195b6993ba 171 | <Наименование>Магазин "Детские товары". Тула 172 | <Адрес> 173 | <Представление>РОССИЯ ,Москва г ,Москва г ,34 ,1 , 174 | <АдресноеПоле> 175 | <Тип>Страна 176 | <Значение>РОССИЯ 177 | 178 | <АдресноеПоле> 179 | <Тип>Регион 180 | <Значение>Москва г 181 | 182 | <АдресноеПоле> 183 | <Тип>Населенный пункт 184 | <Значение>Москва г 185 | 186 | <АдресноеПоле> 187 | <Тип>Дом 188 | <Значение>34 189 | 190 | <АдресноеПоле> 191 | <Тип>Корпус 192 | <Значение>1 193 | 194 | 195 | <Контакты> 196 | <Контакт> 197 | <Тип>Почта 198 | <Значение>Москва, Дмитровское шоссе, д.9 199 | 200 | 201 | 202 | 203 | <Предложения> 204 | <Предложение> 205 | <Ид>bd72d910-55bc-11d9-848a-00112f43529a#90c55447-d3a8-11e4-9423-e0cb4ed5eed4 206 | <Артикул>Б-130001 207 | <Наименование>Женские ботфорты коричневые (38) 208 | <БазоваяЕдиница Код="715" НаименованиеПолное="Пара (2 шт.)"> 209 | <Пересчет> 210 | <Единица>715 211 | <Коэффициент>1 212 | 213 | 214 | <Цены> 215 | <Цена> 216 | <Представление> 1 719 RUB за пара 217 | <ИдТипаЦены>bb14a3a4-6b17-11e0-9819-e0cb4ed5eed4 218 | <ЦенаЗаЕдиницу>1719 219 | <Валюта>RUB 220 | <Коэффициент>1 221 | 222 | 223 | <Количество>20 224 | <Склад ИдСклада="b6112590-41ba-11dd-ac9d-0015e9b8c48d" КоличествоНаСкладе="20"/> 225 | 226 | <Предложение> 227 | <Ид>bd72d910-55bc-11d9-848a-00112f43529a#e5a4c316-a659-11dd-acee-0015e9b8c48d 228 | <Артикул>Б-130001 229 | <Наименование>Женские ботфорты коричневые (39) 230 | <БазоваяЕдиница Код="715" НаименованиеПолное="Пара (2 шт.)"> 231 | <Пересчет> 232 | <Единица>715 233 | <Коэффициент>1 234 | 235 | 236 | <Цены> 237 | <Цена> 238 | <Представление> 1 496 RUB за пара 239 | <ИдТипаЦены>bb14a3a4-6b17-11e0-9819-e0cb4ed5eed4 240 | <ЦенаЗаЕдиницу>1496 241 | <Валюта>RUB 242 | <Коэффициент>1 243 | 244 | 245 | <Количество>19 246 | <Склад ИдСклада="b6112590-41ba-11dd-ac9d-0015e9b8c48d" КоличествоНаСкладе="19"/> 247 | 248 | <Предложение> 249 | <Ид>bd72d913-55bc-11d9-848a-00112f43529a#90c55449-d3a8-11e4-9423-e0cb4ed5eed4 250 | <Артикул>Б- 130005 251 | <Наименование>Ботинки женские демисезонные (35) 252 | <БазоваяЕдиница Код="715" НаименованиеПолное="Пара (2 шт.)"> 253 | <Пересчет> 254 | <Единица>715 255 | <Коэффициент>1 256 | 257 | 258 | <Цены> 259 | <Цена> 260 | <Представление> 1 309 RUB за пара 261 | <ИдТипаЦены>bb14a3a4-6b17-11e0-9819-e0cb4ed5eed4 262 | <ЦенаЗаЕдиницу>1309 263 | <Валюта>RUB 264 | <Коэффициент>1 265 | 266 | 267 | <Количество>120 268 | <Склад ИдСклада="b6112590-41ba-11dd-ac9d-0015e9b8c48d" КоличествоНаСкладе="120"/> 269 | 270 | <Предложение> 271 | <Ид>bd72d913-55bc-11d9-848a-00112f43529a#90c5544a-d3a8-11e4-9423-e0cb4ed5eed4 272 | <Артикул>Б- 130005 273 | <Наименование>Ботинки женские демисезонные (36) 274 | <БазоваяЕдиница Код="715" НаименованиеПолное="Пара (2 шт.)"> 275 | <Пересчет> 276 | <Единица>715 277 | <Коэффициент>1 278 | 279 | 280 | <Цены> 281 | <Цена> 282 | <Представление> 1 309 RUB за пара 283 | <ИдТипаЦены>bb14a3a4-6b17-11e0-9819-e0cb4ed5eed4 284 | <ЦенаЗаЕдиницу>1309 285 | <Валюта>RUB 286 | <Коэффициент>1 287 | 288 | 289 | <Количество>15 290 | <Склад ИдСклада="b6112590-41ba-11dd-ac9d-0015e9b8c48d" КоличествоНаСкладе="15"/> 291 | 292 | <Предложение> 293 | <Ид>bd72d913-55bc-11d9-848a-00112f43529a#ad5de1b6-ca90-11dd-ad02-0015e9b8c48d 294 | <Артикул>Б- 130005 295 | <Наименование>Ботинки женские демисезонные (37) 296 | <БазоваяЕдиница Код="715" НаименованиеПолное="Пара (2 шт.)"> 297 | <Пересчет> 298 | <Единица>715 299 | <Коэффициент>1 300 | 301 | 302 | <Цены> 303 | <Цена> 304 | <Представление> 1 271 RUB за пара 305 | <ИдТипаЦены>bb14a3a4-6b17-11e0-9819-e0cb4ed5eed4 306 | <ЦенаЗаЕдиницу>1271 307 | <Валюта>RUB 308 | <Коэффициент>1 309 | 310 | 311 | <Количество>45 312 | <Склад ИдСклада="b6112590-41ba-11dd-ac9d-0015e9b8c48d" КоличествоНаСкладе="45"/> 313 | 314 | 315 | 316 | -------------------------------------------------------------------------------- /files/xml/to.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carono/yii2-1c-exchange/31e33ce46f98550dd63974c94994f277205b7d7a/files/xml/to.xml -------------------------------------------------------------------------------- /helpers/ByteHelper.php: -------------------------------------------------------------------------------- 1 | getMethods(\ReflectionMethod::IS_ABSTRACT) as $method) { 33 | if (StringHelper::startsWith($method->class, 'carono\exchange1c\interfaces')) { 34 | $result[] = $method; 35 | } 36 | } 37 | return array_values(ArrayHelper::map($result, 'name', 'name')); 38 | } 39 | 40 | /** 41 | * @param $class 42 | * @param $interface 43 | * @return boolean[] 44 | */ 45 | public static function getImplementedMethods($class, $interface) 46 | { 47 | $methods = $class ? ClassHelper::getMethods($class) : []; 48 | $interfaceMethods = self::getInterfaceMethods($interface); 49 | $result = []; 50 | foreach ($interfaceMethods as $interfaceMethod) { 51 | $result[$interfaceMethod] = array_search($interfaceMethod, $methods) !== false; 52 | } 53 | return $result; 54 | } 55 | } -------------------------------------------------------------------------------- /helpers/ModuleHelper.php: -------------------------------------------------------------------------------- 1 | modules as $name => $module) { 17 | $result = ''; 18 | if ((is_array($module))) { 19 | $result = ltrim($module['class'], '\\'); 20 | } elseif (is_object($module)) { 21 | $result = get_class($module); 22 | } 23 | if ($result == ltrim($class, '\\')) { 24 | return $name; 25 | } 26 | } 27 | return $default; 28 | } 29 | 30 | /** 31 | * @param $variable 32 | * @param string $class 33 | * @return string|null 34 | */ 35 | public static function getPhpDocInterfaceProperty($variable, $class = 'carono\exchange1c\ExchangeModule') 36 | { 37 | $reflection = new \ReflectionClass($class); 38 | $property = $reflection->getProperty($variable); 39 | if (preg_match('#@var\s+([\w\\\]+)#iu', $property->getDocComment(), $match)) { 40 | return $match[1]; 41 | } else { 42 | return null; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /helpers/NodeHelper.php: -------------------------------------------------------------------------------- 1 | ownerDocument->importNode($childDom, true); 22 | $parentDom->appendChild($childDom); 23 | return $child; 24 | } 25 | 26 | /** 27 | * @param \SimpleXMLElement $xml 28 | * @param $model 29 | * @param $field1c 30 | * @param $attribute 31 | * @return int|\SimpleXMLElement|string 32 | */ 33 | public static function addChild($xml, $model, $field1c, $attribute) 34 | { 35 | if ($attribute instanceof \Closure) { 36 | return self::addChild($xml, $model, $field1c, call_user_func($attribute, $model)); 37 | } elseif (is_string($attribute) && isset($model->{$attribute})) { 38 | return self::addChild($xml, $model, $field1c, $model->{$attribute}); 39 | } elseif (is_array($attribute)) { 40 | return self::addArrayChild($xml, $model, $field1c, $attribute); 41 | } elseif ($attribute instanceof \SimpleXMLElement) { 42 | return self::appendNode($xml, $attribute); 43 | } else { 44 | return $xml->addChild($field1c, $attribute); 45 | } 46 | } 47 | 48 | /** 49 | * @param \SimpleXMLElement $xml 50 | * @param $model 51 | * @param $field1c 52 | * @param $attribute 53 | * @return int|\SimpleXMLElement|string 54 | */ 55 | protected static function addArrayChild($xml, $model, $field1c, $attribute) 56 | { 57 | $array = $attribute; 58 | $content = ArrayHelper::remove($array, '@content', ''); 59 | $field1c = ArrayHelper::remove($array, '@name', $field1c); 60 | $attributes = ArrayHelper::remove($array, '@attributes', []); 61 | if (is_array($content)) { 62 | $item = self::addChild($xml, $model, $field1c, $content); 63 | return $item; 64 | } else { 65 | $item = new \SimpleXMLElement("<{$field1c}>$content"); 66 | foreach ($attributes as $name => $value) { 67 | $item->addAttribute($name, $value); 68 | } 69 | foreach ($array as $field => $value) { 70 | self::addChild($item, $model, $field, $value); 71 | } 72 | return self::appendNode($xml, $item); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /helpers/SerializeHelper.php: -------------------------------------------------------------------------------- 1 | '); 20 | self::addFields($xml, $partner, $partner->getExportFields1c()); 21 | return $xml; 22 | } 23 | 24 | /** 25 | * @param OfferInterface $offer 26 | * @param DocumentInterface $document 27 | * @return \SimpleXMLElement 28 | */ 29 | public static function serializeOffer(OfferInterface $offer, DocumentInterface $document) 30 | { 31 | $productNode = new \SimpleXMLElement('<Товар>'); 32 | self::addFields($productNode, $offer, $offer->getExportFields1c($document)); 33 | if ($group = $offer->getGroup1c()) { 34 | $productNode->addChild('ИдКаталога', $group->{$group->getIdFieldName1c()}); 35 | } 36 | return $productNode; 37 | } 38 | 39 | /** 40 | * @param DocumentInterface $document 41 | * @return \SimpleXMLElement 42 | */ 43 | public static function serializeDocument(DocumentInterface $document) 44 | { 45 | $documentNode = new \SimpleXMLElement('<Документ>'); 46 | self::addFields($documentNode, $document, $document->getExportFields1c()); 47 | $partnersNode = $documentNode->addChild('Контрагенты'); 48 | $partner = $document->getPartner1c(); 49 | $partnerNode = self::serializePartner($partner); 50 | NodeHelper::appendNode($partnersNode, $partnerNode); 51 | $products = $documentNode->addChild('Товары'); 52 | foreach ($document->getOffers1c() as $offer) { 53 | $productNode = self::serializeOffer($offer, $document); 54 | NodeHelper::appendNode($products, $productNode); 55 | } 56 | return $documentNode; 57 | } 58 | 59 | /** 60 | * @param $node 61 | * @param $object 62 | * @param $fields 63 | */ 64 | public static function addFields($node, $object, $fields) 65 | { 66 | foreach ($fields as $field => $value) { 67 | NodeHelper::addChild($node, $object, $field, $value); 68 | } 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /interfaces/DocumentInterface.php: -------------------------------------------------------------------------------- 1 | Классификатор > Группы) 12 | * $groups[0]->parent - родительская группа 13 | * $groups[0]->children - дочерние группы 14 | * 15 | * @param \Zenwalker\CommerceML\Model\Group[] $groups 16 | * @return void 17 | */ 18 | public static function createTree1c($groups); 19 | } -------------------------------------------------------------------------------- /interfaces/IdentifierInterface.php: -------------------------------------------------------------------------------- 1 | ПакетПредложений > Предложения > Предложение > Цены 18 | * 19 | * Цена товара, 20 | * К $price можно обратиться как к массиву, чтобы получить список цен (Цены > Цена) 21 | * $price->type - тип цены (offers.xml > ПакетПредложений > ТипыЦен > ТипЦены) 22 | * 23 | * @param \Zenwalker\CommerceML\Model\Price $price 24 | * @return void 25 | */ 26 | public function setPrice1c($price); 27 | 28 | /** 29 | * @param $types 30 | * @return void 31 | */ 32 | public static function createPriceTypes1c($types); 33 | 34 | 35 | /** 36 | * offers.xml > ПакетПредложений > Предложения > Предложение > ХарактеристикиТовара > ХарактеристикаТовара 37 | * 38 | * Характеристики товара 39 | * $name - Наименование 40 | * $value - Значение 41 | * 42 | * @param \Zenwalker\CommerceML\Model\Simple $specification 43 | * @return void 44 | */ 45 | public function setSpecification1c($specification); 46 | } -------------------------------------------------------------------------------- /interfaces/PartnerInterface.php: -------------------------------------------------------------------------------- 1 | Каталог > Товары > Товар > ЗначенияРеквизитов > ЗначениеРеквизита) 28 | * $name - Наименование 29 | * $value - Значение 30 | * 31 | * @param string $name 32 | * @param string $value 33 | * @return void 34 | */ 35 | public function setRequisite1c($name, $value); 36 | 37 | /** 38 | * Предпологается, что дерево групп у Вас уже создано (\carono\exchange1c\interfaces\GroupInterface::createTree1c) 39 | * 40 | * @param \Zenwalker\CommerceML\Model\Group $group 41 | * @return mixed 42 | */ 43 | public function setGroup1c($group); 44 | 45 | /** 46 | * import.xml > Классификатор > Свойства > Свойство 47 | * $property - Свойство товара 48 | * 49 | * import.xml > Классификатор > Свойства > Свойство > Значение 50 | * $property->value - Разыменованное значение (string) 51 | * 52 | * import.xml > Классификатор > Свойства > Свойство > ВариантыЗначений > Справочник 53 | * $property->getValueModel() - Данные по значению, Ид значения, и т.д 54 | * 55 | * @param \Zenwalker\CommerceML\Model\Property $property 56 | * @return void 57 | */ 58 | public function setProperty1c($property); 59 | 60 | /** 61 | * @param string $path 62 | * @param string $caption 63 | * @return void 64 | */ 65 | public function addImage1c($path, $caption); 66 | 67 | /** 68 | * @return GroupInterface 69 | */ 70 | public function getGroup1c(); 71 | 72 | /** 73 | * Создание всех свойств продутка 74 | * import.xml > Классификатор > Свойства 75 | * 76 | * $properties[]->availableValues - список доступных значений, для этого свойства 77 | * import.xml > Классификатор > Свойства > Свойство > ВариантыЗначений > Справочник 78 | * 79 | * @param PropertyCollection $properties 80 | * @return mixed 81 | */ 82 | public static function createProperties1c($properties); 83 | 84 | /** 85 | * @param \Zenwalker\CommerceML\Model\Offer $offer 86 | * @return OfferInterface 87 | */ 88 | public function getOffer1c($offer); 89 | 90 | /** 91 | * @param \Zenwalker\CommerceML\Model\Product $product 92 | * @return self 93 | */ 94 | public static function createModel1c($product); 95 | } -------------------------------------------------------------------------------- /interfaces/RawInterface.php: -------------------------------------------------------------------------------- 1 | hasOne(Article::class, ['id' => 'parent_id']); 29 | } 30 | 31 | /** 32 | * @return ArticleQuery|ActiveQuery 33 | */ 34 | public function getArticles() 35 | { 36 | return $this->hasMany(Article::class, ['parent_id' => 'id']); 37 | } 38 | 39 | /** 40 | * @return null|object|\yii\db\Connection|mixed 41 | */ 42 | public static function getDb() 43 | { 44 | return Yii::$app->get('exchangeDb'); 45 | } 46 | 47 | /** 48 | * @return array 49 | */ 50 | public function behaviors() 51 | { 52 | return [ 53 | 'timestamp' => [ 54 | 'class' => TimestampBehavior::class, 55 | 'value' => new Expression('CURRENT_TIMESTAMP') 56 | ] 57 | ]; 58 | } 59 | 60 | /** 61 | * @return array 62 | */ 63 | public function formForMenu() 64 | { 65 | /** 66 | * @var Article $subGroup 67 | */ 68 | $item = ['label' => $this->name, 'url' => ['article/view', 'id' => $this->id]]; 69 | foreach ($this->getArticles()->orderBy(['[[pos]]' => SORT_ASC])->each() as $subGroup) { 70 | $item['items'][] = $subGroup->formForMenu(); 71 | } 72 | return $item; 73 | } 74 | 75 | /** 76 | * @param int|null $parent 77 | * @return array 78 | */ 79 | public static function formMenuItems($parent = null) 80 | { 81 | /** 82 | * @var Article $group 83 | */ 84 | $items = []; 85 | $query = self::find()->andWhere(['parent_id' => $parent])->orderBy(['[[pos]]' => SORT_ASC]); 86 | foreach ($query->each() as $group) { 87 | $items[] = $group->formForMenu(); 88 | } 89 | return $items; 90 | } 91 | 92 | /** 93 | * @param int $deep 94 | * @return array 95 | */ 96 | public function formForTitle($deep = 0) 97 | { 98 | /** 99 | * @var Article $subGroup 100 | */ 101 | $item = []; 102 | $item[] = str_repeat("\t", $deep) . '* ' . "[{$this->name}](#{$this->id})"; 103 | foreach ($this->getArticles()->orderBy(['[[pos]]' => SORT_ASC])->each() as $subGroup) { 104 | $item[] = $subGroup->formForTitle($deep + 1); 105 | } 106 | return implode("\n", $item); 107 | } 108 | 109 | /** 110 | * @param int|null $parent 111 | * @return array 112 | */ 113 | public static function formTitleItems($parent = null) 114 | { 115 | /** 116 | * @var Article $group 117 | */ 118 | $items = []; 119 | $query = self::find()->andWhere(['parent_id' => $parent])->orderBy(['[[pos]]' => SORT_ASC]); 120 | foreach ($query->each() as $group) { 121 | $items[] = $group->formForTitle(); 122 | } 123 | return $items; 124 | } 125 | 126 | /** 127 | * @param null $parent 128 | * @return array 129 | */ 130 | public static function formContentItems($parent = null) 131 | { 132 | /** 133 | * @var Article $article 134 | */ 135 | $items = []; 136 | $query = self::find()->andWhere(['parent_id' => $parent])->orderBy(['[[pos]]' => SORT_ASC]); 137 | foreach ($query->each() as $article) { 138 | if ($article->content) { 139 | $link = 'https://raw.github.com/carono/yii2-1c-exchange/HEAD/files/articles'; 140 | $content = str_replace(['../file/article?file=', 'view?id='], [$link, '#'], $article->content); 141 | $items[] = Html::a($article->name, false, ['name' => $article->id]) . "\n=\n"; 142 | $items[] = $content; 143 | $items[] = "\n"; 144 | } 145 | $items = array_merge($items, static::formContentItems($article->id)); 146 | } 147 | return $items; 148 | } 149 | 150 | /** 151 | * @return false|int 152 | */ 153 | public function delete() 154 | { 155 | $files = self::extractFilesFromString($this->content); 156 | foreach ($files as $file) { 157 | $uploadFile = Yii::$app->controller->module->redactor->uploadDir . '/' . $file; 158 | FileHelper::unlink($uploadFile); 159 | } 160 | foreach ($this->articles as $article) { 161 | $article->delete(); 162 | } 163 | return parent::delete(); 164 | } 165 | 166 | /** 167 | * @param $content 168 | * @return mixed 169 | */ 170 | public static function extractFilesFromString($content) 171 | { 172 | preg_match_all('#/file/article\?file=([\w\-\/\.]+)"#ui', $content, $m); 173 | return $m[1]; 174 | } 175 | 176 | /** 177 | * @param bool $insert 178 | * @param array $changedAttributes 179 | */ 180 | public function afterSave($insert, $changedAttributes) 181 | { 182 | if ($content = ArrayHelper::getValue($changedAttributes, 'content')) { 183 | $old = self::extractFilesFromString($content); 184 | $new = self::extractFilesFromString($this->content); 185 | foreach (array_diff($old, $new) as $file) { 186 | $uploadFile = Yii::$app->controller->module->redactor->uploadDir . '/' . $file; 187 | FileHelper::unlink($uploadFile); 188 | } 189 | } 190 | parent::afterSave($insert, $changedAttributes); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /models/InterfaceModel.php: -------------------------------------------------------------------------------- 1 | 'Метод не найден' 22 | ]; 23 | public $function; 24 | public $interface; 25 | public $class; 26 | 27 | public function getStatus_id() 28 | { 29 | if (!$this->functionExists()) { 30 | return self::STATUS_METHOD_NOT_FOUND; 31 | } 32 | return self::STATUS_UNKNOWN; 33 | } 34 | 35 | public function getStatus_name() 36 | { 37 | return ArrayHelper::getValue(self::$statuses, $this->status_id, $this->status_id); 38 | } 39 | 40 | public function functionExists() 41 | { 42 | return array_search($this->function, ClassHelper::getMethods($this->class)) !== false; 43 | } 44 | 45 | public function getDescription() 46 | { 47 | $method = new \ReflectionMethod($this->interface, $this->function); 48 | return nl2br(preg_replace('#\*/|/\*|\*#', '', $method->getDocComment())); 49 | } 50 | } -------------------------------------------------------------------------------- /models/InterfaceTest.php: -------------------------------------------------------------------------------- 1 | getModel()) { 26 | $this->addError('id', 'Model not found'); 27 | return false; 28 | } else { 29 | return \Yii::$app->cache->set([self::class, $this->class], $this, 300); 30 | } 31 | } 32 | 33 | public function getModel() 34 | { 35 | try { 36 | return call_user_func("{$this->class}::findOne", $this->id); 37 | } catch (\Exception $e) { 38 | return null; 39 | } 40 | } 41 | 42 | /** 43 | * @param $class 44 | * @return InterfaceTest|mixed 45 | */ 46 | public static function findByClass($class) 47 | { 48 | if (!$model = \Yii::$app->cache->get([self::class, $class])) { 49 | return new self(['class' => $class]); 50 | } else { 51 | return $model; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /models/Monitor.php: -------------------------------------------------------------------------------- 1 | controller->module; 30 | } 31 | 32 | /** 33 | * @return array 34 | */ 35 | public static function findAll() 36 | { 37 | $reflection = new \ReflectionClass(static::class); 38 | $methods = $reflection->getMethods(\ReflectionMethod::IS_STATIC); 39 | $methods = ArrayHelper::map(array_filter($methods, function ($data) { 40 | return StringHelper::startsWith($data->name, 'test'); 41 | }), 'name', 'name'); 42 | $data = []; 43 | foreach ($methods as $method) { 44 | if ($test = call_user_func(static::class . "::$method")) { 45 | $data[] = $test; 46 | } 47 | } 48 | return $data; 49 | } 50 | 51 | /** 52 | * @return bool 53 | */ 54 | public function testing() 55 | { 56 | return !$this->hasErrors(); 57 | } 58 | 59 | /** 60 | * Testing constructor. 61 | * 62 | * @param array $config 63 | */ 64 | public function __construct(array $config = []) 65 | { 66 | parent::__construct($config); 67 | } 68 | } -------------------------------------------------------------------------------- /models/TestingClass.php: -------------------------------------------------------------------------------- 1 | 'array|string|interface'] 32 | * [['name'], 'return' => 'interface', 'value'=>''] 33 | * 34 | * 35 | * @return array 36 | */ 37 | protected static function methodRules() 38 | { 39 | return []; 40 | } 41 | 42 | /** 43 | * @param $result 44 | * @return mixed 45 | */ 46 | protected function saveResult($result) 47 | { 48 | if (\Yii::$app->cache) { 49 | \Yii::$app->cache->set([$this->method, self::getPropertyClass()], $result); 50 | } 51 | return $result; 52 | } 53 | 54 | /** 55 | * @return mixed|null 56 | */ 57 | protected function getSavedResult() 58 | { 59 | if (\Yii::$app->cache) { 60 | return \Yii::$app->cache->get([$this->method, self::getPropertyClass()]); 61 | } 62 | return null; 63 | } 64 | 65 | /** 66 | * @param $params 67 | * @return array 68 | */ 69 | protected static function getParams($params) 70 | { 71 | $values = []; 72 | foreach ($params as $param) { 73 | $value = null; 74 | $cml = new CommerceML(); 75 | $cml->loadImportXml(\Yii::getAlias('@vendor/carono/yii2-1c-exchange/files/xml/import.xml')); 76 | $cml->loadOffersXml(\Yii::getAlias('@vendor/carono/yii2-1c-exchange/files/xml/offers.xml')); 77 | if ($param instanceof \Closure) { 78 | $values[] = call_user_func($param); 79 | } elseif (StringHelper::startsWith($param, 'cml.')) { 80 | $value = ArrayHelper::getValue($cml, substr($param, 4)); 81 | } else { 82 | $value = $param; 83 | } 84 | $values[] = $value; 85 | } 86 | return $values; 87 | } 88 | 89 | /** 90 | * @return ActiveRecord|mixed 91 | */ 92 | protected static function getPropertyClass() 93 | { 94 | return self::module()->{static::$property}; 95 | } 96 | 97 | /** 98 | * @param $method 99 | * @param $params 100 | * @return mixed|null 101 | */ 102 | protected static function getMethodResult($method, $params) 103 | { 104 | $class = self::getPropertyClass(); 105 | $methodResult = null; 106 | if (method_exists($class, $method)) { 107 | $reflectionMethod = new \ReflectionMethod($class, $method); 108 | $params = self::getParams($params); 109 | try { 110 | if ($reflectionMethod->isStatic()) { 111 | $methodResult = call_user_func_array("$class::$method", $params); 112 | } elseif (!$context = static::getContext()) { 113 | return null; 114 | } else { 115 | $methodResult = call_user_func_array([$context, $method], $params); 116 | } 117 | } catch (\Exception $e) { 118 | return null; 119 | } 120 | } 121 | return $methodResult; 122 | } 123 | 124 | /** 125 | * @param Testing $test 126 | * @param $method 127 | * @param $rule 128 | */ 129 | private static function validateMethodRule($test, $method, $rule) 130 | { 131 | 132 | } 133 | 134 | public static function findAll() 135 | { 136 | $result = parent::findAll(); 137 | foreach (static::methodRules() as $method => $rule) { 138 | $test = new static(); 139 | $test->name = "Результат '$method'"; 140 | $test->method = $method; 141 | $test->expect = ArrayHelper::getValue($rule, 'return', false) ?: 'VOID'; 142 | $result[] = $test; 143 | } 144 | return $result; 145 | } 146 | 147 | protected static function getContext() 148 | { 149 | $class = \Yii::$app->controller->module->{static::$property}; 150 | return InterfaceTest::findByClass($class)->getModel(); 151 | } 152 | 153 | public static function testPropertyIsSet() 154 | { 155 | $property = static::$property; 156 | $test = new static(); 157 | $test->name = ModuleHelper::getModuleNameByClass() . "->{$property}"; 158 | if (!self::module()->{$property}) { 159 | $test->result = false; 160 | $test->comment = "Необходимо прописать '$property' в модуле '" . ModuleHelper::getModuleNameByClass() . "'"; 161 | } 162 | return $test; 163 | } 164 | 165 | public function hasResult() 166 | { 167 | return $this->_result; 168 | } 169 | 170 | public function getResult($force = false) 171 | { 172 | if (!$force && ($cache = $this->getSavedResult())) { 173 | return $cache; 174 | } 175 | try { 176 | return $this->saveResult($this->prepareResult()); 177 | } catch (\Exception $e) { 178 | return $e->getMessage(); 179 | } 180 | } 181 | 182 | public function prepareResult() 183 | { 184 | if ($method = $this->method) { 185 | $methodName = "getResult" . ucfirst($method); 186 | if (method_exists($this, $methodName)) { 187 | $result = call_user_func([$this, $methodName]); 188 | return $this->_result = $result; 189 | } else { 190 | $params = ArrayHelper::getValue(static::methodRules(), $method . '.params', []); 191 | return $this->_result = static::getMethodResult($method, $params); 192 | } 193 | } else { 194 | return null; 195 | } 196 | } 197 | 198 | public static function testImplementsClass() 199 | { 200 | $property = static::$property; 201 | $test = new static(); 202 | $test->name = "Реализация интерфейсов $property (" . self::module()->{$property} . ")"; 203 | $propertyValue = self::module()->{$property}; 204 | $propertyDoc = ModuleHelper::getPhpDocInterfaceProperty($property); 205 | $implements = ClassHelper::getImplementedMethods($propertyValue, $propertyDoc); 206 | $implements = array_filter($implements, function ($data) { 207 | return !$data; 208 | }); 209 | if (!empty($implements)) { 210 | $comment = []; 211 | foreach ($implements as $class => $value) { 212 | $comment[] = $class; 213 | $test->addError('', 'Need implement: ' . $class); 214 | } 215 | $test->comment = "Не реализованы:
" . join("
", $comment); 216 | } 217 | return $test; 218 | } 219 | 220 | public static function getMethodRule($method) 221 | { 222 | return ArrayHelper::getValue(static::methodRules(), $method, []); 223 | } 224 | 225 | public function isAutoTest() 226 | { 227 | return ArrayHelper::getValue(self::getMethodRule($this->method), 'auto') == true; 228 | } 229 | 230 | public function validateMethod() 231 | { 232 | return false; 233 | } 234 | 235 | public function testing() 236 | { 237 | if (!$rule = self::getMethodRule($this->method)) { 238 | return parent::testing(); 239 | } 240 | $result = $this->isAutoTest() ? $this->getResult() : $this->getSavedResult(); 241 | $validateMethod = 'validateMethod' . ucfirst($this->method); 242 | if (method_exists($this, $validateMethod)) { 243 | $params = self::getParams($rule['params']); 244 | $params[] = $result; 245 | return call_user_func_array([$this, $validateMethod], $params); 246 | } 247 | switch ($rule['return']) { 248 | case 'string': 249 | return is_string($result); 250 | break; 251 | case 'interface'; 252 | return $result instanceof $rule['value']; 253 | break; 254 | } 255 | } 256 | } -------------------------------------------------------------------------------- /models/TestingDocumentClass.php: -------------------------------------------------------------------------------- 1 | true, 16 | 'return' => 'interface', 17 | 'value' => 'carono\exchange1c\interfaces\PartnerInterface' 18 | ], 19 | [['findDocuments1c'], 'return' => 'array'], 20 | ]); 21 | } 22 | } -------------------------------------------------------------------------------- /models/TestingGroupClass.php: -------------------------------------------------------------------------------- 1 | createTree($params[0], $class); 32 | } 33 | 34 | /** 35 | * @param Group[] $groups 36 | * @param GroupInterface $class 37 | * @return array 38 | */ 39 | private function createTree($groups, $class) 40 | { 41 | $result = []; 42 | $id = $class::getIdFieldName1c(); 43 | foreach ($groups as $group) { 44 | if ($model = $class::find()->andWhere([$id => $group->id])->one()) { 45 | $result[] = $model; 46 | } 47 | if ($children = $group->getChildren()) { 48 | $result += $this->createTree($children, $class); 49 | } 50 | } 51 | return $result; 52 | } 53 | 54 | public static function methodRules() 55 | { 56 | return [ 57 | 'getIdFieldName1c' => [ 58 | 'return' => 'string', 59 | 'auto' => true 60 | ], 61 | 'createTree1c' => [ 62 | 'return' => false, 63 | 'params' => ['cml.classifier.groups'] 64 | ], 65 | ]; 66 | } 67 | } -------------------------------------------------------------------------------- /models/TestingPartnerClass.php: -------------------------------------------------------------------------------- 1 | $params[0]->id]); 32 | } 33 | 34 | public static function methodRules() 35 | { 36 | return [ 37 | 'getIdFieldName1c' => [ 38 | 'return' => self::RETURN_STRING, 39 | 'auto' => true 40 | ], 41 | 'createModel1c' => [ 42 | 'return' => self::RETURN_INTERFACE, 43 | 'value' => ProductInterface::class, 44 | 'params' => ['cml.catalog.products.0'] 45 | ], 46 | 'getOffer1c' => [ 47 | 'return' => self::RETURN_INTERFACE, 48 | 'value' => OfferInterface::class, 49 | 'params' => ['cml.offerPackage.offers.0'] 50 | ], 51 | 'setGroup1c' => [ 52 | 'return' => false, 53 | 'params' => ['cml.catalog.products.0.group'] 54 | ], 55 | 'getGroup1c' => [ 56 | 'return' => self::RETURN_INTERFACE, 57 | 'value' => GroupInterface::class 58 | ] 59 | ]; 60 | } 61 | } -------------------------------------------------------------------------------- /models/base/Article.php: -------------------------------------------------------------------------------- 1 | get('exchangeDb'); 35 | } 36 | 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | public static function tableName() 42 | { 43 | return '{{%article}}'; 44 | } 45 | 46 | 47 | /** 48 | * @inheritdoc 49 | */ 50 | public function rules() 51 | { 52 | return [ 53 | [['name'], 'required'], 54 | [['parent_id', 'pos'], 'integer'], 55 | [['content'], 'string'], 56 | [['name'], 'string', 'max' => 255], 57 | ]; 58 | } 59 | 60 | 61 | /** 62 | * @inheritdoc 63 | * @return \carono\exchange1c\models\Article|\yii\db\ActiveRecord 64 | */ 65 | public static function findOne($condition, $raise = false) 66 | { 67 | $model = parent::findOne($condition); 68 | if (!$model && $raise){ 69 | throw new \yii\web\HttpException(404, Yii::t('errors', "Model carono\\exchange1c\\models\\Article not found")); 70 | }else{ 71 | return $model; 72 | } 73 | } 74 | 75 | 76 | /** 77 | * @inheritdoc 78 | */ 79 | public function attributeLabels() 80 | { 81 | return [ 82 | 'id' => Yii::t('models', 'ID'), 83 | 'name' => Yii::t('models', 'Name'), 84 | 'parent_id' => Yii::t('models', 'Parent ID'), 85 | 'pos' => Yii::t('models', 'Pos'), 86 | 'content' => Yii::t('models', 'Content'), 87 | 'created_at' => Yii::t('models', 'Created At'), 88 | 'updated_at' => Yii::t('models', 'Updated At') 89 | ]; 90 | } 91 | 92 | 93 | /** 94 | * @inheritdoc 95 | * @return \carono\exchange1c\models\query\ArticleQuery the active query used by this AR class. 96 | */ 97 | public static function find() 98 | { 99 | return new \carono\exchange1c\models\query\ArticleQuery(get_called_class()); 100 | } 101 | 102 | 103 | /** 104 | * @param string $attribute 105 | * @return string|null 106 | */ 107 | public function getRelationClass($attribute) 108 | { 109 | return ArrayHelper::getValue($this->_relationClasses, $attribute); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /models/base/Monitor.php: -------------------------------------------------------------------------------- 1 | get('exchangeDb'); 40 | } 41 | 42 | 43 | /** 44 | * @inheritdoc 45 | */ 46 | public static function tableName() 47 | { 48 | return '{{%monitor}}'; 49 | } 50 | 51 | 52 | /** 53 | * @inheritdoc 54 | */ 55 | public function rules() 56 | { 57 | return [ 58 | [['url', 'route', 'headers', 'get', 'post', 'file', 'ip', 'user_id', 'response'], 'string'], 59 | [['http_code'], 'integer'], 60 | ]; 61 | } 62 | 63 | 64 | /** 65 | * @inheritdoc 66 | * @return \carono\exchange1c\models\Monitor|\yii\db\ActiveRecord 67 | */ 68 | public static function findOne($condition, $raise = false) 69 | { 70 | $model = parent::findOne($condition); 71 | if (!$model && $raise){ 72 | throw new \yii\web\HttpException(404, Yii::t('errors', "Model carono\\exchange1c\\models\\Monitor not found")); 73 | }else{ 74 | return $model; 75 | } 76 | } 77 | 78 | 79 | /** 80 | * @inheritdoc 81 | */ 82 | public function attributeLabels() 83 | { 84 | return [ 85 | 'id' => Yii::t('models', 'ID'), 86 | 'url' => Yii::t('models', 'Url'), 87 | 'route' => Yii::t('models', 'Route'), 88 | 'headers' => Yii::t('models', 'Headers'), 89 | 'get' => Yii::t('models', 'Get'), 90 | 'post' => Yii::t('models', 'Post'), 91 | 'file' => Yii::t('models', 'File'), 92 | 'ip' => Yii::t('models', 'Ip'), 93 | 'user_id' => Yii::t('models', 'User ID'), 94 | 'response' => Yii::t('models', 'Response'), 95 | 'http_code' => Yii::t('models', 'Http Code'), 96 | 'created_at' => Yii::t('models', 'Created At') 97 | ]; 98 | } 99 | 100 | 101 | /** 102 | * @inheritdoc 103 | * @return \carono\exchange1c\models\query\MonitorQuery the active query used by this AR class. 104 | */ 105 | public static function find() 106 | { 107 | return new \carono\exchange1c\models\query\MonitorQuery(get_called_class()); 108 | } 109 | 110 | 111 | /** 112 | * @param string $attribute 113 | * @return string|null 114 | */ 115 | public function getRelationClass($attribute) 116 | { 117 | return ArrayHelper::getValue($this->_relationClasses, $attribute); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /models/query/ArticleQuery.php: -------------------------------------------------------------------------------- 1 | filter($filter); 50 | $sort = new Sort(); 51 | return new ActiveDataProvider( 52 | array_merge([ 53 | 'query' => $query, 54 | 'sort' => $sort 55 | ], $options) 56 | ); 57 | } 58 | 59 | 60 | /** 61 | * @var array|\yii\db\ActiveRecord $model 62 | * @return $this 63 | */ 64 | public function filter($model = null) 65 | { 66 | return $this; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /models/query/base/MonitorQuery.php: -------------------------------------------------------------------------------- 1 | filter($filter); 50 | $sort = new Sort(); 51 | return new ActiveDataProvider( 52 | array_merge([ 53 | 'query' => $query, 54 | 'sort' => $sort 55 | ], $options) 56 | ); 57 | } 58 | 59 | 60 | /** 61 | * @var array|\yii\db\ActiveRecord $model 62 | * @return $this 63 | */ 64 | public function filter($model = null) 65 | { 66 | return $this; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /views/article/index.php: -------------------------------------------------------------------------------- 1 | title = 'Документация по работе модуля'; 12 | $items = Article::formMenuItems(); 13 | Panel::begin(); 14 | echo Menu::widget([ 15 | 'items' => $items, 16 | 'options' => ['class' => 'article-menu'] 17 | ]); 18 | Panel::end(); 19 | -------------------------------------------------------------------------------- /views/article/partial/nav.php: -------------------------------------------------------------------------------- 1 | orderBy(['{{%article}}.[[pos]]' => SORT_ASC]) 12 | ->andWhere(['parent_id' => $article->parent_id]) 13 | ->andWhere(['<>', '[[id]]', $article->id]) 14 | ->andWhere(['>=', '[[pos]]', $article->pos]) 15 | ->orWhere(['parent_id' => $article->id]); 16 | $next = $query->one(); 17 | 18 | $query = Article::find() 19 | ->orderBy(['{{%article}}.[[pos]]' => SORT_DESC]) 20 | ->andWhere(['parent_id' => $article->parent_id]) 21 | ->andWhere(['<>', '[[id]]', $article->id]) 22 | ->andWhere(['<=', '[[pos]]', $article->pos]) 23 | ->orWhere(['id' => $article->parent_id]); 24 | $prev = $query->one(); 25 | 26 | 27 | Panel::begin(); 28 | if ($prev) { 29 | $options = ['class' => 'btn btn-primary']; 30 | echo Html::a('Читать ранее: ' . $prev->name, ['article/view', 'id' => $prev->id], $options); 31 | } 32 | if ($next) { 33 | $options = ['class' => 'btn btn-primary pull-right']; 34 | echo Html::a('Читать далее: ' . $next->name, ['article/view', 'id' => $next->id], $options); 35 | } 36 | Panel::end(); -------------------------------------------------------------------------------- /views/article/update.php: -------------------------------------------------------------------------------- 1 | controller->module->redactor; 17 | if (!$module) { 18 | echo '
Для редактирования, необходимо установить редактор composer require yiidoc/yii2-redactor
'; 19 | } 20 | 21 | $this->title = $article->isNewRecord ? 'Добавить статью' : 'Редактирование ' . $article->name; 22 | $articles = ArrayHelper::map(Article::find()->select(['id', 'name'])->asArray()->all(), 'id', 'name'); 23 | Panel::begin(); 24 | $form = ActiveForm::begin(); 25 | echo $form->field($article, 'name'); 26 | echo $form->field($article, 'pos')->textInput(['type' => 'number']); 27 | echo $form->field($article, 'parent_id')->dropDownList($articles, ['prompt' => '']); 28 | if ($module) { 29 | echo $form->field($article, 'content')->widget(Redactor::class, [ 30 | 'moduleId' => $module->id, 31 | 'clientOptions' => [ 32 | 'lang' => 'ru', 33 | 'plugins' => ['clips', 'fontcolor', 'imagemanager', 'table'] 34 | ], 35 | ]); 36 | } else { 37 | echo $form->field($article, 'content')->textarea(); 38 | } 39 | 40 | echo '
'; 41 | echo Html::submitButton($article->isNewRecord ? 'Добавить' : 'Сохранить', ['class' => 'btn btn-primary']); 42 | echo Html::a('Отмена', ['view', 'id' => $article->id], ['class' => 'btn btn-warning']); 43 | echo '
'; 44 | 45 | ActiveForm::end(); 46 | Panel::end(); -------------------------------------------------------------------------------- /views/article/view.php: -------------------------------------------------------------------------------- 1 | title = $article->name; 14 | 15 | if ($items = Article::formMenuItems()) { 16 | Panel::begin(); 17 | echo Menu::widget([ 18 | 'items' => $items, 19 | 'options' => ['class' => 'article-menu'], 20 | ]); 21 | Panel::end(); 22 | } 23 | 24 | echo $this->render('partial/nav', ['article' => $article]); 25 | 26 | Panel::begin(['id' => 'article-content']); 27 | echo $article->content; 28 | Panel::end(); 29 | 30 | echo $this->render('partial/nav', ['article' => $article]); 31 | 32 | $this->registerJs("$('#article-content').find('table').addClass('table table-striped table-bordered');"); 33 | -------------------------------------------------------------------------------- /views/default/documentation.php: -------------------------------------------------------------------------------- 1 | 13 |
Файлы формата .XSD необходимо отрывать в Visual Studio
14 | title = 'Спецификация по стандарту CommerceML'; 16 | Panel::begin(); 17 | echo GridView::widget([ 18 | 'dataProvider' => $dataProvider, 19 | 'columns' => [ 20 | 'filename', 21 | 'size:shortSize', 22 | [ 23 | 'class' => ActionColumn::class, 24 | 'template' => '{view}', 25 | 'buttons' => [ 26 | 'view' => function ($url, $data) { 27 | $span = Html::tag('i', '', ['class' => 'glyphicon glyphicon-eye-open']); 28 | return Html::a($span, ['file/doc', 'file' => $data['filename']], ['target' => '_blank']); 29 | } 30 | ] 31 | ] 32 | ] 33 | ]); 34 | Panel::end(); -------------------------------------------------------------------------------- /views/default/export.php: -------------------------------------------------------------------------------- 1 | 'alert alert-danger']); -------------------------------------------------------------------------------- /views/default/files.php: -------------------------------------------------------------------------------- 1 | title = "Список временных файлов ({$this->context->module->tmpDir})"; 13 | 14 | Panel::begin(); 15 | echo Html::a('Очистить всё', ['default/clear-tmp'], [ 16 | 'class' => ['btn btn-warning'], 17 | 'data-confirm' => 'Очистить все временные файлы?' 18 | ]); 19 | 20 | echo "
"; 21 | 22 | echo GridView::widget([ 23 | 'dataProvider' => $dataProvider, 24 | 'columns' => [ 25 | 'filename', 26 | 'size:shortSize', 27 | [ 28 | 'class' => ActionColumn::class, 29 | 'template' => '{download}', 30 | 'buttons' => [ 31 | 'download' => function ($url, $data) { 32 | $span = Html::tag('i', '', ['class' => 'glyphicon glyphicon-download-alt']); 33 | return Html::a($span, ['default/download', 'file' => $data['filename']]); 34 | } 35 | ] 36 | ] 37 | ] 38 | ]); 39 | Panel::end(); -------------------------------------------------------------------------------- /views/default/import.php: -------------------------------------------------------------------------------- 1 | 'alert alert-danger']); 7 | 8 | echo Html::a('Импорт товаров', [ 9 | '/1c_exchange.php', 10 | 'mode' => 'import', 11 | 'type' => 'catalog', 12 | 'filename' => 'import.xml' 13 | ], ['class' => 'btn btn-primary', 'target' => '_blank']); 14 | echo Html::a('Импорт предложений', [ 15 | '/1c_exchange.php', 16 | 'mode' => 'import', 17 | 'type' => 'catalog', 18 | 'filename' => 'offers.xml' 19 | ], ['class' => 'btn btn-primary', 'target' => '_blank']); 20 | 21 | $form = ActiveForm::begin(); 22 | echo Html::submitButton('Start'); 23 | ActiveForm::end(); 24 | -------------------------------------------------------------------------------- /views/default/index.php: -------------------------------------------------------------------------------- 1 | title = ''; 9 | ?> 10 |
11 |
12 |
13 |
14 |

Добро пожаловать в модуль обмена товарами с 1С

15 |

Этот модуль поможет вам настроить обмен с Вашим сайтом и 1С Предприятие: Управление торговлей 16 | или розница, так же модуль может обмениваться документами с 1С.

17 |

Чтобы начать интеграцию, прочитайте

18 |

Описание находится еще в стадии наполнения, могут присутсвовать ошибки и неточности.

19 |

Если есть вопросы по настройки или возможностям, пишите на странице репозитория, мне на почту info@carono.ru или в телеграм Carno59

20 |
21 |
22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 | 31 |
32 |
33 |
34 |
35 | 36 | -------------------------------------------------------------------------------- /views/default/interfaces.php: -------------------------------------------------------------------------------- 1 | title = 'Список интерфейсов'; 14 | 15 | $module = Yii::$app->controller->module; 16 | 17 | $reflection = new ReflectionClass($module); 18 | $properties = array_filter($reflection->getProperties(), function ($data) { 19 | return StringHelper::endsWith($data->name, 'Class'); 20 | }); 21 | 22 | Panel::begin(); 23 | echo GridView::widget([ 24 | 'dataProvider' => new \yii\data\ArrayDataProvider(['allModels' => $properties]), 25 | 'columns' => [ 26 | 'name', 27 | [ 28 | 'attribute' => 'class', 29 | 'value' => function ($data) use ($module) { 30 | return $module->{$data->name}; 31 | } 32 | ], 33 | [ 34 | 'class' => ActionColumn::class, 35 | 'template' => '{testing}', 36 | 'buttons' => [ 37 | 'testing' => function ($url, $data) use ($module) { 38 | if ($module->{$data->name}) { 39 | $span = Html::tag('i', '', ['class' => 'glyphicon glyphicon-cog']); 40 | return Html::a($span, ['interface/check', 'variable' => $data->name]); 41 | } else { 42 | return null; 43 | } 44 | } 45 | ] 46 | ] 47 | ] 48 | ]); 49 | Panel::end(); -------------------------------------------------------------------------------- /views/default/list.php: -------------------------------------------------------------------------------- 1 | title = 'Монитор запросов'; 14 | 15 | if (!Yii::$app->controller->module->debug) { 16 | echo Html::tag('div', 'Требуется включить debug режим в модуле', ['class' => 'alert alert-danger']); 17 | return; 18 | } 19 | Panel::begin(); 20 | echo Html::a('Очистить всё', ['default/clear-monitor'], [ 21 | 'class' => ['btn btn-warning'], 22 | 'data-confirm' => 'Очистить все временные файлы?' 23 | ]); 24 | 25 | echo "
"; 26 | 27 | echo GridView::widget([ 28 | 'dataProvider' => $dataProvider, 29 | 'columns' => [ 30 | 'url', 31 | 'route', 32 | 'get', 33 | 'post', 34 | 'user_id', 35 | 'http_code', 36 | 'response', 37 | 'created_at:datetime' 38 | ] 39 | ]); 40 | Panel::end(); -------------------------------------------------------------------------------- /views/default/settings.php: -------------------------------------------------------------------------------- 1 | title = 'Настройки модуля'; 10 | Panel::begin(); 11 | echo DetailView::widget([ 12 | 'model' => Yii::$app->controller->module, 13 | 'attributes' => [ 14 | 'exchangeDocuments:boolean', 15 | 'debug:boolean', 16 | 'productClass', 17 | 'documentClass', 18 | 'groupClass', 19 | 'partnerClass', 20 | 'offerClass', 21 | 'useZip:boolean', 22 | 'tmpDir', 23 | 'validateModelOnSave:boolean', 24 | 'timeLimit' 25 | ] 26 | ]); 27 | Panel::end(); -------------------------------------------------------------------------------- /views/interface/check.php: -------------------------------------------------------------------------------- 1 | 20 | 21 |
22 |
23 | model) { 25 | echo Html::tag('div', "Модель найдена, PK = " . $interfaceTest->model->primaryKey, ['class' => 'alert alert-success']); 26 | } 27 | $form = ActiveForm::begin(['layout' => 'horizontal']); 28 | echo $form->field($interfaceTest, 'id')->textInput(['placeholder' => 'Найти модель через findOne()']); 29 | echo Html::submitButton('Протестировать', ['class' => 'btn btn-primary pull-right']); 30 | ActiveForm::end(); 31 | ?> 32 |
33 |
34 | 35 | title = "Класс $class"; 38 | $data = []; 39 | foreach (ClassHelper::getInterfaceMethods($interfaceClass) as $method) { 40 | $data[] = new InterfaceModel([ 41 | 'function' => $method, 42 | 'interface' => $interfaceClass, 43 | 'class' => $class 44 | ]); 45 | } 46 | echo GridView::widget([ 47 | 'dataProvider' => new ArrayDataProvider(['allModels' => $data]), 48 | 'rowOptions' => function (InterfaceModel $model) { 49 | if ($model->status_id == InterfaceModel::STATUS_METHOD_NOT_FOUND) { 50 | return ['class' => 'danger']; 51 | } 52 | return []; 53 | }, 54 | 'columns' => [ 55 | 'function', 56 | 'description:raw', 57 | 'status_name', 58 | ] 59 | ]); 60 | Panel::end(); -------------------------------------------------------------------------------- /views/layouts/main.php: -------------------------------------------------------------------------------- 1 | controller->id . '/' . Yii::$app->controller->action->id; 15 | $controller = Yii::$app->controller->id; 16 | 17 | $bundle = AppAsset::register($this); 18 | $ico = $this->assetManager->publish('@vendor/carono/yii2-1c-exchange/assets/other/favicon.ico'); 19 | $this->beginPage(); 20 | ?> 21 | 22 | 23 | 24 | 25 | 26 | 27 | 1С Exchange - <?= $this->title ?> 28 | head() ?> 29 | 30 | 31 | 32 | beginBody() ?> 33 | 54 | 55 | 56 | 120 | 121 |
122 |
123 | ArrayHelper::getValue($this->params, 'breadcrumbs', []), 126 | 'options' => [ 127 | 'class' => 'breadcrumb col-lg-7' 128 | ], 129 | 'homeLink' => [ 130 | 'label' => '', 131 | 'encode' => false, 132 | 'url' => ['default/index'] 133 | ] 134 | ]); 135 | ?> 136 |
137 | ArrayHelper::getValue($this->params, 'buttons', []), 140 | 'linkTemplate' => '{label}', 141 | 'itemOptions' => ['tag' => false], 142 | 'options' => [ 143 | 'tag' => 'div', 144 | 'class' => ['btn-group pull-right'], 145 | ], 146 | ]); 147 | ?> 148 |
149 |
150 | 151 |
152 |
153 |

title ?>

154 |
155 |
156 | 157 | 158 | 159 |
160 | 161 | endBody() ?> 162 | 163 | 164 | 165 | endPage() ?> 166 | 167 | -------------------------------------------------------------------------------- /views/partial/find-model.php: -------------------------------------------------------------------------------- 1 | 9 |
10 |
11 | controller->module->{$variable}; 13 | $interfaceTest = InterfaceTest::findByClass($class); 14 | 15 | $hint = ''; 16 | if ($interfaceTest->model) { 17 | $hint = "Модель найдена, $class::PK = " . $interfaceTest->model->primaryKey; 18 | } 19 | $form = ActiveForm::begin(); 20 | echo $form->field($interfaceTest, 'class')->hiddenInput(['value' => $class])->label(false); 21 | echo $form->field($interfaceTest, 'id')->textInput(['placeholder' => "Найти модель $class через findOne()"])->hint($hint); 22 | echo Html::submitButton('Найти', ['class' => 'btn btn-primary pull-right']); 23 | ActiveForm::end(); 24 | ?> 25 |
26 |
-------------------------------------------------------------------------------- /views/testing/index.php: -------------------------------------------------------------------------------- 1 | title = 'Тестирование модуля'; 15 | echo Html::tag('div', 'В разработке', ['class' => 'alert alert-danger']); 16 | if (YII_ENV_PROD) { 17 | ?> 18 |
19 | Проводить тестирование в окружении YII_ENV_PROD невозможно. 20 |
21 | 26 |
27 | Внимание! Будет происходить тестирование вашей реализации методов. 28 |
29 | ['testing/index', 'class' => 'TestingGroupClass'], 33 | 'productClass' => ['testing/index', 'class' => 'TestingProductClass'], 34 | 'documentClass' => ['testing/index', 'class' => 'TestingDocumentClass'], 35 | 'partnerClass' => ['testing/index', 'class' => 'TestingPartnerClass'], 36 | ]; 37 | ?> 38 |
39 |
40 | $link) { 42 | echo Html::a($name, $link, ['class' => 'btn btn-primary']); 43 | } 44 | ?> 45 |
46 |
47 | 48 | 49 | db->beginTransaction(); 55 | 56 | Panel::begin(); 57 | $testingProductClass = $testingClass::testImplementsClass(); 58 | 59 | 60 | echo TestingGridView::widget([ 61 | 'formatter' => [ 62 | 'class' => \yii\i18n\Formatter::class, 63 | 'nullDisplay' => '' 64 | ], 65 | 'caption' => $testingClass->caption, 66 | 'dataProvider' => new ArrayDataProvider(['allModels' => $testingClass::findAll()]), 67 | ]); 68 | 69 | Panel::end(); 70 | 71 | if ($resultClass) { 72 | Panel::begin(); 73 | $result = $resultClass->getResult(); 74 | if (is_array($result)) { 75 | echo GridView::widget(['dataProvider' => new ArrayDataProvider(['allModels' => $result])]); 76 | } elseif (is_string($result)) { 77 | echo $result; 78 | } elseif (is_object($result)) { 79 | echo \yii\widgets\DetailView::widget(['model' => $result]); 80 | } else { 81 | var_dump($result); 82 | } 83 | Panel::end(); 84 | } 85 | 86 | $transaction->rollBack(); -------------------------------------------------------------------------------- /views/widgets/panel.php: -------------------------------------------------------------------------------- 1 | context; 8 | $id = $context->id; 9 | ?> 10 |
11 |
12 |
13 |
14 |
15 | 16 |
17 |
18 |
19 |
20 |
-------------------------------------------------------------------------------- /widgets/Menu.php: -------------------------------------------------------------------------------- 1 | linkTemplate); 21 | return strtr($template, [ 22 | '{url}' => Html::encode(Url::to($item['url'])), 23 | '{label}' => $item['label'], 24 | '{options}' => trim(Html::renderTagAttributes(ArrayHelper::getValue($item, 'linkOptions', []))) 25 | ]); 26 | } 27 | $template = ArrayHelper::getValue($item, 'template', $this->labelTemplate); 28 | return strtr($template, [ 29 | '{label}' => $item['label'], 30 | ]); 31 | } 32 | } -------------------------------------------------------------------------------- /widgets/Panel.php: -------------------------------------------------------------------------------- 1 | getView()->render('@vendor/carono/yii2-1c-exchange/views/widgets/panel', ['content' => ob_get_clean()], $this); 18 | } 19 | } -------------------------------------------------------------------------------- /widgets/TestingGridView.php: -------------------------------------------------------------------------------- 1 | columns = [ 16 | 'name', 17 | 'expect', 18 | [ 19 | 'attribute' => 'comment', 20 | 'value' => function ($data) { 21 | /** 22 | * @var TestingClass $data 23 | */ 24 | if ($data->hasErrors()) { 25 | return Html::errorSummary($data); 26 | } 27 | return $data->comment; 28 | } 29 | ], 30 | [ 31 | 'class' => ActionColumn::class, 32 | 'header' => 'Result', 33 | 'template' => '{view}', 34 | 'buttons' => [ 35 | 'view' => function ($url, $data) { 36 | /** 37 | * @var TestingClass $data 38 | */ 39 | if ($data->method && !$data->isAutoTest()) { 40 | $span = Html::tag('i', '', [ 41 | 'class' => 'glyphicon glyphicon-eye-open', 42 | 'title' => "Выполнить метод {$data->method}" 43 | ]); 44 | return Html::a($span, [ 45 | 'testing/index', 46 | 'class' => (new \ReflectionClass($data))->getShortName(), 47 | 'result' => $data->method 48 | ]); 49 | } else { 50 | return $data->result; 51 | } 52 | } 53 | ] 54 | ] 55 | ]; 56 | parent::initColumns(); 57 | } 58 | 59 | public function init() 60 | { 61 | $this->rowOptions = function ($data) { 62 | /** 63 | * @var TestingClass $data 64 | */ 65 | $result = $data->testing(); 66 | if (($result === true || $data->hasResult()) && !$data->hasErrors()) { 67 | return ['class' => 'success']; 68 | } elseif ($result === false || $data->hasErrors()) { 69 | return ['class' => 'danger']; 70 | } else { 71 | return ['class' => 'warning']; 72 | } 73 | }; 74 | 75 | 76 | parent::init(); 77 | } 78 | } --------------------------------------------------------------------------------