├── .DS_Store
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── composer.json
├── resources
├── .DS_Store
└── img
│ └── plugin-logo.png
└── src
├── .DS_Store
├── Conditions.php
├── assets
└── ConditionsAssets.php
├── elements
└── Conditions.php
├── migrations
└── Install.php
├── models
└── ConditionalsModel.php
├── records
└── ConditionalsRecord.php
├── resources
├── .DS_Store
├── javascripts
│ ├── .DS_Store
│ ├── conditions-atest3dc3r.js
│ ├── modules
│ │ ├── builder.js
│ │ ├── fld.js
│ │ └── render.js
│ └── reasons.js
└── stylesheets
│ ├── .DS_Store
│ └── conditions-btest9098.css
├── services
└── ConditionsService.php
└── translations
└── en
└── conditions.php
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MilkshakeStudio/craft-conditions/1c334a49e908d562ea1459c5b4726d2cb90f5ec0/.DS_Store
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Conditions Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
6 |
7 | ## 1.0.0 - 2019-03-01
8 | ### Added
9 | - Initial release
10 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Milkshake Studio
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | # Conditions plugin for Craft CMS 3.x
7 | Conditions is taken from [Reasons for Craft 2.0](https://github.com/mmikkel/Reasons-Craft). Since it was not being rebuilt we decided to try and update it for 3.0.
8 |
9 |
10 |
11 | ## Conditions Roadmap
12 |
13 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "craftconditions/conditions",
3 | "description": "conditions on fields",
4 | "type": "craft-plugin",
5 | "version": "1.0.3",
6 | "keywords": [
7 | "craft",
8 | "cms",
9 | "craftcms",
10 | "craft-plugin",
11 | "conditions"
12 | ],
13 | "support": {
14 | "docs": "https://github.com/MilkshakeStudio/craft-conditions/",
15 | "issues": "https://github.com/MilkshakeStudio/craft-conditions/issues"
16 | },
17 | "license": "MIT",
18 | "authors": [
19 | {
20 | "name": "Milkshake Studio",
21 | "homepage": "http://milkshake.studio/"
22 | }
23 | ],
24 | "require": {
25 | "craftcms/cms": "^3.0.0-RC1"
26 | },
27 | "autoload": {
28 | "psr-4": {
29 | "craftconditions\\conditions\\": "src/"
30 | }
31 | },
32 | "extra": {
33 | "name": "Conditions",
34 | "handle": "conditions",
35 | "hasCpSettings": false,
36 | "hasCpSection": false,
37 | "changelogUrl": "???",
38 | "components": {
39 | "conditionsService": "craftconditions\\conditions\\services\\ConditionsService"
40 | },
41 | "class": "craftconditions\\conditions\\Conditions"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/resources/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MilkshakeStudio/craft-conditions/1c334a49e908d562ea1459c5b4726d2cb90f5ec0/resources/.DS_Store
--------------------------------------------------------------------------------
/resources/img/plugin-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MilkshakeStudio/craft-conditions/1c334a49e908d562ea1459c5b4726d2cb90f5ec0/resources/img/plugin-logo.png
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MilkshakeStudio/craft-conditions/1c334a49e908d562ea1459c5b4726d2cb90f5ec0/src/.DS_Store
--------------------------------------------------------------------------------
/src/Conditions.php:
--------------------------------------------------------------------------------
1 | types[] = ConditionsElement::class;
108 | }
109 | );
110 |
111 | // Do something after we're installed
112 | Event::on(
113 | Plugins::class,
114 | Plugins::EVENT_AFTER_INSTALL_PLUGIN,
115 | function (PluginEvent $event) {
116 | if ($event->plugin === $this) {
117 | // We were just installed
118 | }
119 | }
120 | );
121 |
122 | /**
123 | * Logging in Craft involves using one of the following methods:
124 | *
125 | * Craft::trace(): record a message to trace how a piece of code runs. This is mainly for development use.
126 | * Craft::info(): record a message that conveys some useful information.
127 | * Craft::warning(): record a warning message that indicates something unexpected has happened.
128 | * Craft::error(): record a fatal error that should be investigated as soon as possible.
129 | *
130 | * Unless `devMode` is on, only Craft::warning() & Craft::error() will log to `craft/storage/logs/web.log`
131 | *
132 | * It's recommended that you pass in the magic constant `__METHOD__` as the second parameter, which sets
133 | * the category to the method (prefixed with the fully qualified class name) where the constant appears.
134 | *
135 | * To enable the Yii debug toolbar, go to your user account in the AdminCP and check the
136 | * [] Show the debug toolbar on the front end & [] Show the debug toolbar on the Control Panel
137 | *
138 | * http://www.yiiframework.com/doc-2.0/guide-runtime-logging.html
139 | */
140 | Craft::info(
141 | Craft::t(
142 | 'conditions',
143 | '{name} plugin loaded',
144 | ['name' => $this->name]
145 | ),
146 | __METHOD__
147 | );
148 | if(Craft::$app->getRequest()->getIsCpRequest()) {
149 | if (Craft::$app->getRequest()->getIsAjax()) {
150 | $this->ProcessAfterLoad();
151 | } else {
152 |
153 | $this->includeAssets();
154 | Craft::$app->view->registerJs('if (window.Craft && window.Craft.ConditionsPlugin) {
155 | Craft.ConditionsPlugin.init('.$this->jsonToJs().');
156 | }');
157 | Event::on(Fields::class, Fields::EVENT_BEFORE_SAVE_FIELD_LAYOUT, function(Event $event) {
158 | $this->onSaveConditionalLayout($event);
159 | });
160 | }
161 | }
162 | }
163 | /**
164 | * include Javascript and css Assets
165 | */
166 | protected function includeAssets()
167 | {
168 | $this->view->registerAssetBundle(ConditionsAssets::class);
169 | }
170 |
171 |
172 | /**
173 | * @return string
174 | */
175 | protected function jsonToJs()
176 | {
177 | $data = array(
178 | 'expressions' => $this->getConditionalObj(),
179 | 'fldIds' => $this->getFieldIds(),
180 | 'conditionalFieldTypes' => $this->getAllConditionalFieldTypes(),
181 | 'conditionalFields' => $this->getAllConditionalFields(),
182 | );
183 | return json_encode($data);
184 | }
185 |
186 | /**
187 | * @return array
188 | */
189 | protected function getConditionalObj()
190 | {
191 | $resources = array();
192 | $sources = array();
193 |
194 | // Get Asset volumes
195 | $allAssetSources = Craft::$app->getVolumes()->getAllVolumes();
196 |
197 | if(!empty($allAssetSources))
198 | {
199 | foreach ($allAssetSources as $assetSource) {
200 | $sources['assetSource:' . $assetSource->id] = $assetSource->fieldLayoutId;
201 | }
202 | }
203 |
204 | // Get Tag groups
205 | $allTagGroups = Craft::$app->tags->getAllTagGroups();
206 | foreach ($allTagGroups as $tagGroup) {
207 | $sources['tagGroup:' . $tagGroup->id] = $tagGroup->fieldLayoutId;
208 | }
209 |
210 | // Get all Entry types records
211 |
212 | $entryTypeRecords = EntryTypeRecord::find()->all();
213 |
214 | if ($entryTypeRecords) {
215 | foreach ($entryTypeRecords as $entryType) {
216 | $sources['entryType:' . $entryType->id] = $entryType->fieldLayoutId;
217 | $sources['section:' . $entryType->sectionId] = $entryType->fieldLayoutId;
218 | }
219 | }
220 |
221 |
222 | // Get Global sets
223 | $allGlobalSets = Craft::$app->globals->getAllSets();
224 | foreach ($allGlobalSets as $globalSet) {
225 | $sources['globalSet:' . $globalSet->id] = $globalSet->fieldLayoutId;
226 | }
227 |
228 | // Get Category groups
229 | $allCategoryGroups = Craft::$app->categories->getAllGroups();
230 | foreach ($allCategoryGroups as $categoryGroup) {
231 | $sources['categoryGroup:' . $categoryGroup->id] = $categoryGroup->fieldLayoutId;
232 | }
233 |
234 |
235 | // Retrive Users Field Layout
236 | $usersFieldLayout = Craft::$app->fields->getLayoutByType('craft\elements\User');
237 |
238 |
239 |
240 | if ($usersFieldLayout) {
241 | $sources['users'] = $usersFieldLayout->id;
242 | }
243 |
244 |
245 | // Get conditionals Array
246 | $conArr = array();
247 | $tableSchema = Craft::$app->db->schema->getTableSchema('{{%conditions_conditionalsrecord}}');
248 | if ($tableSchema != null)
249 | {
250 | $conditionalsRecords = ConditionalsRecord::find()->all();
251 | if ($conditionalsRecords) {
252 | foreach ($conditionalsRecords as $conditionalsRecord) {
253 | $conditionalsModel = $conditionalsRecord;
254 | if ($conditionalsModel->expressions && $conditionalsModel->expressions != '') {
255 | $conArr['fieldLayout:' . $conditionalsModel->fieldLayoutId] = $conditionalsModel->expressions;
256 | }
257 | }
258 | }
259 | }
260 | // Conditionals to origin mapping
261 | foreach ($sources as $sourceId => $fieldLayoutId) {
262 | if (isset($conArr['fieldLayout:' . $fieldLayoutId])) {
263 | $resources[$sourceId] = $conArr['fieldLayout:' . $fieldLayoutId];
264 | }
265 | }
266 | return $resources;
267 |
268 | }
269 | /**
270 | * @param Event $event
271 | */
272 | public function onSaveConditionalLayout(Event $event)
273 | {
274 |
275 | $fldLayout = $event->layout;
276 | $cndlModel = new ConditionalsModel();
277 | $cndlModel->fieldLayoutId = $fldLayout->id;
278 |
279 | $cndlModel->expressions = Craft::$app->getRequest()->getBodyParam('_conditions');
280 | $conditionsService = new ConditionsService();
281 | $conditionsService->save($cndlModel);
282 | }
283 | /**
284 | * @return bool Ajax
285 | */
286 | protected function ProcessAfterLoad()
287 | {
288 |
289 | if (!Craft::$app->getRequest()->getIsPost()) {
290 | return false;
291 | }
292 |
293 | $segments = Craft::$app->request->segments;
294 | $actionSegment = $segments[count($segments) - 1];
295 |
296 | switch ($actionSegment) {
297 |
298 | case 'switch-entry-type' :
299 | Craft::$app->view->registerJs('Craft.ConditionsPlugin.FormLoad();');
300 | break;
301 |
302 | case 'get-editor-html' :
303 |
304 | $elementId = (int)Craft::$app->getRequest()->getBodyParam('elementId');
305 |
306 | $element = $elementId ? Craft::$app->getElements()->getElementById($elementId) : null;
307 | $elementType = $element ?Craft::$app->getElements()->getElementTypeById($elementId) : Craft::$app->getRequest()->getBodyParam('elementType');
308 | $attributes = Craft::$app->getRequest()->getBodyParam('attributes');
309 |
310 | $entityType = null;
311 |
312 | switch ($elementType) {
313 |
314 | case 'craft\elements\Entry' :
315 | if ($element) {
316 | $entityType = 'entryType:' . $element->type->id;
317 | } else if (isset($attributes['typeId'])) {
318 | $entityType = 'entryType:' . $attributes['typeId'];
319 | } else if (isset($attributes['sectionId'])) {
320 | $entryTypes = Craft::$app->sections->getEntryTypesBySectionId((int)$attributes['sectionId']);
321 | $entryType = $entryTypes ? array_shift($entryTypes) : false;
322 | $entityType = $entryType ? 'entryType:' . $entryType->id : null;
323 | }
324 | break;
325 |
326 | case 'craft\elements\GlobalSet' :
327 | $entityType = $element ? 'globalSet:' . $element->id : null;
328 | break;
329 |
330 | case 'craft\elements\Asset' :
331 |
332 | $entityType = $element ? 'assetSource:' . $element->volumeId : null;
333 | break;
334 |
335 | case 'craft\elements\Category' :
336 | $entityType = $element ? 'categoryGroup:' . $element->group->id : null;
337 | break;
338 |
339 | case 'craft\elements\Tag' :
340 | $entityType = $element ? 'tagGroup:' . $element->group->id : null;
341 | break;
342 |
343 | case 'craft\elements\User' :
344 | $entityType = 'users';
345 | break;
346 | }
347 |
348 | if ($entityType) {
349 | Craft::$app->view->registerJs('Craft.ConditionsPlugin.ElementEditorLoad("' . $entityType . '");');
350 | }
351 | break;
352 | }
353 | }
354 |
355 | /*
356 | * Returns all toggleable fields
357 | *
358 | */
359 | /**
360 | * @return array
361 | */
362 | protected function getAllConditionalFields()
363 | {
364 | $tgFields = array();
365 | $flds = Craft::$app->fields->getAllFields();
366 |
367 | $toggleFieldTypes = $this->getAllConditionalFieldTypes();
368 | foreach ($flds as $field) {
369 |
370 | $fieldType = join('', array_slice(explode('\\', get_class($field)), -1));
371 | $classHandle = $fieldType;
372 | if (!$classHandle) {
373 | continue;
374 | }
375 | if (in_array($classHandle, $toggleFieldTypes)) {
376 | $tgFields[] = array(
377 | 'id' => $field->id,
378 | 'handle' => $field->handle,
379 | 'name' => $field->name,
380 | 'type' => $classHandle,
381 | 'settings' => $field->settings,
382 | );
383 | }
384 | }
385 | return $tgFields;
386 | }
387 |
388 | /**
389 | * @return array
390 | */
391 | protected function getFieldIds()
392 | {
393 | $data = array();
394 | $flds = Craft::$app->fields->getAllFields();
395 | foreach ($flds as $field) {
396 | $data[$field->handle] = $field->id;
397 | }
398 | return $data;
399 | }
400 |
401 | /**
402 | * @return array
403 | */
404 | protected function getAllConditionalFieldTypes()
405 | {
406 | return array(
407 | 'PlainText',
408 | 'Number',
409 | 'Entries',
410 | 'SuperTableField',
411 | 'MultiSelect',
412 | 'Lightswitch',
413 | 'ButtonBox_Buttons',
414 | 'Tags',
415 | 'Dropdown',
416 | 'Assets',
417 | 'ButtonBox_Width',
418 | 'Checkboxes',
419 | 'ButtonBox_TextSize',
420 | 'Users',
421 | 'ButtonBox_Stars',
422 | 'RadioButtons',
423 | 'Calendar_Event',
424 | 'PositionSelect',
425 | 'Categories',
426 | 'ButtonBox_Colours',
427 | );
428 | }
429 |
430 | }
431 |
--------------------------------------------------------------------------------
/src/assets/ConditionsAssets.php:
--------------------------------------------------------------------------------
1 | sourcePath = '@craftconditions/conditions/resources';
78 |
79 | // define the dependencies
80 | $this->depends = [
81 | GarnishAsset::class,
82 | CpAsset::class,
83 | ];
84 | $cssFile = 'stylesheets/conditions-btest9098.css';
85 | $jsFile = 'javascripts/conditions-atest3dc3r.js';
86 | $this->js = [
87 | $jsFile
88 | ];
89 |
90 | $this->css = [
91 | $cssFile
92 | ];
93 |
94 | parent::init();
95 | }
96 |
97 | // Protected Methods
98 | // =========================================================================
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/src/elements/Conditions.php:
--------------------------------------------------------------------------------
1 | id(5)->one();
136 | *
137 | * // Find all assets and order them by their filename:
138 | * $assets = Asset::find()
139 | * ->orderBy('filename')
140 | * ->all();
141 | * ```
142 | *
143 | * If you want to define custom criteria parameters for your elements, you can do so by overriding
144 | * this method and returning a custom query class. For example,
145 | *
146 | * ```php
147 | * class Product extends Element
148 | * {
149 | * public static function find()
150 | * {
151 | * // use ProductQuery instead of the default ElementQuery
152 | * return new ProductQuery(get_called_class());
153 | * }
154 | * }
155 | * ```
156 | *
157 | * You can also set default criteria parameters on the ElementQuery if you don’t have a need for
158 | * a custom query class. For example,
159 | *
160 | * ```php
161 | * class Customer extends ActiveRecord
162 | * {
163 | * public static function find()
164 | * {
165 | * return parent::find()->limit(50);
166 | * }
167 | * }
168 | * ```
169 | *
170 | * @return ElementQueryInterface The newly created [[ElementQueryInterface]] instance.
171 | */
172 | public static function find(): ElementQueryInterface
173 | {
174 | return new ElementQuery(get_called_class());
175 | }
176 |
177 | /**
178 | * Defines the sources that elements of this type may belong to.
179 | *
180 | * @param string|null $context The context ('index' or 'modal').
181 | *
182 | * @return array The sources.
183 | * @see sources()
184 | */
185 | protected static function defineSources(string $context = null): array
186 | {
187 | $sources = [];
188 |
189 | return $sources;
190 | }
191 |
192 | // Public Methods
193 | // =========================================================================
194 |
195 | /**
196 | * Returns the validation rules for attributes.
197 | *
198 | * Validation rules are used by [[validate()]] to check if attribute values are valid.
199 | * Child classes may override this method to declare different validation rules.
200 | *
201 | * More info: http://www.yiiframework.com/doc-2.0/guide-input-validation.html
202 | *
203 | * @return array
204 | */
205 | public function rules()
206 | {
207 | return [
208 | ['someAttribute', 'string'],
209 | ['someAttribute', 'default', 'value' => 'Some Default'],
210 | ];
211 | }
212 |
213 | /**
214 | * Returns whether the current user can edit the element.
215 | *
216 | * @return bool
217 | */
218 | public function getIsEditable(): bool
219 | {
220 | return true;
221 | }
222 |
223 | /**
224 | * Returns the field layout used by this element.
225 | *
226 | * @return FieldLayout|null
227 | */
228 | public function getFieldLayout()
229 | {
230 | $tagGroup = $this->getGroup();
231 |
232 | if ($tagGroup) {
233 | return $tagGroup->getFieldLayout();
234 | }
235 |
236 | return null;
237 | }
238 |
239 | public function getGroup()
240 | {
241 | if ($this->groupId === null) {
242 | throw new InvalidConfigException('Tag is missing its group ID');
243 | }
244 |
245 | if (($group = Craft::$app->getTags()->getTagGroupById($this->groupId)) === null) {
246 | throw new InvalidConfigException('Invalid tag group ID: '.$this->groupId);
247 | }
248 |
249 | return $group;
250 | }
251 |
252 | // Indexes, etc.
253 | // -------------------------------------------------------------------------
254 |
255 | /**
256 | * Returns the HTML for the element’s editor HUD.
257 | *
258 | * @return string The HTML for the editor HUD
259 | */
260 | public function getEditorHtml(): string
261 | {
262 | $html = Craft::$app->getView()->renderTemplateMacro('_includes/forms', 'textField', [
263 | [
264 | 'label' => Craft::t('app', 'Title'),
265 | 'siteId' => $this->siteId,
266 | 'id' => 'title',
267 | 'name' => 'title',
268 | 'value' => $this->title,
269 | 'errors' => $this->getErrors('title'),
270 | 'first' => true,
271 | 'autofocus' => true,
272 | 'required' => true
273 | ]
274 | ]);
275 |
276 | $html .= parent::getEditorHtml();
277 |
278 | return $html;
279 | }
280 |
281 | // Events
282 | // -------------------------------------------------------------------------
283 |
284 | /**
285 | * Performs actions before an element is saved.
286 | *
287 | * @param bool $isNew Whether the element is brand new
288 | *
289 | * @return bool Whether the element should be saved
290 | */
291 | public function beforeSave(bool $isNew): bool
292 | {
293 | return true;
294 | }
295 |
296 | /**
297 | * Performs actions after an element is saved.
298 | *
299 | * @param bool $isNew Whether the element is brand new
300 | *
301 | * @return void
302 | */
303 | public function afterSave(bool $isNew)
304 | {
305 | }
306 |
307 | /**
308 | * Performs actions before an element is deleted.
309 | *
310 | * @return bool Whether the element should be deleted
311 | */
312 | public function beforeDelete(): bool
313 | {
314 | return true;
315 | }
316 |
317 | /**
318 | * Performs actions after an element is deleted.
319 | *
320 | * @return void
321 | */
322 | public function afterDelete()
323 | {
324 | }
325 |
326 | /**
327 | * Performs actions before an element is moved within a structure.
328 | *
329 | * @param int $structureId The structure ID
330 | *
331 | * @return bool Whether the element should be moved within the structure
332 | */
333 | public function beforeMoveInStructure(int $structureId): bool
334 | {
335 | return true;
336 | }
337 |
338 | /**
339 | * Performs actions after an element is moved within a structure.
340 | *
341 | * @param int $structureId The structure ID
342 | *
343 | * @return void
344 | */
345 | public function afterMoveInStructure(int $structureId)
346 | {
347 | }
348 | }
349 |
--------------------------------------------------------------------------------
/src/migrations/Install.php:
--------------------------------------------------------------------------------
1 | driver = Craft::$app->getConfig()->getDb()->driver;
60 | if ($this->createTables()) {
61 |
62 | $this->createIndexes();
63 | // $this->addForeignKeys();
64 | // Refresh the db schema caches
65 | Craft::$app->db->schema->refresh();
66 | $this->insertDefaultData();
67 | }
68 |
69 | return true;
70 | }
71 |
72 | /**
73 | * This method contains the logic to be executed when removing this migration.
74 | * This method differs from [[down()]] in that the DB logic implemented here will
75 | * be enclosed within a DB transaction.
76 | * Child classes may implement this method instead of [[down()]] if the DB logic
77 | * needs to be within a transaction.
78 | *
79 | * @return boolean return a false value to indicate the migration fails
80 | * and should not proceed further. All other return values mean the migration succeeds.
81 | */
82 | public function safeDown()
83 | {
84 | $this->driver = Craft::$app->getConfig()->getDb()->driver;
85 | $this->removeTables();
86 |
87 | return true;
88 | }
89 |
90 | // Protected Methods
91 | // =========================================================================
92 |
93 | /**
94 | * Creates the tables needed for the Records used by the plugin
95 | *
96 | * @return bool
97 | */
98 | protected function createTables()
99 | {
100 | $tablesCreated = false;
101 |
102 | // conditions_conditionalsrecord table
103 | $tableSchema = Craft::$app->db->schema->getTableSchema('{{%conditions_conditionalsrecord}}');
104 | if ($tableSchema === null) {
105 | $tablesCreated = true;
106 | $this->createTable(
107 | '{{%conditions_conditionalsrecord}}',
108 | [
109 | 'id' => $this->primaryKey(),
110 | 'fieldLayoutId' => $this->integer()->notNull(),
111 | 'expressions' => $this->text()->notNull(),
112 | 'dateCreated' => $this->dateTime()->notNull(),
113 | 'dateUpdated' => $this->dateTime()->notNull(),
114 | 'uid' => $this->uid(),
115 | 'siteId' => $this->integer()->notNull()->defaultValue(1),
116 | 'some_field' => $this->string(255)->notNull()->defaultValue('')
117 | ]
118 | );
119 | }
120 |
121 | return $tablesCreated;
122 | }
123 |
124 | /**
125 | * Creates the indexes needed for the Records used by the plugin
126 | *
127 | * @return void
128 | */
129 | protected function createIndexes()
130 | {
131 | // conditions_conditionalsrecord table
132 | /* $this->createIndex(
133 | $this->db->getIndexName(
134 | '{{%conditions_conditionalsrecord}}',
135 | 'some_field',
136 | true
137 | ),
138 |
139 | '{{%conditions_conditionalsrecord}}',
140 | 'some_field',
141 | true
142 | );
143 | */
144 | // Additional commands depending on the db driver
145 | switch ($this->driver) {
146 | case DbConfig::DRIVER_MYSQL:
147 | break;
148 | case DbConfig::DRIVER_PGSQL:
149 | break;
150 | }
151 | }
152 |
153 | /**
154 | * Creates the foreign keys needed for the Records used by the plugin
155 | *
156 | * @return void
157 | */
158 | protected function addForeignKeys()
159 | {
160 | // conditions_conditionalsrecord table
161 | $this->addForeignKey(
162 | $this->db->getForeignKeyName('{{%conditions_conditionalsrecord}}', 'siteId'),
163 | '{{%conditions_conditionalsrecord}}',
164 | 'siteId',
165 | '{{%sites}}',
166 | 'id',
167 | 'CASCADE',
168 | 'CASCADE'
169 | );
170 | }
171 |
172 | /**
173 | * Populates the DB with the default data.
174 | *
175 | * @return void
176 | */
177 | protected function insertDefaultData()
178 | {
179 | }
180 |
181 | /**
182 | * Removes the tables needed for the Records used by the plugin
183 | *
184 | * @return void
185 | */
186 | protected function removeTables()
187 | {
188 | // conditions_conditionalsrecord table
189 | $this->dropTableIfExists('{{%conditions_conditionalsrecord}}');
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/src/models/ConditionalsModel.php:
--------------------------------------------------------------------------------
1 | 'Some Default'],
62 | ];
63 | }
64 | protected function defineAttributes()
65 | {
66 | return array(
67 | 'id' => AttributeType::Number,
68 | 'fieldLayoutId' => AttributeType::Number,
69 | 'expressions' => AttributeType::Mixed,
70 | );
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/records/ConditionalsRecord.php:
--------------------------------------------------------------------------------
1 | array(AttributeType::Number),
64 | 'expressions' => array(AttributeType::Mixed),
65 | );
66 |
67 | }
68 | /**
69 | * @access public
70 | * @return array
71 | */
72 |
73 | public function defineRelations()
74 | {
75 | return array(
76 | 'fieldLayout' => array(
77 | static::BELONGS_TO,
78 | 'FieldLayoutRecord',
79 | 'fieldLayoutId',
80 | 'onDelete' => static::CASCADE,
81 | ),
82 | );
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/resources/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MilkshakeStudio/craft-conditions/1c334a49e908d562ea1459c5b4726d2cb90f5ec0/src/resources/.DS_Store
--------------------------------------------------------------------------------
/src/resources/javascripts/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MilkshakeStudio/craft-conditions/1c334a49e908d562ea1459c5b4726d2cb90f5ec0/src/resources/javascripts/.DS_Store
--------------------------------------------------------------------------------
/src/resources/javascripts/conditions-atest3dc3r.js:
--------------------------------------------------------------------------------
1 | ! function (e) {
2 |
3 | function t(s) {
4 | if (i[s]) return i[s].exports;
5 | var n = i[s] = {
6 | exports: {},
7 | id: s,
8 | loaded: !1
9 | };
10 | return e[s].call(n.exports, n, n.exports, t), n.loaded = !0, n.exports
11 | }
12 | var i = {};
13 | return t.m = e, t.c = i, t.p = "javascripts/", t(0)
14 | }([function (e, t, i) {
15 |
16 | e.exports = i(1)
17 | }, function (e, t, i) {
18 | "use strict";
19 | ! function (e) {
20 | /*** action */
21 | return !!e.Craft && void(Craft.ConditionsPlugin = {
22 | FieldLayoutDesigner: i(2),
23 | ConditionalsRenderer: i(4),
24 | ASSET_SOURCE_HANDLE: "assetSource",
25 | CATEGORY_GROUP_HANDLE: "categoryGroup",
26 | TAG_GROUP_HANDLE: "tagGroup",
27 | GLOBAL_SET_HANDLE: "globalSet",
28 | ENTRY_TYPE_HANDLE: "entryType",
29 | SECTION_HANDLE: "section",
30 | USERS_HANDLE: "users",
31 | FIELDS_HANDLE: "field",
32 | SOLSPACE_CALENDAR_HANDLE: "solspace-calendar",
33 | ASSET_SOURCE_ACTION: "volumes/save-volume",
34 | CATEGORY_ACTION: "categories/save-category",
35 | CATEGORY_GROUP_ACTION: "categories/save-group",
36 | TAG_ACTION: "tag-manager/save-tag",
37 | TAG_GROUP_ACTION: "tags/save-tag-group",
38 | GLOBAL_SET_CONTENT_ACTION: "globals/save-content",
39 | GLOBAL_SET_ACTION: "globals/save-set",
40 | ENTRY_ACTION: "entries/save-entry",
41 | ENTRY_REVISION_ACTION: "entry-revisions/save-draft",
42 | ENTRY_TYPE_ACTION: "sections/save-entry-type",
43 | USERS_ACTION: "users/save-user",
44 | USERS_FIELDS_ACTION: "users/save-field-layout",
45 | FIELDS_ACTION: "fields/save-field",
46 | SOLSPACE_CALENDAR_EVENTS_ACTION: "calendar/events/save-event",
47 | SOLSPACE_CALENDAR_SETTINGS_ACTION: "calendar/calendars/save-calendar",
48 | SOLSPACE_CALENDAR_LEGACY_SETTINGS_ACTION: "calendar/settings/save-settings",
49 | RENDER_CONTEXT: "render",
50 | LAYOUT_DESIGNER_CONTEXT: "fld",
51 | FIELD_DESIGNER_CONTEXT: "field",
52 | init: function (e) {
53 | this.data = e, this.initPrimaryForm();
54 |
55 | },
56 | initPrimaryForm: function () {
57 | this.destroyPrimaryForm(), Garnish.requestAnimationFrame(function () {
58 |
59 | var e = Craft.cp.$primaryForm && Craft.cp.$primaryForm.length ? Craft.cp.$primaryForm : $("#content form:first");
60 |
61 | e && e.length && (this.primaryForm = this.initForm(e));
62 |
63 | }.bind(this));
64 |
65 | },
66 | destroyPrimaryForm: function () {
67 | this.primaryForm && (this.primaryForm.destroy(), delete this.primaryForm)
68 | },
69 | initElementEditor: function (e) {
70 | //alert('qqqqq');
71 | //console.log(e);
72 | var t = this.getConditionals(e);
73 |
74 | if (!t) return !1;
75 | var i = (new Date).getTime(),
76 | s = function () {
77 | var e = (new Date).getTime(),
78 | n = $(".elementeditor:last"),
79 | a = n.length > 0 && n.closest(".hud"),
80 | r = !!(a && a.length > 0) && a.data("elementEditor"),
81 | o = !!r && r.$form;
82 | o ? (r._conditionsForm = new this.ConditionalsRenderer(o, t), r.hud.on("hide", $.proxy(this.destroyElementEditorForm, this, r))) : e - i < 2e3 && Garnish.requestAnimationFrame(s)
83 | }.bind(this);
84 | s()
85 | },
86 | destroyElementEditorForm: function (e) {
87 | var t = e._conditionsForm || null;
88 | t && (t.destroy(), delete e._conditionsForm)
89 | },
90 | initForm: function (e) {
91 |
92 | var t = this.getElementSourceFromForm(e);
93 |
94 | i = !!t && this.getFormContext(e);
95 | /*
96 | alert('ddd');
97 | console.log(e);
98 | console.log(t);
99 | */
100 |
101 | if (!t || !i) return !1;
102 | var s = t.type + (t.id ? ":" + t.id : ""),
103 | n = this.getConditionals(s);
104 |
105 | switch (i) {
106 | case this.LAYOUT_DESIGNER_CONTEXT:
107 |
108 | return new this.FieldLayoutDesigner(e, n);
109 | case this.FIELD_DESIGNER_CONTEXT:
110 | return null;
111 | case this.RENDER_CONTEXT:
112 | return n ? new this.ConditionalsRenderer(e, n) : null
113 | }
114 | return null
115 | },
116 | getConditionals: function (e) {
117 | //alert('qqqqqxx');
118 | console.log(e);
119 | // alert('getConditionals');
120 | // console.log('xxxx');
121 | // console.log(e);
122 | // console.log(JSON.parse(this.data.conditionals[e]));
123 | return e ? this.data.conditionals && this.data.conditionals.hasOwnProperty(e) ? JSON.parse(this.data.conditionals[e]): null : this.data.conditionals || {}
124 | },
125 | getToggleFields: function () {
126 | return this.data.toggleFields ? this.data.toggleFields : []
127 | },
128 | getToggleFieldById: function (e) {
129 | e = parseInt(e);
130 | for (var t = this.getToggleFields(), i = t.length, s = 0; s < i; ++s)
131 | if (parseInt(t[s].id) === e) return t[s];
132 | return !1
133 | },
134 | getFieldIds: function () {
135 | return this.data.fieldIds ? this.data.fieldIds : {}
136 | },
137 | getFieldIdByHandle: function (e) {
138 | var t = this.getFieldIds();
139 | return !(!t || !t.hasOwnProperty(e)) && t[e]
140 | },
141 | getToggleFieldTypes: function () {
142 | return this.data.toggleFieldTypes ? this.data.toggleFieldTypes : []
143 | },
144 | getElementSourceFromForm: function (e) {
145 |
146 | if (e.data("elementEditor")) return !1;
147 |
148 | var t = e.find('input[type="hidden"][name="namespace"]').val();
149 | t && (t += "-");
150 | var i, s, n = e.find('input[type="hidden"][name="action"]').val();
151 |
152 | switch (n) {
153 | case this.ASSET_SOURCE_ACTION:
154 | i = this.ASSET_SOURCE_HANDLE, s = 'input[type="hidden"][name="volumeId"]';
155 | break;
156 | case this.CATEGORY_ACTION:
157 | case this.CATEGORY_GROUP_ACTION:
158 | i = this.CATEGORY_GROUP_HANDLE, s = 'input[type="hidden"][name="groupId"]';
159 | break;
160 | case this.GLOBAL_SET_CONTENT_ACTION:
161 | case this.GLOBAL_SET_ACTION:
162 | i = this.GLOBAL_SET_HANDLE, s = 'input[type="hidden"][name="setId"]';
163 | break;
164 | case this.ENTRY_ACTION:
165 | case this.ENTRY_REVISION_ACTION:
166 | var a = e.find('select#entryType, input[type="hidden"][name="entryTypeId"], input[type="hidden"][name="typeId"], #' + t + "entryType");
167 | i = a.length ? this.ENTRY_TYPE_HANDLE : this.SECTION_HANDLE, s = a.length ? 'select#entryType, input[type="hidden"][name="entryTypeId"], input[type="hidden"][name="typeId"], #' + t + "entryType" : 'input[type="hidden"][name="sectionId"], #' + t + "section";
168 | break;
169 | case this.ENTRY_TYPE_ACTION:
170 | i = this.ENTRY_TYPE_HANDLE, s = 'input[type="hidden"][name="entryTypeId"]';
171 |
172 | break;
173 | case this.TAG_ACTION:
174 | case this.TAG_GROUP_ACTION:
175 | i = this.TAG_GROUP_HANDLE, s = 'input[type="hidden"][name="tagGroupId"], input[type="hidden"][name="groupId"]';
176 | break;
177 | case this.USERS_ACTION:
178 | case this.USERS_FIELDS_ACTION:
179 | i = this.USERS_HANDLE;
180 | break;
181 | case this.FIELDS_ACTION:
182 | i = this.FIELDS_HANDLE, s = 'input[type="hidden"][name="fieldId"]';
183 | break;
184 | case this.SOLSPACE_CALENDAR_LEGACY_SETTINGS_ACTION:
185 | i = this.SOLSPACE_CALENDAR_HANDLE;
186 | break;
187 | case this.SOLSPACE_CALENDAR_EVENTS_ACTION:
188 | i = this.SOLSPACE_CALENDAR_HANDLE, s = 'input[type="hidden"][name="calendarEvent[calendarId]"]';
189 | break;
190 | case this.SOLSPACE_CALENDAR_SETTINGS_ACTION:
191 | i = this.SOLSPACE_CALENDAR_HANDLE, s = 'input[type="hidden"][name="calendarId"]';
192 | break;
193 | case this.COMMERCE_PRODUCT_TYPE_ACTION:
194 | case this.COMMERCE_PRODUCT_ACTION:
195 | i = this.COMMERCE_PRODUCT_TYPE_HANDLE, s = 'input[type="hidden"][name="typeId"]'
196 | }
197 | /* code added by firoz */
198 |
199 |
200 |
201 | /* code added by firoz end */
202 | return !!i && {
203 | type: i,
204 | id: !!s && 0 | e.find(s).val()
205 | }
206 | },
207 | getFormContext: function (e) {
208 |
209 | if (e.data("elementEditor")) return !1;
210 | var t = e.find('input[type="hidden"][name="action"]').val();
211 | /**** hidden action field value **/
212 | switch (t) {
213 | case this.GLOBAL_SET_CONTENT_ACTION:
214 | case this.ENTRY_ACTION:
215 | case this.ENTRY_REVISION_ACTION:
216 | case this.TAG_ACTION:
217 | case this.CATEGORY_ACTION:
218 | case this.USERS_ACTION:
219 | case this.SOLSPACE_CALENDAR_EVENTS_ACTION:
220 | case this.COMMERCE_PRODUCT_ACTION:
221 | return this.RENDER_CONTEXT;
222 | case this.ASSET_SOURCE_ACTION:
223 | case this.CATEGORY_GROUP_ACTION:
224 | case this.GLOBAL_SET_ACTION:
225 | case this.ENTRY_TYPE_ACTION:
226 | case this.TAG_GROUP_ACTION:
227 | case this.USERS_FIELDS_ACTION:
228 | case this.SOLSPACE_CALENDAR_LEGACY_SETTINGS_ACTION:
229 | case this.SOLSPACE_CALENDAR_SETTINGS_ACTION:
230 | case this.COMMERCE_PRODUCT_TYPE_ACTION:
231 | return this.LAYOUT_DESIGNER_CONTEXT;
232 | case this.FIELDS_ACTION:
233 | return this.FIELD_DESIGNER_CONTEXT
234 | }
235 | return !1
236 | }
237 | })
238 | }(window), window.jQuery &&
239 | /*!
240 | * jQuery.fn.hasAttr()
241 | *
242 | * Copyright 2011, Rick Waldron
243 | * Licensed under MIT license.
244 | *
245 | */
246 | ! function (e) {
247 | e.fn.hasAttr = function (e) {
248 | for (var t = 0, i = this.length; t < i; t++)
249 | if (void 0 !== this.attr(e)) return !0;
250 | return !1
251 | }
252 | }(jQuery)
253 | },
254 |
255 | function (e, t, i) {
256 | "use strict";
257 |
258 | function s(e, t) {
259 | if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function")
260 | }
261 | var n = function () {
262 | function e(e, t) {
263 | for (var i = 0; i < t.length; i++) {
264 | var s = t[i];
265 | s.enumerable = s.enumerable || !1, s.configurable = !0, "value" in s && (s.writable = !0), Object.defineProperty(e, s.key, s)
266 | }
267 | }
268 | return function (t, i, s) {
269 | return i && e(t.prototype, i), s && e(t, s), t
270 | }
271 | }(),
272 | a = i(3);
273 |
274 | e.exports = function () {
275 |
276 | function e(t, i) {
277 |
278 | s(this, e), t && t.length && (this.$el = t, this.conditionals = i, this.settings = {
279 | formSelector: "form:first",
280 | fieldSettingsSelector: "a.settings",
281 | fieldSelector: ".fld-field",
282 | tabSelector: ".fld-tabs .fld-tab"
283 | }, this.templates = {
284 | input: function (e) {
285 | return ''
286 | },
287 | modal: function () {
288 | return '
'
289 | }
290 | }, this.init())
291 | }
292 | return n(e, [{
293 | key: "init",
294 | value: function () {
295 | var e = Craft.ConditionsPlugin.getToggleFields();
296 | this.toggleFieldIds = $.map(e, function (e) {
297 | return parseInt(e.id)
298 | }), this.$conditionalsInput = $(this.templates.input({
299 | name: "_conditions",
300 | type: "hidden"
301 | })), this.$conditionalsIdInput = $(this.templates.input({
302 | name: "_conditionsId",
303 | value: this.id || "",
304 | type: "hidden"
305 | })), this.$el.append(this.$conditionalsInput).append(this.$conditionalsIdInput).on("submit", $.proxy(this.onFormSubmit, this)), Garnish.requestAnimationFrame($.proxy(function () {
306 | this.refresh()
307 | }, this)), this.$el.on("mousedown", this.settings.fieldSelector, $.proxy(this.onFieldMouseDown, this)), Garnish.$doc.on("click", ".menu a", $.proxy(this.onFieldSettingsMenuItemClick, this))
308 | }
309 | }, {
310 | key: "destroy",
311 | value: function () {
312 | this.$el.off("mousedown", this.settings.fieldSelector, $.proxy(this.onFieldMouseDown, this)), Garnish.$doc.on("click", ".menu a", $.proxy(this.onFieldSettingsMenuItemClick, this))
313 | }
314 | }, {
315 | key: "refresh",
316 | value: function () {
317 |
318 | var e, t, i, s, n = this;
319 | var r = {};
320 |
321 | this.$el.find(this.settings.tabSelector).each(function () {
322 |
323 | var $fields = $(this).find(n.settings.fieldSelector);
324 | var s = [];
325 |
326 | $fields.each(function () {
327 | t = $(this);
328 | i = parseInt(t.data("id"));
329 |
330 | if (n.toggleFieldIds.indexOf(i) > -1) {
331 | var e = Craft.ConditionsPlugin.getToggleFieldById(i);
332 | e && s.push(e)
333 | }
334 | });
335 | $fields.each(function () {
336 | t = $(this), i = parseInt(t.data("id")), t.data("_conditionsBuilder") ? t.data("_conditionsBuilder").update({
337 | toggleFields: s
338 | }) : t.data("_conditionsBuilder", new a({
339 | fieldId: i,
340 | toggleFields: s,
341 | rules: n.conditionals && n.conditionals.hasOwnProperty(i) ? n.conditionals[i] : null
342 | }));
343 |
344 | var e = t.data("_conditionsBuilder").getConditionals();
345 | if (e ? (r[i] = e, t.addClass("conditionsHasConditionals")) : t.removeClass("conditionsHasConditionals"), !t.data("_conditionsSettingsMenuItemInitialized")) {
346 | var o = t.find(n.settings.fieldSettingsSelector),
347 | l = o.data("menubtn") || !1;
348 | if (!l) return;
349 | var d = l.menu.$container;
350 |
351 | d.find("ul").children(":first").clone(!0).insertBefore(d.find("ul:first li:last")).find("a:first").data("_conditionsField", t).attr("data-action", "toggle-conditionals").html("Edit conditionals"), t.data("_conditionsSettingsMenuItemInitialized", !0);
352 | d.find("ul").children().eq(1).find("a:first").html("Edit conditionals");
353 | }
354 | })
355 | }), 0 === Object.keys(r).length ? this.$conditionalsInput.attr("value", "") : this.$conditionalsInput.attr("value", JSON.stringify(r))
356 | }
357 | }, {
358 | key: "onFieldMouseDown",
359 | value: function (e) {
360 | var t = this,
361 | i = function e(i) {
362 | $("body").off("mouseup", e), Garnish.requestAnimationFrame(function () {
363 | t.refresh()
364 | })
365 | };
366 | $("body").on("mouseup", i)
367 | }
368 | }, {
369 | key: "onFieldSettingsMenuItemClick",
370 | value: function (e) {
371 | var $trigger = $(e.target),
372 | $field = $trigger.data('_conditionsField');
373 |
374 |
375 | if ($trigger.data('action') === 'toggle-conditionals')
376 | {
377 |
378 | e.preventDefault();
379 | e.stopPropagation();
380 |
381 | if (!$trigger.data('conditionsModal'))
382 | {
383 |
384 | // Create modal
385 | var self = this,
386 | builder = $field.data('_conditionsBuilder'),
387 | $modal = $(this.templates.modal());
388 |
389 | var modal = new Garnish.Modal($modal, {
390 | resizable : true,
391 | autoShow : false,
392 | onShow : function()
393 | {
394 | Garnish.requestAnimationFrame(function () {
395 | self.refresh();
396 | });
397 | },
398 | onHide : function()
399 | {
400 | Garnish.requestAnimationFrame(function () {
401 | self.refresh();
402 | });
403 | }
404 | });
405 |
406 | // Add builder to modal
407 | builder.get().appendTo($modal.find('.body'));
408 |
409 | $modal.on('click', '.close', function (e) {
410 | modal.hide();
411 | } );
412 |
413 | $trigger.data('conditionsModal', modal);
414 |
415 | }
416 |
417 | $trigger.data('conditionsModal').show();
418 |
419 | }
420 | Garnish.requestAnimationFrame($.proxy(function () {
421 | this.refresh()
422 | }, this))
423 | }
424 | }, {
425 | key: "onFormSubmit",
426 | value: function () {
427 | this.refresh()
428 | }
429 | }]), e
430 | }()
431 | }, function (e, t) {
432 | "use strict";
433 | var i = Garnish.Base.extend({
434 | $container: null,
435 | init: function (e) {
436 | this.setSettings(e, i.defaults);
437 | /* *** */
438 | //alert('optionstt');
439 | //console.log(e);
440 |
441 | this.templates = this.settings.templates;
442 | this.fieldId = this.settings.fieldId;
443 | this.$container = $(this.templates.builderUi());
444 | this.$builder = this.$container.find(".conditionsBuilder:first");
445 | this.$rule = this.$container.find(".conditionsRule:first").clone(true);
446 | this.$statement = this.$container.find(".conditionsStatement:first").clone(true);
447 | this.$statement.find(".conditionsRule").remove();
448 | this.$message = this.$container.find(".conditionsMessage:first");
449 | this.$container.on("click", ".conditionsAddRule", $.proxy(this.onConditionsAddRuleClick, this))
450 | .on("click", ".conditionsRemoveRule", $.proxy(this.onConditionsRemoveRuleClick, this))
451 | .on("click", ".conditionsAddStatement", $.proxy(this.onConditionsAddStatementClick, this))
452 | .on("change", ".conditionsRuleToggleField select", $.proxy(this.onConditionsRuleToggleFieldChange, this))
453 | .on("change", ".conditionsRuleCompare select", $.proxy(this.onConditionsRuleCompareChange, this))
454 | .on("change", ".conditionsRuleValue *:input", $.proxy(this.onConditionsRuleValueChange, this));
455 | this.$builder.html("");
456 |
457 | this.setToggleFields(this.settings.toggleFields);
458 |
459 |
460 |
461 | if (this.settings.rules && this.settings.rules.length > 0)
462 | {
463 | for (var t = 0; t < this.settings.rules.length; ++t)
464 | {
465 | this.addStatement({
466 | rules: this.settings.rules[t]
467 | });
468 | }
469 | }
470 | this.refresh(), i.instances.push(this)
471 | },
472 | get: function () {
473 | return this.$container
474 | },
475 | disable: function () {
476 | this.$container.addClass("disabled")
477 | },
478 | enable: function () {
479 | this.$container.removeClass("disabled")
480 | },
481 | update: function (e) {
482 | this.setSettings(e, this.settings), this.setToggleFields(this.settings.toggleFields), this.refresh()
483 | },
484 | setToggleFields : function (toggleFields)
485 | {
486 |
487 | if (!toggleFields) {
488 | return false;
489 | }
490 |
491 | this.settings.toggleFields = [];
492 | this.settings.toggleFieldIds = [];
493 |
494 | for(var i = 0; i < toggleFields.length; ++i){
495 | if (parseInt(toggleFields[i].id) !== this.fieldId){
496 | this.settings.toggleFields.push(toggleFields[i]);
497 | this.settings.toggleFieldIds.push(parseInt(toggleFields[i].id));
498 | }
499 | }
500 |
501 | // Update rule template
502 | var toggleFieldSelectOptions = '';
503 | for (var i = 0; i < this.settings.toggleFields.length; ++i){
504 | toggleFieldSelectOptions += this.templates.toggleSelectOption(this.settings.toggleFields[i]);
505 | }
506 | this.$rule.find('.conditionsRuleToggleField select').html(toggleFieldSelectOptions);
507 |
508 | },
509 | refresh: function () {
510 | this.settings.rules = [];
511 | var e = this.settings.toggleFields;
512 |
513 | if (0 === e.length) return this.disable(), this.$message.text("No toggle fields available."), !1;
514 | this.enable(), this.$message.text("");
515 | var t, i, s, n, a, r, o, l = this,
516 | d = this.$container.find(".conditionsStatement");
517 | d.each(function () {
518 | return t = [], i = $(this), s = i.find(".conditionsRule"), s.each(function () {
519 | n = $(this);
520 |
521 | if (a = n.find(".conditionsRuleToggleField select"), r = parseInt(a.val()), l.settings.toggleFieldIds.indexOf(r) === -1) return void n.remove();
522 | o = "";
523 | for (var i = 0; i < l.settings.toggleFields.length; ++i) o += l.templates.toggleSelectOption(e[i], parseInt(e[i].id) === r);
524 | a.html(o);
525 | //alert('rrrrr');
526 | //console.log(n);
527 | t.push({
528 | fieldId: r,
529 | compare: n.find(".conditionsRuleCompare select").val(),
530 | value: n.find(".conditionsRuleValue *:input:first").val()
531 | })
532 | }), 0 === t.length ? void i.remove() : void l.settings.rules.push(t)
533 | })
534 | },
535 | getConditionals: function () {
536 | return !!(this.settings.rules && this.settings.rules.length > 0) && this.settings.rules
537 | },
538 | addStatement: function (e) {
539 | e = $.extend({
540 | rules: !1
541 | }, e);
542 | var t = this.$statement.clone(!0),
543 | i = e.rules;
544 | if (this.$builder.append(t), i)
545 | for (var s = 0; s < i.length; ++s) this.addRule($.extend({
546 | target: t
547 | }, i[s]));
548 | else this.addRule({
549 | target: t
550 | });
551 | return t
552 | },
553 | addRule: function (e) {
554 | e = $.extend({
555 | fieldId: null,
556 | compare: null,
557 | value: null
558 | }, e);
559 | var t = this.$rule.clone(!0),
560 | i = e.target || this.$builder.find(".conditionsStatement:last"),
561 | s = e.fieldId,
562 | n = e.compare,
563 | a = e.value;
564 | if(s)
565 | {
566 | t.find(".conditionsRuleToggleField select").val(s);
567 | }
568 | if(i.length > 0)
569 | {
570 | i.find(".conditionsRules:first").append(t);
571 | }
572 | else {
573 | return false;
574 | }
575 | t.find(".conditionsRuleToggleField select").trigger("change");
576 | if(n)
577 | {
578 | t.find(".conditionsRuleCompare select").val(n);
579 | }
580 | if(a)
581 | {
582 | t.find(".conditionsRuleValue *:input:first").val(a);
583 | }
584 | /*
585 | alert('pppp');
586 | console.log(e);
587 | console.log(t);
588 | */
589 | return t;
590 | },
591 | onConditionsAddRuleClick: function (e) {
592 | e.preventDefault();
593 | var t = $(e.currentTarget).parents(".conditionsStatement");
594 | this.addRule({
595 | target: t
596 | })
597 | },
598 | onConditionsRemoveRuleClick: function (e) {
599 | e.preventDefault();
600 | var t = $(e.currentTarget),
601 | i = t.parents(".conditionsRule");
602 | i.remove(), this.refresh()
603 | },
604 | onConditionsAddStatementClick: function (e) {
605 | e.preventDefault(), this.addStatement()
606 | },
607 | onConditionsRuleToggleFieldChange: function (e) {
608 | e.preventDefault();
609 | var t = $(e.currentTarget),
610 | i = t.parents(".conditionsRule"),
611 | s = i.find(".conditionsRuleValue"),
612 | n = t.val(),
613 | a = Craft.ConditionsPlugin.getToggleFieldById(n),
614 | r = a.type,
615 | o = a.settings,
616 | superTableColumns = i.find(".conditionsRuleSuperTableColumns"),
617 | l = "";
618 | var superTableColsArr = "";
619 | switch (r) {
620 | case "Lightswitch":
621 | l = this.templates.select([{
622 | true:"on"
623 | }, {
624 | false: "off"
625 | }]);
626 | break;
627 | case "Dropdown":
628 | case "MultiSelect":
629 | case "Checkboxes":
630 | case "RadioButtons":
631 | case "ButtonBox_Buttons":
632 | case "ButtonBox_Colours":
633 | case "ButtonBox_TextSize":
634 | case "ButtonBox_Width":
635 | for (var d, u = o.options, h = [], c = 0; c < u.length; ++c) d = {}, d[u[c].value] = u[c].label, h.push(d);
636 | l = this.templates.select(h, "MultiSelect" === r || "Checkboxes" === r);
637 | break;
638 | case "Number":
639 | l = this.templates.number(o);
640 | break;
641 | case "ButtonBox_Stars":
642 | for (var d, f = parseInt(o.numStars) + 1, h = [], c = 0; c < f; ++c) d = {}, d["" + c] = c, h.push(d);
643 | l = this.templates.select(h);
644 | break;
645 | case "PositionSelect":
646 | for (var d, u = o.options, h = [], c = 0; c < u.length; ++c) d = {}, d[u[c]] = u[c].charAt(0).toUpperCase() + u[c].slice(1), h.push(d);
647 | l = this.templates.select(h);
648 | break;
649 | case "Entries":
650 | case "Categories":
651 | case "Tags":
652 | case "Assets":
653 | case "Users":
654 | case "Calendar_Event":
655 | var empty = "Empty";
656 | var notempty = "Not empty";
657 | var h = [{
658 | null: empty.toLowerCase()
659 | }, {
660 | notnull: notempty.toLowerCase()
661 | }];
662 | l = this.templates.select(h);
663 | break;
664 | case "SuperTableField":
665 | superTableColsArr = this.templates.selectColumns([{'column1':'column1', 'column2':'column2'}]);
666 | l = this.templates.input(o)
667 | break;
668 | default:
669 | l = this.templates.input(o)
670 | }
671 | s.html(l);
672 | // superTableColumns.html(superTableColsArr);
673 | },
674 | onConditionsRuleCompareChange: function (e) {
675 | e.preventDefault()
676 | },
677 | onConditionsRuleValueChange: function (e) {
678 | e.preventDefault()
679 | }
680 | }, {
681 | defaults: {
682 | fieldId: null,
683 | toggleFields: null,
684 | rules: null,
685 | templates: {
686 | select : function(options,isMultiSelect)
687 | {
688 | /*
689 | alert('options');
690 | console.log(options);
691 | */
692 | var selectOptions = [],
693 | option,
694 | value,
695 | label;
696 | for (var i = 0; i < options.length; ++i) {
697 | option = options[i];
698 | value = Object.keys(option)[0];
699 | label = option[value];
700 | selectOptions.push('');
701 | }
702 | return '';
703 | },
704 | selectColumns : function(options,isMultiSelect)
705 | {
706 | /*
707 | alert('options');
708 | console.log(options);
709 | */
710 | var selectOptions = [],
711 | option,
712 | value,
713 | label;
714 | for (var i = 0; i < options.length; ++i) {
715 | option = options[i];
716 | value = Object.keys(option)[0];
717 | label = option[value];
718 | selectOptions.push('');
719 | }
720 | return '';
721 | },
722 | toggleSelectOption: function (e, t) {
723 | return '"
724 | },
725 | number: function (e) {
726 | return ''
727 | },
728 | input: function e(t) {
729 | var e = "";
730 | return t = $.extend({
731 | initialRows: 4,
732 | placeholder: "",
733 | multiline: !1
734 | }, t), e += "1" === t.multiline ? '' : '', '' + e + "
"
735 | },
736 | builderUi: function () {
737 | return '' +
738 | '
' +
739 | '
Show this field if
' +
740 | '
' +
741 | '
' +
742 | '
or' +
743 | '
' +
744 | '
' +
745 | '
' +
746 | '
' +
747 | '
' +
748 | '
' +
749 | '' +
753 | '
' +
754 | '
' +
755 | '
' +
756 | '
' +
757 | '
' +
758 | '
' +
759 | '
' +
760 | '
and' +
761 | '
' +
762 | '
' +
763 | '
' +
764 | '
' +
765 | '
' +
768 | '
' +
769 | '
' +
770 | '
';
771 | }
772 | }
773 | },
774 | instances: []
775 | });
776 | e.exports = i
777 | }, function (e, t) {
778 | "use strict";
779 |
780 | function i(e, t) {
781 | if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function")
782 | }
783 | var s = function () {
784 |
785 | function e(e, t) {
786 |
787 | for (var i = 0; i < t.length; i++) {
788 | var s = t[i];
789 | s.enumerable = s.enumerable || !1, s.configurable = !0, "value" in s && (s.writable = !0), Object.defineProperty(e, s.key, s)
790 | }
791 | }
792 | return function (t, i, s) {
793 | return i && e(t.prototype, i), s && e(t, s), t
794 | }
795 | }();
796 | e.exports = function () {
797 | /*
798 | alert('ppp');
799 | console.log(t);
800 | console.log(s);
801 | */
802 |
803 | function e(t, s) {
804 | //alert('qqqqq');
805 | console.log(t);
806 | console.log(s);
807 | return i(this, e), this.settings = {
808 | fieldsSelector: ".field:not(#title-field)",
809 | livePreviewEditorSelector: ".lp-editor",
810 | elementEditorSelector: ".elementeditor",
811 | lightswitchContainerSelector: ".lightswitch",
812 | positionSelectContainerSelector: ".btngroup"
813 | }, this.$el = t, this.id = this.$el.attr("id"), this.id || (this.id = "_conditionsForm-" + Math.random().toString(36).slice(2), this.$el.attr("id", this.id)), this.conditionals = s, $(this.init.bind(this)), this
814 | }
815 | return s(e, [{
816 | key: "init",
817 | value: function () {
818 | // alert('aaaaa');
819 | this.addEventListeners(), this.addLivePreviewListeners(), this.render()
820 | }
821 | }, {
822 | key: "addEventListeners",
823 | value: function () {
824 |
825 | Garnish.$doc.on("click", this.settings.fieldsSelector + '[data-toggle="1"]', this.onInputWrapperClick.bind(this)).on("change keyup", this.settings.fieldsSelector + '[data-toggle="1"] *:input, ' +this.settings.fieldsSelector + ' *:input, '+ this.settings.fieldsSelector + '[data-toggle="1"] ' + this.settings.lightswitchContainerSelector, this.onFieldInputChange.bind(this)).on("click", "a[data-buttonbox-value]", this.onFieldInputChange.bind(this));
826 | for (var e, t = this, i = ["elementselect", "categoriesfield"], s = 0; s < i.length; ++s) $(this.settings.fieldsSelector + " ." + i[s]).each(function () {
827 | if (!$(this).hasAttr("data-conditionselementselect")) {
828 | var i = (new Date).getTime(),
829 | s = function () {
830 | e = $(this).data("elementSelect"), e ? (e.on("selectElements", t.onElementSelectChange.bind(t)), e.on("removeElements", t.onElementSelectChange.bind(t)), $(this).attr("data-conditionselementselect", ""), t.onElementSelectChange()) : (new Date).getTime() - i < 2e3 && Garnish.requestAnimationFrame(s)
831 | }.bind(this);
832 | s()
833 | }
834 | })
835 | }
836 | }, {
837 | key: "removeEventListeners",
838 | value: function () {
839 | Garnish.$doc.off("click", this.settings.fieldsSelector + '[data-toggle="1"]', this.onInputWrapperClick.bind(this)).off("change keyup", this.settings.fieldsSelector + '[data-toggle="1"] *:input, ' + this.settings.fieldsSelector + '[data-toggle="1"] ' + this.settings.lightswitchContainerSelector, this.onFieldInputChange.bind(this)).off("click", "a[data-buttonbox-value]", this.onFieldInputChange.bind(this));
840 | var e, t = this;
841 | $("[data-conditionselementselect]").each(function () {
842 | e = $(this).data("elementSelect"), e && (e.off("selectElements", t.onElementSelectChange.bind(t)), e.off("removeElements", t.onElementSelectChange.bind(t))), $(this).removeAttr("[data-conditionselementselect]")
843 | })
844 | }
845 | }, {
846 | key: "addLivePreviewListeners",
847 | value: function () {
848 | function e() {
849 | Craft.livePreview ? (this._livePreview = Craft.livePreview, this._livePreview.on("enter", $.proxy(this.onLivePreviewEnter, this)), this._livePreview.on("exit", $.proxy(this.onLivePreviewExit, this)), this._livePreviewPollId && delete this._livePreviewPollId) : (new Date).getTime() - i < 2e3 && (this._livePreviewPollId = Garnish.requestAnimationFrame(t))
850 | }
851 | var t = e.bind(this),
852 | i = (new Date).getTime();
853 | t()
854 | }
855 | }, {
856 | key: "removeLivePreviewListeners",
857 | value: function () {
858 | this._livePreviewPollId && (Garnish.cancelAnimationFrame(this._livePreviewPollId), delete this._livePreviewPollId), this._livePreview && (this._livePreview.off("enter", $.proxy(this.onLivePreviewEnter, this)), this._livePreview.off("exit", $.proxy(this.onLivePreviewExit, this)), delete this._livePreview)
859 | }
860 | }, {
861 | key: "destroy",
862 | value: function () {
863 | this.removeEventListeners(), this.removeLivePreviewListeners()
864 | }
865 | }, {
866 | key: "render",
867 | value: function () {
868 |
869 | this.initToggleFields() && this.evaluateConditionals()
870 | }
871 | }, {
872 | key: "getFieldsSelector",
873 | value: function () {
874 | var e = [this.settings.fieldsSelector];
875 | return this.isLivePreview ? e.unshift(this.settings.livePreviewEditorSelector) : e.unshift("#" + this.id), e.join(" ")
876 | }
877 | }, {
878 | key: "initToggleFields",
879 | value: function () {
880 | if (this.$fields = $(this.getFieldsSelector()), 0 === this.$fields.length) return !1;
881 | for (var e, t = Object.keys(this.conditionals), i = [], s = 0; s < t.length; ++s) {
882 | e = this.conditionals[t[s]][0];
883 | for (var n = 0; n < e.length; ++n) i.push(e[n].fieldId)
884 | }
885 | //alert('toggleFieldIds');
886 | var a, r, o, l, d = this;
887 | return this.$fields.each(function () {
888 | a = $(this), void 0 !== a.attr("id") && (r = a.attr("id").split("-"), r.length < 3 || r.length > 4 || (o = r.slice(-2, -1)[0] || !1, o && (l = Craft.ConditionsPlugin.getFieldIdByHandle(o), l && a.attr("data-id", l), d.conditionals[l] && a.attr("data-target", 1), i.indexOf(parseInt(l)) > -1 && a.attr("data-toggle", 1))))
889 | }), !0
890 | }
891 | }, {
892 | key: "evaluateConditionals",
893 | value: function () {
894 | var e, t, i, s, n, a, r, o, l, d = this,
895 | u = $(this.getFieldsSelector() + '[data-target="1"]');
896 | u.removeClass("conditionsHide").removeAttr("aria-hidden").removeAttr("tabindex").each(function () {
897 | e = $(this);
898 | t = d.conditionals[e.data("id")];
899 | console.log('All conditionals');
900 | console.log(e.data("id"));
901 | console.log(t);
902 | if ( t) {
903 |
904 | for (var u = t.length, h = u, c = 0; c < u; ++c) {
905 | i = !0; // Statement valid true
906 | s = t[c];
907 | //alert('statements');
908 | // console.log(s);
909 | for (var f = 0; f < s.length; ++f)
910 | {
911 | var rule = s[f];
912 | // console.log(rule);
913 | a = $(d.getFieldsSelector() + '[data-id="' + rule.fieldId + '"]');
914 | // alert('fieldId'+n.fieldId);
915 | //console.log(o);
916 | if ( 0 !== a.length) {
917 | o = Craft.ConditionsPlugin.getToggleFieldById(rule.fieldId)
918 | l = null;
919 | //alert('statementsxx'+n.fieldId);
920 | // console.log(o);
921 | console.log(o.type);
922 | switch (o.type) {
923 | case "Lightswitch":
924 | r = a.find("*:input:first"), r.length > 0 && (l = "1" === r.val() ? "true" : "false");
925 | break;
926 | case "Checkboxes":
927 | case "RadioButtons":
928 | case "ButtonBox_Buttons":
929 | case "ButtonBox_Stars":
930 | case "ButtonBox_Width":
931 | l = a.find("input:checkbox:checked,input:radio:checked").map(function () {
932 | return $(this).val()
933 | }).get();
934 | //console.log('checkbox');
935 | //console.log(l);
936 | break;
937 | case "Entries":
938 | case "Categories":
939 | case "Tags":
940 | case "Assets":
941 | case "Users":
942 | case "Calendar_Event":
943 | var g = a.find("[data-conditionselementselect]").data("elementSelect") || null;
944 | l = g && g.totalSelected ? "notnull" : "null";
945 | break;
946 | case "MultiSelect":
947 | r = a.find("select:first"), l = r.val();
948 | break;
949 | case "Number":
950 | r = a.find("*:input[type='text']"), l = r.val();
951 | console.log(l);
952 | break;
953 | default:
954 | r = a.find("*:input:first"), l = r.val();
955 | // console.log('default');
956 | // console.log(l);
957 | break;
958 | }
959 | // alert('statements');
960 | // console.log(n);
961 |
962 | switch ($.isArray(l) && (l = l.join("")), $.isArray(rule.value) && (rule.value = rule.value.join("")), rule.compare) {
963 | case "!=":
964 | // console.log('compare conditions');
965 | // console.log(l);
966 | // console.log(rule.value);
967 | l == rule.value && (i = !1);
968 | break;
969 | case "==":
970 | default:
971 | // console.log('compare conditions');
972 | // console.log(l);
973 | // console.log(rule.value);
974 | l != rule.value && (i = !1);
975 | break;
976 | }
977 | //alert('ddddggg');
978 | //console.log(i);
979 |
980 | if (!i) {
981 | h--;
982 | break
983 | }
984 | }
985 | }
986 | }
987 | console.log('valdi statements');
988 | console.log(h);
989 | console.log(e);
990 | h <= 0 && e.addClass("conditionsHide").attr("aria-hidden", "true").attr("tabindex", "-1")
991 | }
992 | })
993 | }
994 | }, {
995 | key: "onLivePreviewEnter",
996 | value: function () {
997 | this.isLivePreview = !0, this.render()
998 | }
999 | }, {
1000 | key: "onLivePreviewExit",
1001 | value: function () {
1002 | this.isLivePreview = !1, this.render()
1003 | }
1004 | }, {
1005 | key: "onInputWrapperClick",
1006 | value: function (e) {
1007 | $(e.currentTarget).find("input:first").trigger("change")
1008 | }
1009 | }, {
1010 | key: "onFieldInputChange",
1011 | value: function (e) {
1012 | this.evaluateConditionals()
1013 | }
1014 | }, {
1015 | key: "onElementSelectChange",
1016 | value: function (e) {
1017 |
1018 | Garnish.requestAnimationFrame(this.evaluateConditionals.bind(this))
1019 | }
1020 | }]), e
1021 | }()
1022 | }]);
1023 |
--------------------------------------------------------------------------------
/src/resources/javascripts/modules/builder.js:
--------------------------------------------------------------------------------
1 | var ConditionalsBuilder = Garnish.Base.extend({
2 |
3 | $container : null,
4 |
5 | init: function(settings)
6 | {
7 |
8 | this.setSettings(settings, ConditionalsBuilder.defaults);
9 |
10 | this.templates = this.settings.templates;
11 | this.fieldId = this.settings.fieldId;
12 |
13 | this.$container = $(this.templates.builderUi());
14 |
15 | this.$builder = this.$container.find('.reasonsBuilder:first');
16 |
17 | // Create rule template
18 | this.$rule = this.$container.find('.reasonsRule:first').clone(true);
19 |
20 | // Create statement template
21 | this.$statement = this.$container.find('.reasonsStatement:first').clone(true);
22 | this.$statement.find('.reasonsRule').remove();
23 |
24 | this.$message = this.$container.find('.reasonsMessage:first');
25 |
26 | // Add some event listeners
27 | this.$container
28 | .on('click', '.reasonsAddRule', $.proxy(this.onReasonsAddRuleClick, this))
29 | .on('click', '.reasonsRemoveRule', $.proxy(this.onReasonsRemoveRuleClick, this))
30 | .on('click', '.reasonsAddStatement', $.proxy(this.onReasonsAddStatementClick, this))
31 | .on('change', '.reasonsRuleToggleField select', $.proxy(this.onReasonsRuleToggleFieldChange, this))
32 | .on('change', '.reasonsRuleCompare select', $.proxy(this.onReasonsRuleCompareChange, this))
33 | .on('change', '.reasonsRuleValue *:input', $.proxy(this.onReasonsRuleValueChange, this));
34 |
35 | // Clean out the builder
36 | this.$builder.html('');
37 |
38 | // Update toggle fields
39 | this.setToggleFields(this.settings.toggleFields);
40 |
41 | // Render existing rules
42 | if (this.settings.rules && this.settings.rules.length > 0) {
43 | for (var i = 0; i < this.settings.rules.length; ++i) {
44 | this.addStatement({
45 | rules : this.settings.rules[i]
46 | });
47 | }
48 | }
49 |
50 | this.refresh();
51 |
52 | ConditionalsBuilder.instances.push(this);
53 |
54 | },
55 |
56 | get : function()
57 | {
58 | return this.$container;
59 | },
60 |
61 | disable : function()
62 | {
63 | this.$container.addClass('disabled');
64 | },
65 |
66 | enable : function()
67 | {
68 | this.$container.removeClass('disabled');
69 | },
70 |
71 | update : function(settings)
72 | {
73 |
74 | // Set new settings
75 | this.setSettings(settings, this.settings);
76 |
77 | // Set new toggle fields
78 | this.setToggleFields(this.settings.toggleFields);
79 |
80 | // Refresh
81 | this.refresh();
82 |
83 | },
84 |
85 | setToggleFields : function (toggleFields)
86 | {
87 |
88 | if (!toggleFields) {
89 | return false;
90 | }
91 |
92 | this.settings.toggleFields = [];
93 | this.settings.toggleFieldIds = [];
94 |
95 | for(var i = 0; i < toggleFields.length; ++i){
96 | if (parseInt(toggleFields[i].id) !== this.fieldId){
97 | this.settings.toggleFields.push(toggleFields[i]);
98 | this.settings.toggleFieldIds.push(parseInt(toggleFields[i].id));
99 | }
100 | }
101 |
102 | // Update rule template
103 | var toggleFieldSelectOptions = '';
104 | for (var i = 0; i < this.settings.toggleFields.length; ++i){
105 | toggleFieldSelectOptions += this.templates.toggleSelectOption(this.settings.toggleFields[i]);
106 | }
107 | this.$rule.find('.reasonsRuleToggleField select').html(toggleFieldSelectOptions);
108 |
109 | },
110 |
111 | refresh : function ()
112 | {
113 |
114 | this.settings.rules = [];
115 |
116 | var toggleFields = this.settings.toggleFields;
117 |
118 | // If no toggle fields, GTFO
119 | if (toggleFields.length === 0){
120 | this.disable();
121 | this.$message.text(Craft.t('No toggle fields available.'));
122 | return false;
123 | } else {
124 | this.enable();
125 | this.$message.text('');
126 | }
127 |
128 | var self = this,
129 | statement,
130 | $statements = this.$container.find('.reasonsStatement'),
131 | $statement,
132 | $rules,
133 | $rule,
134 | $toggleSelect,
135 | toggleSelectValue,
136 | toggleSelectOpts;
137 |
138 | $statements.each(function () {
139 |
140 | statement = [];
141 | $statement = $(this);
142 | $rules = $statement.find('.reasonsRule');
143 |
144 | $rules.each(function () {
145 |
146 | $rule = $(this);
147 |
148 | $toggleSelect = $rule.find('.reasonsRuleToggleField select');
149 | toggleSelectValue = parseInt($toggleSelect.val());
150 |
151 | // Remove rules where the selected toggle field no longer exists
152 | if(self.settings.toggleFieldIds.indexOf(toggleSelectValue) === -1){
153 | $rule.remove();
154 | return;
155 | }
156 |
157 | // Re-render toggle select
158 | toggleSelectOpts = '';
159 | for (var i = 0; i < self.settings.toggleFields.length; ++i){
160 | toggleSelectOpts += self.templates.toggleSelectOption(toggleFields[i], parseInt(toggleFields[i].id) === toggleSelectValue);
161 | }
162 | $toggleSelect.html(toggleSelectOpts);
163 |
164 | // Create the rule
165 | statement.push({
166 | fieldId : toggleSelectValue,
167 | compare : $rule.find('.reasonsRuleCompare select').val(),
168 | value : $rule.find('.reasonsRuleValue *:input:first').val()
169 | });
170 |
171 | });
172 |
173 | // Remove empty statements
174 | if (statement.length === 0) {
175 | $statement.remove();
176 | return;
177 | }
178 |
179 | self.settings.rules.push(statement);
180 |
181 | });
182 |
183 | },
184 |
185 | getConditionals : function ()
186 | {
187 | return this.settings.rules && this.settings.rules.length > 0 ? this.settings.rules : false;
188 | },
189 |
190 | addStatement : function(settings)
191 | {
192 |
193 | settings = $.extend({
194 | rules : false
195 | },settings);
196 |
197 | var $statement = this.$statement.clone(true),
198 | rules = settings.rules;
199 |
200 | // Append the statement
201 | this.$builder.append($statement);
202 |
203 | if (!rules) {
204 |
205 | // This is a new statement. Just add a default rule
206 | this.addRule({
207 | target : $statement
208 | });
209 |
210 | } else {
211 |
212 | for (var i = 0; i < rules.length; ++i){
213 | this.addRule($.extend({
214 | target : $statement
215 | },rules[i]));
216 | }
217 |
218 | }
219 |
220 | return $statement;
221 | },
222 |
223 | addRule : function(settings)
224 | {
225 |
226 | settings = $.extend({
227 | fieldId : null,
228 | compare : null,
229 | value : null
230 | },settings);
231 |
232 | var $rule = this.$rule.clone(true),
233 | $target = settings.target || this.$builder.find('.reasonsStatement:last'),
234 | fieldId = settings.fieldId,
235 | compare = settings.compare,
236 | value = settings.value;
237 |
238 | // Build the rule
239 | if (fieldId) {
240 | $rule.find('.reasonsRuleToggleField select').val(fieldId);
241 | }
242 |
243 | // Append the rule
244 | if ($target.length > 0) {
245 | $target.find('.reasonsRules:first').append($rule);
246 | } else {
247 | return false;
248 | }
249 |
250 | $rule
251 | .find('.reasonsRuleToggleField select')
252 | .trigger('change');
253 |
254 | if (compare) {
255 | $rule.find('.reasonsRuleCompare select').val(compare);
256 | }
257 |
258 | if (value) {
259 | $rule.find('.reasonsRuleValue *:input:first').val(value);
260 | }
261 |
262 | return $rule;
263 |
264 | },
265 |
266 | onReasonsAddRuleClick : function (e)
267 | {
268 | e.preventDefault();
269 | var $target = $(e.currentTarget).parents('.reasonsStatement');
270 | this.addRule({
271 | target : $target
272 | });
273 | },
274 |
275 | onReasonsRemoveRuleClick : function (e)
276 | {
277 | e.preventDefault();
278 | var $target = $(e.currentTarget),
279 | $rule = $target.parents('.reasonsRule');
280 | $rule.remove();
281 | this.refresh();
282 | },
283 |
284 | onReasonsAddStatementClick : function (e) {
285 | e.preventDefault();
286 | this.addStatement();
287 | },
288 |
289 | onReasonsRuleToggleFieldChange : function (e) {
290 |
291 | e.preventDefault();
292 |
293 | // Render toggle value
294 | var $target = $(e.currentTarget),
295 | $rule = $target.parents('.reasonsRule'),
296 | $ruleValue = $rule.find('.reasonsRuleValue'),
297 | toggleFieldId = $target.val(),
298 | toggleField = Craft.ReasonsPlugin.getToggleFieldById(toggleFieldId),
299 | toggleFieldType = toggleField.type,
300 | toggleFieldSettings = toggleField.settings,
301 | ruleValueContent = '';
302 |
303 | switch (toggleFieldType) {
304 |
305 | // Lightswitch - true/false
306 | case 'Lightswitch':
307 | ruleValueContent = this.templates.select([
308 | { true : Craft.t('on') },
309 | { false : Craft.t('off') }
310 | ]);
311 | break;
312 |
313 | // Option based inputs
314 | case 'Dropdown': case 'MultiSelect': case 'Checkboxes': case 'RadioButtons': case 'ButtonBox_Buttons': case 'ButtonBox_Colours': case 'ButtonBox_TextSize': case 'ButtonBox_Width':
315 | var values = toggleFieldSettings.options,
316 | options = [],
317 | option;
318 | for (var i = 0; i < values.length; ++i){
319 | option = {};
320 | option[values[i].value] = values[i].label;
321 | options.push(option);
322 | }
323 | ruleValueContent = this.templates.select(options, (toggleFieldType === 'MultiSelect' || toggleFieldType === 'Checkboxes'));
324 | break;
325 |
326 | // Number input
327 | case 'Number':
328 | ruleValueContent = this.templates.number(toggleFieldSettings);
329 | break;
330 |
331 | // Button Box – Stars
332 | case 'ButtonBox_Stars':
333 | var numStars = parseInt(toggleFieldSettings.numStars) + 1,
334 | option,
335 | options = [];
336 | for (var i = 0; i < numStars; ++i) {
337 | option = {};
338 | option[''+i] = i;
339 | options.push(option);
340 | }
341 | ruleValueContent = this.templates.select(options);
342 | break;
343 |
344 | // // Color input
345 | // case 'Color':
346 | // toggleFieldSettings = {
347 | // placeholder : '#'
348 | // };
349 | // ruleValueContent = this.templates.input(toggleFieldSettings);
350 | // break;
351 |
352 | // Position Select
353 | case 'PositionSelect':
354 | var values = toggleFieldSettings.options,
355 | options = [],
356 | option;
357 | for (var i = 0; i < values.length; ++i) {
358 | option = {};
359 | option[values[ i ]] = values[ i ].charAt(0).toUpperCase() + values[ i ].slice(1);
360 | options.push(option);
361 | }
362 | ruleValueContent = this.templates.select(options);
363 | break;
364 |
365 | // Relational fields
366 | case 'Entries': case 'Categories': case 'Tags': case 'Assets': case 'Users': case 'Calendar_Event':
367 | var options = [
368 | {
369 | 'null': Craft.t('Empty').toLowerCase()
370 | },
371 | {
372 | 'notnull': Craft.t('Not empty').toLowerCase()
373 | }
374 | ];
375 | ruleValueContent = this.templates.select(options);
376 | break;
377 |
378 | // Just render a plain text input for anything else
379 | default :
380 | ruleValueContent = this.templates.input(toggleFieldSettings);
381 | }
382 |
383 | $ruleValue.html(ruleValueContent);
384 |
385 | },
386 |
387 | onReasonsRuleCompareChange : function (e)
388 | {
389 | e.preventDefault();
390 | },
391 |
392 | onReasonsRuleValueChange : function (e)
393 | {
394 | e.preventDefault();
395 | }
396 |
397 | },
398 | {
399 | defaults: {
400 | fieldId : null,
401 | toggleFields : null,
402 | rules : null,
403 | templates : {
404 | select : function(options,isMultiSelect)
405 | {
406 | var selectOptions = [],
407 | option,
408 | value,
409 | label;
410 | for (var i = 0; i < options.length; ++i) {
411 | option = options[i];
412 | value = Object.keys(option)[0];
413 | label = option[value];
414 | selectOptions.push('');
415 | }
416 | return '';
417 | },
418 | toggleSelectOption : function(toggleField, selected)
419 | {
420 | return '';
421 | },
422 | number : function(settings)
423 | {
424 | return '';
425 | },
426 | input : function(settings)
427 | {
428 | var input = '';
429 | settings = $.extend({
430 | initialRows : 4,
431 | placeholder : '',
432 | multiline : false
433 | },settings);
434 | if (settings.multiline === '1'){
435 | input += '';
436 | } else {
437 | input += '';
438 | }
439 | return '' + input + '
';
440 | },
441 | builderUi : function()
442 | {
443 | return '' +
444 | '
' +
445 | '
' + Craft.t('Show this field if') + '
' +
446 | '
' +
447 | '
' +
448 | '
' + Craft.t('or') + '' +
449 | '
' +
450 | '
' +
451 | '
' +
452 | '
' +
453 | '
' +
454 | '' +
458 | '
' +
459 | '
' +
460 | '
' +
461 | '
' +
462 | '
' +
463 | '
' +
464 | '
' +
465 | '
' + Craft.t('and') + '' +
466 | '
' +
467 | '
' +
468 | '
' +
469 | '
' +
470 | '
' +
473 | '
' +
474 | '
' +
475 | '
';
476 | }
477 | }
478 | },
479 | instances: []
480 | });
481 |
482 | module.exports = ConditionalsBuilder;
483 |
--------------------------------------------------------------------------------
/src/resources/javascripts/modules/fld.js:
--------------------------------------------------------------------------------
1 | var Reasons_ConditionalsBuilder = require('./builder');
2 | alert('qqqqp');
3 | module.exports = class {
4 |
5 | constructor ($el, conditionals)
6 | {
7 |
8 | if (!$el || !$el.length) {
9 | return;
10 | }
11 |
12 | this.$el = $el;
13 |
14 | this.conditionals = conditionals;
15 |
16 | this.settings = {
17 | formSelector : 'form:first',
18 | fieldSettingsSelector : 'a.settings',
19 | fieldSelector : '.fld-field',
20 | tabSelector : '.fld-tabs .fld-tab'
21 | };
22 |
23 | this.templates = {
24 | input : function(settings)
25 | {
26 | return '';
27 | },
28 | modal : function()
29 | {
30 | return '';
31 | }
32 | };
33 |
34 | this.init();
35 |
36 | }
37 |
38 | init ()
39 | {
40 |
41 | // Get available toggle field IDs
42 | var toggleFields = Craft.ReasonsPlugin.getToggleFields();
43 | this.toggleFieldIds = $.map(toggleFields, function(toggleField){
44 | return parseInt(toggleField.id);
45 | });
46 |
47 | // This hidden input will store our serialized conditionals
48 | this.$conditionalsInput = $(this.templates.input({
49 | name : '_reasons',
50 | type : 'hidden'
51 | }));
52 |
53 | // This hidden input stores the conditional's ID
54 | this.$conditionalsIdInput = $(this.templates.input({
55 | name : '_reasonsId',
56 | value : this.id || '',
57 | type : 'hidden'
58 | }));
59 |
60 | // Append the hidden input fields
61 | this.$el
62 | .append(this.$conditionalsInput)
63 | .append(this.$conditionalsIdInput)
64 | // Attach submit event listener
65 | .on('submit', $.proxy(this.onFormSubmit, this));
66 |
67 | // Defer refresh to RAF
68 | Garnish.requestAnimationFrame($.proxy(function () {
69 | this.refresh();
70 | }, this));
71 |
72 | this.$el.on('mousedown', this.settings.fieldSelector, $.proxy(this.onFieldMouseDown, this));
73 | Garnish.$doc.on('click', '.menu a', $.proxy(this.onFieldSettingsMenuItemClick, this));
74 |
75 | }
76 |
77 | destroy ()
78 | {
79 | this.$el.off('mousedown', this.settings.fieldSelector, $.proxy(this.onFieldMouseDown, this));
80 | Garnish.$doc.on('click', '.menu a', $.proxy(this.onFieldSettingsMenuItemClick, this));
81 | }
82 |
83 | refresh ()
84 | {
85 | var self = this,
86 | conditionals = {},
87 | $fields,
88 | $field,
89 | fieldId,
90 | toggleFields;
91 |
92 | // Loop over tabs
93 | this.$el.find(this.settings.tabSelector).each(function(){
94 |
95 | // Get all fields for this tab
96 | $fields = $(this).find(self.settings.fieldSelector);
97 |
98 | // Get all toggle fields for this tab
99 | toggleFields = [];
100 | $fields.each(function(){
101 | $field = $(this);
102 | fieldId = parseInt($field.data('id'));
103 | if (self.toggleFieldIds.indexOf(fieldId) > -1){
104 | var toggleField = Craft.ReasonsPlugin.getToggleFieldById(fieldId);
105 | if (toggleField){
106 | toggleFields.push(toggleField);
107 | }
108 | }
109 | });
110 |
111 | // Loop over fields
112 | $fields.each(function(){
113 |
114 | $field = $(this);
115 | fieldId = parseInt($field.data('id'));
116 |
117 | if (!$field.data('_reasonsBuilder')){
118 |
119 | // Create builder
120 | $field.data('_reasonsBuilder', new Reasons_ConditionalsBuilder({
121 | fieldId : fieldId,
122 | toggleFields : toggleFields,
123 | rules : self.conditionals && self.conditionals.hasOwnProperty(fieldId) ? self.conditionals[fieldId] : null
124 | }));
125 |
126 | } else {
127 |
128 | // Refresh builder
129 | $field.data('_reasonsBuilder').update({
130 | toggleFields : toggleFields
131 | });
132 |
133 | }
134 |
135 | // Get rules
136 | var rules = $field.data('_reasonsBuilder').getConditionals();
137 | if (rules) {
138 | conditionals[fieldId] = rules;
139 | $field.addClass('reasonsHasConditionals');
140 | } else {
141 | $field.removeClass('reasonsHasConditionals');
142 | }
143 |
144 | if (!$field.data('_reasonsSettingsMenuItemInitialized')){
145 |
146 | // Create settings menu item
147 | var $button = $field.find(self.settings.fieldSettingsSelector),
148 | menubtn = $button.data('menubtn') || false;
149 |
150 | if (!menubtn){
151 | return;
152 | }
153 |
154 | var $menu = menubtn.menu.$container;
155 | $menu
156 | .find('ul')
157 | .children(':first')
158 | .clone(true)
159 | .insertBefore($menu.find('ul:first li:last'))
160 | .find('a:first')
161 | .data('_reasonsField', $field)
162 | .attr('data-action', 'toggle-conditionals')
163 | .text(Craft.t('Edit conditionals'));
164 |
165 | $field.data('_reasonsSettingsMenuItemInitialized',true);
166 |
167 | }
168 |
169 | });
170 |
171 | });
172 |
173 | if (Object.keys(conditionals).length === 0){
174 | this.$conditionalsInput.attr('value', '');
175 | } else {
176 | this.$conditionalsInput.attr('value', JSON.stringify(conditionals));
177 | }
178 | }
179 |
180 | /*
181 | * Event handlers
182 | *
183 | */
184 | onFieldMouseDown (e)
185 | {
186 | var self = this,
187 | mouseUpHandler = function(e)
188 | {
189 | $('body').off('mouseup', mouseUpHandler);
190 | Garnish.requestAnimationFrame(function () {
191 | self.refresh();
192 | });
193 | };
194 |
195 | $('body').on('mouseup', mouseUpHandler);
196 | }
197 |
198 | onFieldSettingsMenuItemClick (e)
199 | {
200 |
201 | var $trigger = $(e.target),
202 | $field = $trigger.data('_reasonsField');
203 |
204 | if ($trigger.data('action') === 'toggle-conditionals')
205 | {
206 |
207 | e.preventDefault();
208 | e.stopPropagation();
209 |
210 | if (!$trigger.data('_reasonsModal'))
211 | {
212 |
213 | // Create modal
214 | var self = this,
215 | builder = $field.data('_reasonsBuilder'),
216 | $modal = $(this.templates.modal()),
217 | modal = new Garnish.Modal($modal, {
218 | resizable : true,
219 | autoShow : false,
220 | onShow : function()
221 | {
222 | Garnish.requestAnimationFrame(function () {
223 | self.refresh();
224 | });
225 | },
226 | onHide : function()
227 | {
228 | Garnish.requestAnimationFrame(function () {
229 | self.refresh();
230 | });
231 | }
232 | });
233 |
234 | // Add builder to modal
235 | builder.get().appendTo($modal.find('.body'));
236 |
237 | $modal.on('click', '.close', function (e) {
238 | modal.hide();
239 | } );
240 |
241 | $trigger.data('_reasonsModal', modal);
242 |
243 | }
244 |
245 | $trigger.data('_reasonsModal').show();
246 |
247 | }
248 |
249 | Garnish.requestAnimationFrame($.proxy(function () {
250 | this.refresh();
251 | }, this));
252 |
253 | }
254 |
255 | onFormSubmit ()
256 | {
257 | this.refresh();
258 | }
259 |
260 | }
261 |
--------------------------------------------------------------------------------
/src/resources/javascripts/modules/render.js:
--------------------------------------------------------------------------------
1 | module.exports = class {
2 |
3 | constructor ($el, conditionals)
4 | {
5 |
6 | this.settings = {
7 | fieldsSelector: '.field:not(#title-field)',
8 | livePreviewEditorSelector: '.lp-editor',
9 | elementEditorSelector: '.elementeditor',
10 | lightswitchContainerSelector: '.lightswitch',
11 | positionSelectContainerSelector: '.btngroup'
12 | };
13 |
14 | this.$el = $el;
15 | this.id = this.$el.attr('id');
16 |
17 | if (!this.id) {
18 | this.id = '_reasonsForm-' + Math.random().toString(36).slice(2);
19 | this.$el.attr('id', this.id);
20 | }
21 |
22 | this.conditionals = conditionals;
23 |
24 | $(this.init.bind(this));
25 |
26 | return this;
27 |
28 | }
29 |
30 | init ()
31 | {
32 | this.addEventListeners();
33 | this.addLivePreviewListeners();
34 | this.render();
35 | }
36 |
37 | addEventListeners()
38 | {
39 |
40 | Garnish.$doc
41 | .on('click', this.settings.fieldsSelector + '[data-toggle="1"]', this.onInputWrapperClick.bind(this))
42 | .on('change keyup', this.settings.fieldsSelector + '[data-toggle="1"] *:input, '+this.settings.fieldsSelector + '[data-toggle="1"] '+this.settings.lightswitchContainerSelector, this.onFieldInputChange.bind(this))
43 | .on('click', 'a[data-buttonbox-value]', this.onFieldInputChange.bind(this));
44 |
45 | // Init element selects
46 | var self = this,
47 | elementSelectClassnames = ['elementselect', 'categoriesfield'],
48 | elementSelect;
49 |
50 | for (var i = 0; i < elementSelectClassnames.length; ++i) {
51 | $(this.settings.fieldsSelector + ' .' + elementSelectClassnames[i]).each(function () {
52 | if ($(this).hasAttr('data-reasonselementselect')) {
53 | return;
54 | }
55 | var now = new Date().getTime(),
56 | getElementSelect = (function () {
57 | elementSelect = $(this).data('elementSelect');
58 | if (elementSelect) {
59 | elementSelect.on('selectElements', self.onElementSelectChange.bind(self));
60 | elementSelect.on('removeElements', self.onElementSelectChange.bind(self));
61 | $(this).attr('data-reasonselementselect', '');
62 | self.onElementSelectChange();
63 | } else if (new Date().getTime() - now < 2000) {
64 | Garnish.requestAnimationFrame(getElementSelect);
65 | }
66 | }).bind(this);
67 | getElementSelect();
68 | });
69 | }
70 |
71 | }
72 |
73 | removeEventListeners()
74 | {
75 |
76 | Garnish.$doc
77 | .off('click', this.settings.fieldsSelector + '[data-toggle="1"]', this.onInputWrapperClick.bind(this))
78 | .off('change keyup', this.settings.fieldsSelector + '[data-toggle="1"] *:input, '+this.settings.fieldsSelector + '[data-toggle="1"] '+this.settings.lightswitchContainerSelector, this.onFieldInputChange.bind(this))
79 | .off('click', 'a[data-buttonbox-value]', this.onFieldInputChange.bind(this));
80 |
81 | var self = this,
82 | elementSelect;
83 |
84 | $('[data-reasonselementselect]').each(function () {
85 | elementSelect = $(this).data('elementSelect');
86 | if (elementSelect) {
87 | elementSelect.off('selectElements', self.onElementSelectChange.bind(self));
88 | elementSelect.off('removeElements', self.onElementSelectChange.bind(self));
89 | }
90 | $(this).removeAttr('[data-reasonselementselect]');
91 | });
92 |
93 | }
94 |
95 | addLivePreviewListeners()
96 | {
97 |
98 | function getLivePreviewInstance()
99 | {
100 | if (Craft.livePreview) {
101 |
102 | this._livePreview = Craft.livePreview;
103 | this._livePreview.on('enter', $.proxy(this.onLivePreviewEnter, this));
104 | this._livePreview.on('exit', $.proxy(this.onLivePreviewExit, this));
105 |
106 | if (this._livePreviewPollId) delete this._livePreviewPollId;
107 |
108 | } else if (new Date().getTime() - now < 2000) {
109 |
110 | this._livePreviewPollId = Garnish.requestAnimationFrame(livePreviewPoller);
111 |
112 | }
113 | }
114 |
115 | var livePreviewPoller = getLivePreviewInstance.bind(this),
116 | livePreview,
117 | now = new Date().getTime();
118 |
119 | livePreviewPoller();
120 |
121 | }
122 |
123 | removeLivePreviewListeners()
124 | {
125 | if (this._livePreviewPollId) {
126 | Garnish.cancelAnimationFrame(this._livePreviewPollId);
127 | delete this._livePreviewPollId;
128 | }
129 | if (this._livePreview) {
130 | this._livePreview.off('enter', $.proxy(this.onLivePreviewEnter, this));
131 | this._livePreview.off('exit', $.proxy(this.onLivePreviewExit, this));
132 | delete this._livePreview;
133 | }
134 | }
135 |
136 | destroy()
137 | {
138 | this.removeEventListeners();
139 | this.removeLivePreviewListeners();
140 | }
141 |
142 | render()
143 | {
144 | if(this.initToggleFields()){
145 | this.evaluateConditionals();
146 | }
147 | }
148 |
149 | getFieldsSelector()
150 | {
151 | var selectorPath = [this.settings.fieldsSelector];
152 | if (this.isLivePreview)
153 | {
154 | selectorPath.unshift(this.settings.livePreviewEditorSelector);
155 | } else {
156 | selectorPath.unshift('#' + this.id);
157 | }
158 | return selectorPath.join(' ');
159 | }
160 |
161 | initToggleFields()
162 | {
163 |
164 | // Get all current fields
165 | this.$fields = $(this.getFieldsSelector());
166 |
167 | if (this.$fields.length === 0) {
168 | return false;
169 | }
170 |
171 | // Get toggle field IDs
172 | var fieldIds = Object.keys(this.conditionals);
173 | var toggleFieldIds = [];
174 | var statements;
175 |
176 | for (var i = 0; i < fieldIds.length; ++i) {
177 | statements = this.conditionals[fieldIds[i]][0];
178 | for (var j = 0; j < statements.length; ++j) {
179 | toggleFieldIds.push(statements[j].fieldId);
180 | }
181 | }
182 |
183 | // Loop over fields and add data-id attribute
184 | var self = this,
185 | $field,
186 | fieldHandlePath,
187 | fieldHandle,
188 | fieldId;
189 |
190 | this.$fields.each(function () {
191 |
192 | $field = $(this);
193 |
194 | if ($field.attr('id') === undefined) return;
195 |
196 | // Get field handle
197 | fieldHandlePath = $field.attr('id').split('-');
198 |
199 | if (fieldHandlePath.length < 3 || fieldHandlePath.length > 4) return; // Only basic fields for now!
200 | fieldHandle = fieldHandlePath.slice(-2, -1)[0] || false;
201 |
202 | if (!fieldHandle) return;
203 | fieldId = Craft.ReasonsPlugin.getFieldIdByHandle(fieldHandle);
204 |
205 | if (fieldId){
206 | $field.attr('data-id', fieldId);
207 | }
208 |
209 | // Is this a target field?
210 | if (self.conditionals[fieldId]){
211 | $field.attr('data-target', 1);
212 | }
213 |
214 | // Is this a toggle field
215 | if (toggleFieldIds.indexOf(parseInt(fieldId)) > -1){
216 | $field.attr('data-toggle', 1);
217 | }
218 |
219 | });
220 |
221 | return true;
222 |
223 | }
224 |
225 | evaluateConditionals()
226 | {
227 |
228 | var self = this,
229 | $targetFields = $(this.getFieldsSelector() + '[data-target="1"]'),
230 | $targetField,
231 | statements,
232 | statementValid,
233 | rules,
234 | rule,
235 | $toggleField,
236 | $toggleFieldInput,
237 | toggleFieldData,
238 | toggleFieldValue;
239 |
240 | $targetFields
241 | .removeClass('reasonsHide')
242 | .removeAttr('aria-hidden')
243 | .removeAttr('tabindex')
244 | .each(function(){
245 |
246 | $targetField = $(this);
247 | statements = self.conditionals[$targetField.data('id')] || false;
248 |
249 | if (!statements) {
250 | return;
251 | }
252 |
253 | var numStatements = statements.length,
254 | numValidStatements = numStatements;
255 |
256 | for (var i = 0; i < numStatements; ++i) {
257 |
258 | statementValid = true;
259 | rules = statements[i];
260 |
261 | for (var j = 0; j < rules.length; ++j) {
262 |
263 | rule = rules[j];
264 |
265 | $toggleField = $(self.getFieldsSelector() + '[data-id="' + rule.fieldId + '"]');
266 | if ($toggleField.length === 0)
267 | {
268 | continue;
269 | }
270 |
271 | toggleFieldData = Craft.ReasonsPlugin.getToggleFieldById(rule.fieldId);
272 | toggleFieldValue = null;
273 |
274 | switch (toggleFieldData.type)
275 | {
276 | case 'Lightswitch':
277 | $toggleFieldInput = $toggleField.find('*:input:first');
278 | if ($toggleFieldInput.length > 0) {
279 | toggleFieldValue = $toggleFieldInput.val() === '1' ? 'true': 'false';
280 | }
281 | break;
282 | case 'Checkboxes': case 'RadioButtons': case 'ButtonBox_Buttons': case 'ButtonBox_Stars': case 'ButtonBox_Width':
283 | toggleFieldValue = $toggleField.find('input:checkbox:checked,input:radio:checked').map(function(){
284 | return $(this).val();
285 | }).get();
286 | break;
287 | case 'Entries': case 'Categories': case 'Tags': case 'Assets': case 'Users': case 'Calendar_Event':
288 | var elementSelect = $toggleField.find('[data-reasonselementselect]').data('elementSelect') || null;
289 | toggleFieldValue = elementSelect && elementSelect.totalSelected ? 'notnull' : 'null';
290 | break;
291 | default:
292 | $toggleFieldInput = $toggleField.find('*:input:first');
293 | toggleFieldValue = $toggleFieldInput.val();
294 | break;
295 | }
296 |
297 | // Flatten array values for easier comparisons
298 | if ($.isArray(toggleFieldValue))
299 | {
300 | toggleFieldValue = toggleFieldValue.join('');
301 | }
302 | if ($.isArray(rule.value))
303 | {
304 | rule.value = rule.value.join('');
305 | }
306 |
307 | // Compare trigger field value to expected value
308 | switch (rule.compare) {
309 | case '!=' :
310 | if (toggleFieldValue == rule.value){
311 | statementValid = false;
312 | }
313 | break;
314 | case '==' : default :
315 | if (toggleFieldValue != rule.value){
316 | statementValid = false;
317 | }
318 | break;
319 | }
320 |
321 | if (!statementValid) {
322 | numValidStatements--;
323 | break;
324 | }
325 |
326 | }
327 |
328 | }
329 |
330 | if (numValidStatements <= 0){
331 | $targetField
332 | .addClass('reasonsHide')
333 | .attr('aria-hidden', 'true')
334 | .attr('tabindex', '-1');
335 | }
336 |
337 | });
338 | }
339 |
340 | /*
341 | * Live preview
342 | *
343 | */
344 | onLivePreviewEnter ()
345 | {
346 | this.isLivePreview = true;
347 | this.render();
348 | }
349 |
350 | onLivePreviewExit ()
351 | {
352 | this.isLivePreview = false;
353 | this.render();
354 | }
355 |
356 | /*
357 | * Event handlers
358 | *
359 | */
360 | onInputWrapperClick (e)
361 | {
362 | $(e.currentTarget).find('input:first').trigger('change');
363 | }
364 |
365 | onFieldInputChange (e)
366 | {
367 | this.evaluateConditionals();
368 | }
369 |
370 | onElementSelectChange (e)
371 | {
372 | Garnish.requestAnimationFrame(this.evaluateConditionals.bind(this));
373 | }
374 |
375 | }
376 |
--------------------------------------------------------------------------------
/src/resources/javascripts/reasons.js:
--------------------------------------------------------------------------------
1 | (function (window){
2 |
3 | if (!window.Craft) {
4 | return false;
5 | }
6 |
7 | Craft.ReasonsPlugin = {
8 |
9 | FieldLayoutDesigner : require('./modules/fld'),
10 | ConditionalsRenderer : require('./modules/render'),
11 |
12 | ASSET_SOURCE_HANDLE : 'assetSource',
13 | CATEGORY_GROUP_HANDLE : 'categoryGroup',
14 | TAG_GROUP_HANDLE : 'tagGroup',
15 | GLOBAL_SET_HANDLE : 'globalSet',
16 | ENTRY_TYPE_HANDLE : 'entryType',
17 | SECTION_HANDLE : 'section',
18 | USERS_HANDLE : 'users',
19 | FIELDS_HANDLE : 'field',
20 | SOLSPACE_CALENDAR_HANDLE : 'solspaceCalendar',
21 |
22 | ASSET_SOURCE_ACTION : 'assetSources/saveSource',
23 | CATEGORY_ACTION : 'categories/saveCategory',
24 | CATEGORY_GROUP_ACTION : 'categories/saveGroup',
25 | TAG_ACTION : 'tagManager/saveTag',
26 | TAG_GROUP_ACTION : 'tags/saveTagGroup',
27 | GLOBAL_SET_CONTENT_ACTION : 'globals/saveContent',
28 | GLOBAL_SET_ACTION : 'globals/saveSet',
29 | ENTRY_ACTION : 'entries/saveEntry',
30 | ENTRY_REVISION_ACTION : 'entryRevisions/saveDraft',
31 | ENTRY_TYPE_ACTION : 'sections/saveEntryType',
32 | USERS_ACTION : 'users/saveUser',
33 | USERS_FIELDS_ACTION : 'users/saveFieldLayout',
34 | FIELDS_ACTION : 'fields/saveField',
35 | SOLSPACE_CALENDAR_EVENTS_ACTION : 'calendar/events/saveEvent',
36 | SOLSPACE_CALENDAR_SETTINGS_ACTION: 'calendar/calendars/saveCalendar',
37 | SOLSPACE_CALENDAR_LEGACY_SETTINGS_ACTION : 'calendar/settings/saveSettings', // Solspace Calendar < 1.7.0
38 |
39 | RENDER_CONTEXT : 'render',
40 | LAYOUT_DESIGNER_CONTEXT : 'fld',
41 | FIELD_DESIGNER_CONTEXT : 'field',
42 |
43 |
44 | /*
45 | * Initialize Reasons
46 | *
47 | */
48 | init : function (data)
49 | {
50 | this.data = data;
51 | this.initPrimaryForm();
52 | },
53 |
54 | /*
55 | * Init the primary form. This can be an FLD form, a field designer form or an element editing form
56 | *
57 | */
58 | initPrimaryForm : function ()
59 | {
60 | this.destroyPrimaryForm();
61 | Garnish.requestAnimationFrame((function () {
62 | var $form = (Craft.cp.$primaryForm && Craft.cp.$primaryForm.length) ? Craft.cp.$primaryForm : $('#content form:first');
63 | if ($form && $form.length) {
64 | this.primaryForm = this.initForm($form);
65 | }
66 | }).bind(this));
67 | },
68 |
69 | destroyPrimaryForm : function ()
70 | {
71 | if (this.primaryForm) {
72 | this.primaryForm.destroy();
73 | delete this.primaryForm;
74 | }
75 | },
76 |
77 | /*
78 | * Element editor
79 | *
80 | */
81 | initElementEditor : function (conditionalsKey)
82 | {
83 |
84 | var conditionals = this.getConditionals(conditionalsKey);
85 |
86 | if (!conditionals) {
87 | return false;
88 | }
89 |
90 | var now = new Date().getTime(),
91 | doInitElementEditor = (function () {
92 |
93 | var timestamp = new Date().getTime(),
94 | $elementEditor = $('.elementeditor:last'),
95 | $hud = $elementEditor.length > 0 ? $elementEditor.closest('.hud') : false,
96 | elementEditor = $hud && $hud.length > 0 ? $hud.data('elementEditor') : false,
97 | $form = elementEditor ? elementEditor.$form : false;
98 |
99 | if ($form) {
100 | elementEditor['_reasonsForm'] = new this.ConditionalsRenderer($form, conditionals);
101 | elementEditor.hud.on('hide', $.proxy(this.destroyElementEditorForm, this, elementEditor));
102 | } else if (timestamp - now < 2000) { // Poll for 2 secs
103 | Garnish.requestAnimationFrame(doInitElementEditor);
104 | }
105 |
106 | }).bind(this);
107 |
108 | doInitElementEditor();
109 |
110 | },
111 |
112 | destroyElementEditorForm : function (elementEditor)
113 | {
114 | var form = elementEditor._reasonsForm || null;
115 | if (form) {
116 | form.destroy();
117 | delete elementEditor._reasonsForm;
118 | }
119 | },
120 |
121 | /*
122 | * Init form
123 | *
124 | */
125 | initForm : function ($form)
126 | {
127 |
128 | var formData = this.getElementSourceFromForm($form),
129 | context = formData ? this.getFormContext($form) : false;
130 |
131 | if (!formData || !context) {
132 | return false;
133 | }
134 |
135 | var conditionalsKey = formData.type + (formData.id ? ':' + formData.id : ''),
136 | conditionals = this.getConditionals(conditionalsKey);
137 |
138 | switch (context) {
139 |
140 | case this.LAYOUT_DESIGNER_CONTEXT :
141 | return new this.FieldLayoutDesigner($form, conditionals);
142 | break;
143 |
144 | case this.FIELD_DESIGNER_CONTEXT :
145 | return null;
146 | //return new this.FieldDesigner($form, conditionals); TODO – Matrix support is coming :)
147 | break;
148 |
149 | case this.RENDER_CONTEXT :
150 | return conditionals ? new this.ConditionalsRenderer($form, conditionals) : null;
151 |
152 | }
153 |
154 | return null;
155 |
156 | },
157 |
158 | /*
159 | * Core methods
160 | *
161 | */
162 | getConditionals : function (key)
163 | {
164 | return key ? (this.data.conditionals && this.data.conditionals.hasOwnProperty(key) ? this.data.conditionals[key] : null) : (this.data.conditionals || {});
165 | },
166 |
167 | getToggleFields : function () {
168 | return this.data.toggleFields ? this.data.toggleFields : [];
169 | },
170 |
171 | getToggleFieldById : function(fieldId)
172 | {
173 | fieldId = parseInt(fieldId);
174 | var toggleFields = this.getToggleFields(),
175 | numToggleFields = toggleFields.length;
176 | for (var i = 0; i < numToggleFields; ++i) {
177 | if (parseInt(toggleFields[i].id) === fieldId){
178 | return toggleFields[i];
179 | }
180 | }
181 | return false;
182 | },
183 |
184 | getFieldIds : function ()
185 | {
186 | return this.data.fieldIds ? this.data.fieldIds : {};
187 | },
188 |
189 | getFieldIdByHandle : function (fieldHandle)
190 | {
191 | var fieldIds = this.getFieldIds();
192 | return fieldIds && fieldIds.hasOwnProperty(fieldHandle) ? fieldIds[fieldHandle] : false;
193 | },
194 |
195 | getToggleFieldTypes : function ()
196 | {
197 | return this.data.toggleFieldTypes ? this.data.toggleFieldTypes : [];
198 | },
199 |
200 | getElementSourceFromForm : function ($form)
201 | {
202 |
203 | if ($form.data('elementEditor')) {
204 | return false;
205 | }
206 |
207 | // Get namespace
208 | var namespace = $form.find('input[type="hidden"][name="namespace"]').val();
209 | if (namespace) {
210 | namespace += '-';
211 | }
212 |
213 | var action = $form.find('input[type="hidden"][name="action"]').val(),
214 | type,
215 | idInputSelector;
216 |
217 | switch (action) {
218 |
219 | case this.ASSET_SOURCE_ACTION :
220 | type = this.ASSET_SOURCE_HANDLE;
221 | idInputSelector = 'input[type="hidden"][name="sourceId"]';
222 | break;
223 |
224 | case this.CATEGORY_ACTION :
225 | case this.CATEGORY_GROUP_ACTION :
226 | type = this.CATEGORY_GROUP_HANDLE;
227 | idInputSelector = 'input[type="hidden"][name="groupId"]';
228 | break;
229 |
230 | case this.GLOBAL_SET_CONTENT_ACTION:
231 | case this.GLOBAL_SET_ACTION :
232 | type = this.GLOBAL_SET_HANDLE;
233 | idInputSelector = 'input[type="hidden"][name="setId"]';
234 | break;
235 |
236 | case this.ENTRY_ACTION :
237 | case this.ENTRY_REVISION_ACTION :
238 | var $entryType = $form.find('select#entryType, input[type="hidden"][name="entryTypeId"], input[type="hidden"][name="typeId"], #' + namespace + 'entryType');
239 | type = $entryType.length ? this.ENTRY_TYPE_HANDLE : this.SECTION_HANDLE;
240 | idInputSelector = $entryType.length ? 'select#entryType, input[type="hidden"][name="entryTypeId"], input[type="hidden"][name="typeId"], #' + namespace + 'entryType' : 'input[type="hidden"][name="sectionId"], #' + namespace + 'section';
241 | break;
242 |
243 | case this.ENTRY_TYPE_ACTION :
244 | type = this.ENTRY_TYPE_HANDLE;
245 | idInputSelector = 'input[type="hidden"][name="entryTypeId"]';
246 | break;
247 |
248 | case this.TAG_ACTION :
249 | case this.TAG_GROUP_ACTION :
250 | type = this.TAG_GROUP_HANDLE;
251 | idInputSelector = 'input[type="hidden"][name="tagGroupId"], input[type="hidden"][name="groupId"]';
252 | break;
253 |
254 | case this.USERS_ACTION :
255 | case this.USERS_FIELDS_ACTION :
256 | type = this.USERS_HANDLE;
257 | break;
258 |
259 | case this.FIELDS_ACTION :
260 | type = this.FIELDS_HANDLE;
261 | idInputSelector = 'input[type="hidden"][name="fieldId"]';
262 | break;
263 |
264 | case this.SOLSPACE_CALENDAR_LEGACY_SETTINGS_ACTION :
265 | type = this.SOLSPACE_CALENDAR_HANDLE;
266 | break;
267 |
268 | case this.SOLSPACE_CALENDAR_EVENTS_ACTION :
269 | type = this.SOLSPACE_CALENDAR_HANDLE;
270 | idInputSelector = 'input[type="hidden"][name="calendarEvent[calendarId]"]';
271 | break;
272 |
273 | case this.SOLSPACE_CALENDAR_SETTINGS_ACTION :
274 | type = this.SOLSPACE_CALENDAR_HANDLE;
275 | idInputSelector = 'input[type="hidden"][name="calendarId"]';
276 | break;
277 |
278 | case this.COMMERCE_PRODUCT_TYPE_ACTION :
279 | case this.COMMERCE_PRODUCT_ACTION :
280 | type = this.COMMERCE_PRODUCT_TYPE_HANDLE;
281 | idInputSelector = 'input[type="hidden"][name="typeId"]';
282 | break;
283 |
284 | }
285 |
286 | if (!type) {
287 | return false;
288 | }
289 |
290 | return {
291 | type : type,
292 | id : idInputSelector ? ($form.find(idInputSelector).val() | 0) : false
293 | };
294 |
295 | },
296 |
297 | getFormContext : function ($form)
298 | {
299 |
300 | if ($form.data('elementEditor')) {
301 | return false;
302 | }
303 |
304 | var action = $form.find('input[type="hidden"][name="action"]').val();
305 |
306 | switch (action) {
307 |
308 | case this.GLOBAL_SET_CONTENT_ACTION :
309 | case this.ENTRY_ACTION :
310 | case this.ENTRY_REVISION_ACTION :
311 | case this.TAG_ACTION :
312 | case this.CATEGORY_ACTION :
313 | case this.USERS_ACTION :
314 | case this.SOLSPACE_CALENDAR_EVENTS_ACTION :
315 | case this.COMMERCE_PRODUCT_ACTION :
316 | return this.RENDER_CONTEXT;
317 |
318 | case this.ASSET_SOURCE_ACTION :
319 | case this.CATEGORY_GROUP_ACTION :
320 | case this.GLOBAL_SET_ACTION :
321 | case this.ENTRY_TYPE_ACTION :
322 | case this.TAG_GROUP_ACTION :
323 | case this.USERS_FIELDS_ACTION :
324 | case this.SOLSPACE_CALENDAR_LEGACY_SETTINGS_ACTION :
325 | case this.SOLSPACE_CALENDAR_SETTINGS_ACTION :
326 | case this.COMMERCE_PRODUCT_TYPE_ACTION :
327 | return this.LAYOUT_DESIGNER_CONTEXT;
328 |
329 | case this.FIELDS_ACTION :
330 | return this.FIELD_DESIGNER_CONTEXT;
331 |
332 | }
333 |
334 | return false;
335 |
336 | }
337 |
338 | };
339 |
340 | }(window));
341 |
342 | if (window.jQuery) {
343 | /*!
344 | * jQuery.fn.hasAttr()
345 | *
346 | * Copyright 2011, Rick Waldron
347 | * Licensed under MIT license.
348 | *
349 | */
350 | (function( jQuery ) {
351 | jQuery.fn.hasAttr = function( name ) {
352 | for ( var i = 0, l = this.length; i < l; i++ ) {
353 | if ( !!( this.attr( name ) !== undefined ) ) {
354 | return true;
355 | }
356 | }
357 | return false;
358 | };
359 | })( jQuery );
360 | }
361 |
--------------------------------------------------------------------------------
/src/resources/stylesheets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MilkshakeStudio/craft-conditions/1c334a49e908d562ea1459c5b4726d2cb90f5ec0/src/resources/stylesheets/.DS_Store
--------------------------------------------------------------------------------
/src/resources/stylesheets/conditions-btest9098.css:
--------------------------------------------------------------------------------
1 | .conditionsBuilder,.conditionsStatement{width:100%;float:left}.field.conditionsHide{height:0!important;visibility:hidden!important;overflow:hidden!important;pointer-events:none!important;margin:0!important;padding:0!important;position:absolute!important}.conditionsModal .body{overflow:auto}.conditionsBuilderUi .heading{margin-bottom:20px;font-weight:700}.conditionsBuilderUi.disabled{opacity:1}.conditionsBuilderUi.disabled .wrapper{display:none}.conditionsMessage{color:#8f98a3}.conditionsStatement{margin-bottom:20px;padding-bottom:18px;border-bottom:1px solid #ccc;position:relative}.conditionsStatement .delimiter{display:inline-block;position:absolute;left:20px;bottom:-6px;padding:0 6px;background-color:#fff;line-height:1;font-size:10px;font-weight:700;color:#999;text-transform:uppercase}.conditionsRuleParams,.conditionsRuleParams>*{display:inline-block;width:auto;float:left;position:relative;margin:0 10px 10px 0}.conditionsAdd,.conditionsRule{width:100%;float:left}.conditionsRuleParams{margin:0}.conditionsRule{clear:both;margin-right:0}.conditionsRuleLead{display:block;line-height:1;font-size:12px;color:#999;float:left;clear:both;margin-bottom:8px}.conditionsAddRule,.conditionsRemoveRule{display:inline-block;margin:6px 2px}.conditionsAddRule{display:none;margin-left:5px;margin-top:0;float:left;clear:both}.conditionsRule:last-child .conditionsAddRule{display:inline-block}.conditionsRule:last-child .conditionsRuleLead{display:none}.fld-field.conditionsHasConditionals{border-style:dashed}.matrix-configurator .conditionsAdd{display:inline-block;float:none;width:auto;margin-right:10px}
--------------------------------------------------------------------------------
/src/services/ConditionsService.php:
--------------------------------------------------------------------------------
1 | conditionsService->exampleService()
44 | *
45 | * @return mixed
46 | */
47 | public function exampleService()
48 | {
49 | $result = 'something';
50 |
51 | return $result;
52 | }
53 | /**
54 | * @param ConditionalsModel $model
55 | * @return bool
56 | * @throws \Exception
57 | */
58 | public function save( $model)
59 | {
60 | $record1 = new ConditionalsRecord();
61 | $result = $record1->find()->where(array('fieldLayoutId'=>$model->fieldLayoutId))->all();
62 | foreach($result as $row)
63 | {
64 | $row->delete();
65 | }
66 | if($model->expressions != "")
67 | {
68 | $record = new ConditionalsRecord();
69 | $record->find()->where(array('fieldLayoutId'=>$model->fieldLayoutId))->all();
70 | $record->fieldLayoutId = $model->fieldLayoutId;
71 | $record->expressions = $model->expressions;
72 | $record->validate();
73 | $record->save();
74 | return true;
75 | }
76 |
77 | return false;
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/translations/en/conditions.php:
--------------------------------------------------------------------------------
1 | 'Conditions plugin loaded',
25 | ];
26 |
--------------------------------------------------------------------------------