├── .gitignore ├── tests ├── bootstrap.php └── ExtensionTest.php ├── LICENSE ├── composer.json ├── phpunit.xml.dist ├── src └── ConditionalFieldsExtension.php ├── README.md └── web └── conditional-fields.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .idea/* 3 | .DS_* 4 | config.yml 5 | composer.lock 6 | vendor/ 7 | tests/tmp/ 8 | 9 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class ExtensionTest extends BoltUnitTest 14 | { 15 | 16 | /** 17 | * Ensure that the ExtensionName extension loads correctly. 18 | */ 19 | public function testExtensionBasics() 20 | { 21 | 22 | $app = $this->getApp(false); 23 | $extension = new ConditionalFieldsExtension($app); 24 | 25 | $name = $extension->getName(); 26 | $this->assertSame($name, 'ExtensionName'); 27 | $this->assertInstanceOf('\Bolt\Extension\ExtensionInterface', $extension); 28 | } 29 | 30 | public function testExtensionComposerJson() 31 | { 32 | 33 | $composerJson = json_decode(file_get_contents(dirname(__DIR__) . '/composer.json'), true); 34 | 35 | // Check that the 'bolt-class' key correctly matches an existing class 36 | $this->assertArrayHasKey('bolt-class', $composerJson['extra']); 37 | $this->assertTrue(class_exists($composerJson['extra']['bolt-class'])); 38 | 39 | // Check that the 'bolt-assets' key points to the correct directory 40 | $this->assertArrayHasKey('bolt-assets', $composerJson['extra']); 41 | $this->assertSame('web', $composerJson['extra']['bolt-assets']); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | tests 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | vendor/bolt/bolt/app/config/config.yml.dist 25 | 26 | 27 | vendor/bolt/bolt/app/config/contenttypes.yml.dist 28 | 29 | 30 | vendor/bolt/bolt/app/config/menu.yml.dist 31 | 32 | 33 | vendor/bolt/bolt/app/config/permissions.yml.dist 34 | 35 | 36 | vendor/bolt/bolt/app/config/routing.yml.dist 37 | 38 | 39 | vendor/bolt/bolt/app/config/taxonomy.yml.dist 40 | 41 | 42 | 43 | 44 | 45 | theme/base-2014 46 | 47 | 48 | 49 | 50 | 51 | 52 | vendor/bolt/bolt/tests/phpunit/unit/resources/db/bolt.db 53 | 54 | 55 | 56 | true 57 | 58 | true 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/ConditionalFieldsExtension.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class ConditionalFieldsExtension extends SimpleExtension 18 | { 19 | 20 | /** 21 | * Pretty extension name 22 | * 23 | * @return string 24 | */ 25 | public function getDisplayName() 26 | { 27 | 28 | return 'Conditional Fields'; 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | protected function registerAssets() 35 | { 36 | 37 | /** 38 | * @var Application $app 39 | */ 40 | $app = $this->getContainer(); 41 | $content_types = $app['config']->get('contenttypes'); 42 | $taxonomies = $app['config']->get('taxonomy'); 43 | 44 | // Template Fields 45 | $theme = $app['config']->get('theme'); 46 | $template_fields = ''; 47 | 48 | if (!empty($theme['templatefields'])) { 49 | $template_fields = $theme['templatefields']; 50 | } 51 | 52 | // Load the conditional fields javascript file 53 | $asset = new JavaScript(); 54 | 55 | $asset->setFileName('conditional-fields.js') 56 | ->setZone(Zone::BACKEND) 57 | ->setLate(true); 58 | 59 | // Content Types 60 | $content_types_json = $this->sanitiseJsonString($content_types); 61 | $content_types_snippet = (new Snippet())->setCallback('') 62 | ->setZone(Zone::BACKEND) 63 | ->setLocation(Target::BEFORE_HEAD_JS); 64 | 65 | // Taxonomies 66 | $taxonomies_json = $this->sanitiseJsonString($taxonomies); 67 | $taxonomies_snippet = (new Snippet())->setCallback('') 68 | ->setZone(Zone::BACKEND) 69 | ->setLocation(Target::BEFORE_HEAD_JS); 70 | 71 | // Template Fields 72 | $template_fields_json = $this->sanitiseJsonString($template_fields); 73 | $template_fields_snippet = (new Snippet())->setCallback('') 74 | ->setZone(Zone::BACKEND) 75 | ->setLocation(Target::BEFORE_HEAD_JS); 76 | 77 | return [ 78 | $taxonomies_snippet, 79 | $content_types_snippet, 80 | $template_fields_snippet, 81 | $asset 82 | ]; 83 | } 84 | 85 | private function sanitiseJsonString($encode_me) 86 | { 87 | 88 | // Convert array to JSON 89 | $json = str_replace('\\\\', '\\', json_encode($encode_me, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE)); 90 | 91 | // Remove string line breaks that are parsed in to actual line breaks by JSON.parse() 92 | $json = str_replace("\\n", "", $json); 93 | 94 | return $json; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Conditional fields 2 | ====================== 3 | 4 | This extension allows you to add a `condition:` array to fields and repeater sub-fields and taxonomies. 5 | 6 | If no fields are visible on a group (tab) then the group's tab will be hidden. The tab will be shown again if a field inside it is shown. 7 | 8 | ## Config 9 | 10 | The various config options are displayed below: 11 | 12 | ```yml 13 | field: 14 | label: "abc" 15 | type: text 16 | 17 | # The condition array 18 | condition: 19 | # The trigger field (check the fields id in the HTML) 20 | field: fieldname | taxonomy-taxonomyname 21 | # The operator to test the condition with 22 | operator: = | != 23 | # If the condition is met, show or hide this field 24 | show: true | false 25 | # The values to match the condition against 26 | value: [ '' ] | [ a,b,c] | { "a":'A', "b":'c' } 27 | ``` 28 | 29 | `value: [ '' ]` = field value is empty 30 | 31 | 32 | ## Adding conditions 33 | 34 | In your `contenttypes.yml`, add a `condition:` array and indent accordingly: 35 | 36 | 37 | ### Fields 38 | 39 | To make a field conditional, add a `condition:` array to the field, this works for all field including entire repeaters. 40 | 41 | ```yml 42 | map: 43 | label: "Map" 44 | type: geolocation 45 | condition: 46 | field: template 47 | operator: '=' 48 | show: true 49 | value: [ "page-contact.twig" ] 50 | ``` 51 | 52 | The above example is based on a template field, this is also possible via `templatefields` in your `theme.yml`, however setting this up as a conditional field allows for more control over grouping. 53 | 54 | 55 | #### Repeaters 56 | 57 | It is also possible to add conditional fields to the fields *within* a repeater, e.g. the below: 58 | 59 | Please note, these fields can __only__ be conditional on fields *within* each repeater group. So for example, you can't currently have a conditional repeater sub field dependant on the page's template. 60 | 61 | ```yml 62 | featured_content: 63 | group: "Featured content" 64 | label: "Featured Items" 65 | type: repeater 66 | fields: 67 | type_of_content: 68 | label: "Type of content" 69 | type: select 70 | values: { 'page': "Page", 'news': "News" } 71 | item_page: 72 | label: "Page" 73 | type: select 74 | values: page/title 75 | condition: 76 | field: type_of_content 77 | operator: '=' 78 | show: true 79 | value: [ 'page' ] 80 | item_news: 81 | label: "News" 82 | type: select 83 | values: news/title 84 | condition: 85 | field: type_of_content 86 | operator: '=' 87 | show: true 88 | value: [ 'news' ] 89 | size: 90 | label: "Card size" 91 | type: select 92 | values: [ 'small', 'medium', 'large' ] 93 | 94 | ``` 95 | 96 | ### Taxonomies 97 | 98 | To add conditional taxonomies you can add a `condition:` to your `taxonomy.yml` file. 99 | 100 | ```yml 101 | tags: 102 | slug: tags 103 | singular_slug: tag 104 | behaves_like: tags 105 | postfix: "Add some freeform tags. Start a new tag by typing a comma." 106 | allow_spaces: true 107 | condition: 108 | news: 109 | field: taxonomy-newstype 110 | operator: '!=' 111 | show: true 112 | value: [ press-release ] 113 | contenttype2: 114 | field: taxonomy-taxonomyname 115 | operator: '=' 116 | show: false 117 | value: [ abc ] 118 | contenttype3: 119 | field: template 120 | operator: '=' 121 | show: true 122 | value: [ '' ] 123 | searchweight: 25 124 | ``` 125 | 126 | ## Trigger Fields 127 | 128 | These field types are allowed to be set as the trigger field, this is the field that is going to be "watched". When this field is changed, the conditional fields that depend on it will be checked. 129 | * Select 130 | 131 | *Adding more field types to the `on('change', func...` event should be fairly easy but I haven't had a use case to test with yet.* 132 | 133 | 134 | #### Note: 135 | This extension has been built with a specific project in mind, I have tried to generalise functionality as much as possible but there may still be field types that don't work quite right just yet. Please use with caution, if you notice any bugs please submit an issue or a PR. 136 | -------------------------------------------------------------------------------- /web/conditional-fields.js: -------------------------------------------------------------------------------- 1 | /* global contentTypes, taxonomies */ 2 | 3 | // SBTODO: Multiple conditions 4 | // SBTODO: < and > condition functionality 5 | // SBTODO: Make condition: yaml use the field name instead of the backend html class/id (kind of does this already, but taxonomies and relations get prepended) 6 | // SBTODO: On hide, set value to null / empty so they don't still submit (Should clear: true | false be a setting?) 7 | 8 | (function ($) { 9 | 'use strict'; 10 | 11 | // Content Types 12 | var contentType = $('#contenttype').val(); 13 | var ctConfig = contentTypes[contentType]; 14 | 15 | var allFields = null; 16 | var fieldName = ''; 17 | 18 | // Repeaters 19 | var allRepeaterFields = null; 20 | var repeaterToAdd = null; 21 | var regexPattern; 22 | 23 | // Relations 24 | var allRelations = null; 25 | var relationToAdd = null; 26 | 27 | // Taxonomies 28 | var allTaxonomies = taxonomies; 29 | var taxonomyToAdd = null; 30 | 31 | // Templatefields 32 | var $templateSelect = $('.bolt-field-templateselect select'); 33 | var templatefieldToAdd = null; 34 | 35 | // Conditional Arrays 36 | var fieldsToWatch = []; 37 | var repeaterFieldsToWatch = []; 38 | var conditionalFields = []; 39 | var repeaterFields = []; 40 | 41 | if (ctConfig !== undefined) { 42 | initContenttypeFields(); 43 | 44 | initTemplatefieldFields(); 45 | 46 | initRelationFields(); 47 | 48 | initTaxonomyFields(); 49 | 50 | $(document).on('ready', function () { 51 | watchFieldsForChange(); 52 | 53 | var i; 54 | var len = fieldsToWatch.length; 55 | var $fieldToWatch; 56 | var watchName; 57 | var watchVal; 58 | 59 | // Check conditional fields 60 | for (i = 0; i < len; i += 1) { 61 | console.log('# Checking fields that have conditionals on: "#' + fieldsToWatch[i] + '"'); 62 | 63 | $fieldToWatch = $('#' + fieldsToWatch[i]); 64 | 65 | if (!$fieldToWatch.length) { 66 | $fieldToWatch = $('[name=' + fieldsToWatch[i] + ']'); 67 | } 68 | 69 | watchName = $fieldToWatch.attr('id'); 70 | watchVal = $fieldToWatch.val(); 71 | 72 | if ($fieldToWatch.is('input[type="checkbox"]')) { 73 | watchName = $fieldToWatch.attr('name'); 74 | } 75 | 76 | if ($fieldToWatch.is('input[type="checkbox"]') && !$fieldToWatch.is(':checked')) { 77 | watchVal = '0'; 78 | } 79 | 80 | checkConditionalFields(watchName, watchVal); 81 | } 82 | 83 | // Check conditional fields inside repeaters 84 | runRepeaterCheck(); 85 | 86 | // On new repeater item, check for conditional fields 87 | $('.repeater-add').on('click', function () { 88 | runRepeaterCheck(); 89 | }); 90 | }); 91 | } 92 | 93 | function checkConditionalFields (id, watchedValue) { 94 | // Check the watched value against fields with conditions 95 | for (var name in conditionalFields) { 96 | if (conditionalFields.hasOwnProperty(name)) { 97 | if (conditionalFields[name]['condition']['field'] !== id) { 98 | continue; 99 | } 100 | 101 | // Find the bolt fieldset container 102 | var $field; 103 | 104 | if (conditionalFields[name].hasOwnProperty('type')) { 105 | switch (conditionalFields[name]['type']) { 106 | case 'repeater': 107 | $field = $('[name="' + name + '[]"]'); 108 | 109 | break; 110 | case 'relation': 111 | $field = $('#relation-' + name); 112 | 113 | break; 114 | case 'taxonomy': 115 | $field = $('#taxonomy-' + name); 116 | 117 | break; 118 | case 'filelist': 119 | case 'textarea': 120 | case 'checkbox': 121 | $field = $('[name=' + name + ']'); 122 | 123 | break; 124 | case 'image': 125 | case 'file': 126 | $field = $('#field-' + name); 127 | 128 | break; 129 | case 'geolocation': 130 | $field = $('[name*="' + name + '[address]"]'); 131 | 132 | break; 133 | case 'video': 134 | $field = $('[name*="' + name + '[url]"]'); 135 | 136 | break; 137 | default: 138 | $field = $('#' + name); 139 | 140 | break; 141 | } 142 | } 143 | 144 | if ($field.length === 0) { 145 | console.error('Conditional field could not be hidden: ' + name + '. Type = {' + conditionalFields[name]['type'] + '}'); 146 | } 147 | 148 | var $fieldContainer = $field.closest('[data-bolt-fieldset]'); 149 | 150 | // Config value whether to show / hide the field on condition matched 151 | var showField = (conditionalFields[name]['condition']['show'] === undefined || conditionalFields[name]['condition']['show']); 152 | 153 | // Check if the value matches 154 | var conditionMatched = false; 155 | 156 | // Check if field's value is null (e.g. this occurs for images) 157 | if (watchedValue === null) { 158 | watchedValue = ''; 159 | } 160 | 161 | if (typeof watchedValue === 'object') { 162 | var i = 0; 163 | var len = watchedValue.length; 164 | 165 | for (i = 0; i < len; i += 1) { 166 | if (conditionalFields[name]['condition']['value'].indexOf(watchedValue[i]) > -1) { 167 | conditionMatched = true; 168 | 169 | break; 170 | } 171 | } 172 | } else { 173 | if (conditionalFields[name]['condition']['value'].indexOf(watchedValue) > -1) { 174 | conditionMatched = true; 175 | } 176 | } 177 | 178 | // If the condition is a != condition, invert the conditionMatched result 179 | if (conditionalFields[name]['condition']['operator'] === '!=' && conditionMatched) { 180 | conditionMatched = false; 181 | } else if (conditionalFields[name]['condition']['operator'] === '!=') { 182 | conditionMatched = true; 183 | } 184 | 185 | if ((showField && conditionMatched) || (!showField && !conditionMatched)) { 186 | console.log('--> Show ' + name); 187 | 188 | showFieldset($fieldContainer); 189 | } else { 190 | console.log('--> Hide ' + name); 191 | 192 | hideFieldset($fieldContainer); 193 | } 194 | } 195 | } 196 | 197 | checkTabPanes(); 198 | } 199 | 200 | function runRepeaterCheck () { 201 | // Check conditional fields inside repeaters 202 | var $repeaterFieldToWatch; 203 | var i; 204 | var len = repeaterFieldsToWatch.length; 205 | 206 | for (i = 0; i < len; i += 1) { 207 | console.log('# Checking repeater fields that have conditionals on: "name=/' + repeaterFieldsToWatch[i] + '/"'); 208 | 209 | $repeaterFieldToWatch = $('select, input, textarea').filter(function () { 210 | if (typeof $(this).attr('name') === 'undefined') { 211 | return false; 212 | } 213 | 214 | return $(this).attr('name').match(new RegExp(repeaterFieldsToWatch[i])) 215 | }); 216 | 217 | // If repeater fields have been found, loop through them and check the conditional fields within the repeater-group 218 | if ($repeaterFieldToWatch.length) { 219 | $repeaterFieldToWatch.each(function () { 220 | checkRepeaterFields($(this).attr('id'), $(this).val()); 221 | }) 222 | } 223 | } 224 | } 225 | 226 | function checkRepeaterFields (id, watchedValue) { 227 | // Check the watched value against fields with conditions 228 | for (var name in repeaterFields) { 229 | if (repeaterFields.hasOwnProperty(name)) { 230 | var repeater = repeaterFields[name]['repeater']; 231 | var watchedFieldRegex = new RegExp(repeater + '\\[\\d+\\]\\[' + repeaterFields[name]['condition']['field'] + '\\]'); 232 | var fieldRegex = new RegExp(repeater + '\\[\\d+\\]\\[' + name + '\\]'); 233 | var $watched_field = $('#' + id); 234 | 235 | if (!watchedFieldRegex.test($watched_field.attr('name'))) { 236 | continue; 237 | } 238 | 239 | // Find the bolt fieldset container 240 | var $field = $watched_field.closest('.repeater-group').find('select, input, textarea').filter(function () { 241 | if (typeof $(this).attr('name') === 'undefined') { 242 | return false; 243 | } 244 | 245 | return $(this).attr('name').match(fieldRegex); 246 | }); 247 | 248 | if ($field.length === 0) { 249 | console.error('Conditional repeater field could not be hidden: ' + name + '. Type = {' + repeaterFields[name]['type'] + '}'); 250 | } 251 | 252 | var $fieldContainer = $field.closest('.repeater-field'); 253 | 254 | // Config value whether to show / hide the field on condition matched 255 | var showField = (repeaterFields[name]['condition']['show'] === undefined || repeaterFields[name]['condition']['show']); 256 | 257 | // Check if the value matches 258 | var conditionMatched = false; 259 | 260 | if (typeof watchedValue === 'object') { 261 | var i = 0; 262 | var len = watchedValue.length; 263 | 264 | for (i = 0; i < len; i += 1) { 265 | if (repeaterFields[name]['condition']['value'].indexOf(watchedValue[i]) > -1) { 266 | conditionMatched = true; 267 | 268 | break; 269 | } 270 | } 271 | } else { 272 | if (repeaterFields[name]['condition']['value'].indexOf(watchedValue) > -1) { 273 | conditionMatched = true; 274 | } 275 | } 276 | 277 | // If the condition is a != condition, invert the conditionMatched result 278 | if (repeaterFields[name]['condition']['operator'] === '!=' && conditionMatched) { 279 | conditionMatched = false; 280 | } else if (repeaterFields[name]['condition']['operator'] === '!=') { 281 | conditionMatched = true; 282 | } 283 | 284 | if ((showField && conditionMatched) || (!showField && !conditionMatched)) { 285 | console.log('--> Show ' + repeater + ' field: ' + name); 286 | 287 | showFieldset($fieldContainer); 288 | } else { 289 | console.log('--> Hide ' + repeater + ' field: ' + name); 290 | 291 | hideFieldset($fieldContainer); 292 | } 293 | } 294 | } 295 | } 296 | 297 | function initContenttypeFields () { 298 | allFields = ctConfig['fields']; 299 | allRelations = ctConfig['relations']; 300 | 301 | // Check condition config to see what fields need to be checked 302 | for (var name in allFields) { 303 | if (allFields.hasOwnProperty(name) && allFields[name].hasOwnProperty('condition')) { 304 | if (allFields[name]['condition'].hasOwnProperty('field')) { 305 | fieldName = allFields[name]['condition']['field']; 306 | 307 | if (fieldsToWatch.indexOf(fieldName) === -1) { 308 | // Fields to watch the value change of 309 | fieldsToWatch.push(fieldName); 310 | } 311 | 312 | // Add to Conditional fields 313 | conditionalFields[name] = allFields[name]; 314 | } 315 | } 316 | 317 | // Check repeater fields and build array of repeaters to watch 318 | if (allFields.hasOwnProperty(name) && allFields[name].hasOwnProperty('type') && allFields[name]['type'] === 'repeater') { 319 | allRepeaterFields = allFields[name]['fields']; 320 | 321 | for (var field in allRepeaterFields) { 322 | if (allRepeaterFields.hasOwnProperty(field) && allRepeaterFields[field].hasOwnProperty('condition')) { 323 | if (allRepeaterFields[field]['condition'].hasOwnProperty('field')) { 324 | fieldName = allRepeaterFields[field]['condition']['field']; 325 | 326 | if (repeaterFieldsToWatch.indexOf(name + '\\[\\d+\\]\\[' + fieldName + '\\]') === -1) { 327 | // Fields to watch the value change of 328 | repeaterFieldsToWatch.push(name + '\\[\\d+\\]\\[' + fieldName + '\\]'); 329 | } 330 | 331 | repeaterToAdd = allRepeaterFields[field]; 332 | 333 | // Flag this entry as a repeater sub field 334 | repeaterToAdd['repeater'] = name; 335 | 336 | // Add this field to the repeaterFields array 337 | repeaterFields[field] = repeaterToAdd; 338 | } 339 | } 340 | } 341 | } 342 | } 343 | } 344 | 345 | function initRelationFields () { 346 | // Check Relations for condition config to see what relationships need to be checked 347 | for (var relName in allRelations) { 348 | if (allRelations.hasOwnProperty(relName) && allRelations[relName].hasOwnProperty('condition')) { 349 | if (allRelations[relName]['condition'].hasOwnProperty('field')) { 350 | fieldName = allRelations[relName]['condition']['field']; 351 | 352 | if (fieldsToWatch.indexOf(fieldName) === -1) { 353 | // Fields to watch the value change of 354 | fieldsToWatch.push(fieldName); 355 | } 356 | 357 | relationToAdd = allRelations[relName]; 358 | 359 | // Force the field type 360 | relationToAdd['type'] = 'relation'; 361 | 362 | // Add to Conditional fields 363 | conditionalFields[relName] = relationToAdd; 364 | } 365 | } 366 | } 367 | } 368 | 369 | function initTemplatefieldFields () { 370 | // Check templatefields for condition config to see what relationships need to be checked 371 | if ($templateSelect.length && $templateSelect.val().length) { 372 | var selectedTemplate = $templateSelect.val(); 373 | 374 | if (templateFields.hasOwnProperty(selectedTemplate)) { 375 | var fieldsForTemplate = templateFields[selectedTemplate]['fields']; 376 | 377 | // Check templatefields for condition config to see what templatefields need to be checked 378 | for (var templatefieldName in fieldsForTemplate) { 379 | if (fieldsForTemplate.hasOwnProperty(templatefieldName) && fieldsForTemplate[templatefieldName].hasOwnProperty('condition')) { 380 | templatefieldToAdd = fieldsForTemplate[templatefieldName]; 381 | 382 | fieldName = fieldsForTemplate[templatefieldName]['condition']['field']; 383 | 384 | if (fieldsToWatch.indexOf(fieldName) === -1) { 385 | // Fields to watch the value change of 386 | fieldsToWatch.push(fieldName); 387 | } 388 | 389 | // Add to Conditional fields 390 | conditionalFields['templatefields-' + templatefieldName] = fieldsForTemplate[templatefieldName]; 391 | } 392 | } 393 | } 394 | } 395 | } 396 | 397 | function initTaxonomyFields () { 398 | // Check taxonomies for condition config to see what taxonomies need to be checked 399 | for (var taxName in allTaxonomies) { 400 | if (allTaxonomies.hasOwnProperty(taxName) && allTaxonomies[taxName].hasOwnProperty('condition')) { 401 | taxonomyToAdd = allTaxonomies[taxName]; 402 | 403 | if (taxonomyToAdd['condition'].hasOwnProperty(contentType)) { 404 | fieldName = allTaxonomies[taxName]['condition'][contentType]['field']; 405 | 406 | if (fieldsToWatch.indexOf(fieldName) === -1) { 407 | // Fields to watch the value change of 408 | fieldsToWatch.push(fieldName); 409 | } 410 | 411 | // Force the field type 412 | taxonomyToAdd['type'] = 'taxonomy'; 413 | 414 | // Only use the condition for the relevant content type 415 | taxonomyToAdd['condition'] = taxonomyToAdd['condition'][contentType]; 416 | 417 | // Add to Conditional fields 418 | conditionalFields[taxName] = taxonomyToAdd; 419 | } 420 | } 421 | } 422 | } 423 | 424 | function showFieldset ($fieldContainer) { 425 | 426 | var $wasRequiredFields = $fieldContainer.find('.was-required'); 427 | 428 | if ($wasRequiredFields.length) { 429 | $wasRequiredFields.each(function () { 430 | $(this).attr('required', 'required').removeClass('was-required'); 431 | }); 432 | } 433 | 434 | $fieldContainer.show(); 435 | } 436 | 437 | function hideFieldset ($fieldContainer) { 438 | 439 | var $requiredFields = $fieldContainer.find('[required]'); 440 | 441 | if ($requiredFields.length) { 442 | $requiredFields.each(function () { 443 | $(this).removeAttr('required').addClass('was-required'); 444 | }); 445 | } 446 | 447 | $fieldContainer.hide(); 448 | } 449 | 450 | function checkTabPanes () { 451 | var $tabPanes = $('.tab-pane'); 452 | var $fields = null; 453 | 454 | $tabPanes.each(function () { 455 | // Find bolt fields 456 | $fields = $(this).find('[data-bolt-fieldset]'); 457 | 458 | // Check which of these are display none (can't use hidden because inactive tabs return as hidden) 459 | $fields = $fields.filter(function () { 460 | return $(this).data('bolt-fieldset').length && $(this).css("display") !== "none" 461 | }); 462 | 463 | // Show / Hide the tab if it has visible contents 464 | if ($fields.length > 0) { 465 | $('#tabindicator-' + $(this).attr('id')).show(); 466 | } else { 467 | $('#tabindicator-' + $(this).attr('id')).hide(); 468 | } 469 | }); 470 | } 471 | 472 | function watchFieldsForChange () { 473 | // Check for select2 changes 474 | $(document).on('change', 'select,input', function () { 475 | var id = $(this).attr('id'); 476 | var name = $(this).attr('name'); 477 | var watchedValue = $(this).val(); 478 | 479 | if (!id) { 480 | id = name; 481 | } 482 | 483 | // Check if the changed select is inside a repeater 484 | if ($(this).parents('.repeater-field').length) { 485 | checkRepeaterFields(id, watchedValue); 486 | } 487 | 488 | // Check the changed field is one of the fieldsToWatch 489 | if (fieldsToWatch.indexOf(id) > -1) { 490 | checkConditionalFields(id, watchedValue); 491 | } 492 | }).on('click', 'input[type="checkbox"], button', function () { 493 | var $field = $(this); 494 | 495 | if ($field.is('button')) { 496 | $field = $field.prev(); 497 | } 498 | 499 | var id = $field.attr('name'); 500 | var name = id; 501 | var watchedValue = $field.val(); 502 | 503 | if (!$field.is(':checked')) { 504 | watchedValue = '0'; 505 | } 506 | 507 | // Check if the changed select is inside a repeater 508 | if ($field.parents('.repeater-field').length) { 509 | checkRepeaterFields(id, watchedValue); 510 | } 511 | 512 | // Check the changed field is one of the fieldsToWatch 513 | if (fieldsToWatch.indexOf(id) > -1) { 514 | checkConditionalFields(id, watchedValue); 515 | } 516 | }); 517 | } 518 | })(jQuery); 519 | --------------------------------------------------------------------------------