diff --git a/packages/cms/lib/modules/arguments-block-widgets/index.js b/packages/cms/lib/modules/arguments-block-widgets/index.js index f35a3a616..763d8871f 100755 --- a/packages/cms/lib/modules/arguments-block-widgets/index.js +++ b/packages/cms/lib/modules/arguments-block-widgets/index.js @@ -24,13 +24,15 @@ module.exports = { const superLoad = self.load; self.load = function(req, widgets, next) { widgets.forEach((widget) => { + const data = req.data; let config = createConfig({ widget: widget, - data: req.data, + data, }); widget.config = config; widget.divId = widget.config.divId; + widget.isClosedButRoleAllows = config.isClosed && (data.isAdmin || data.isEditor || data.isModerator); }); return superLoad(req, widgets, next); diff --git a/packages/cms/lib/modules/arguments-block-widgets/views/widget.html b/packages/cms/lib/modules/arguments-block-widgets/views/widget.html index 3fb9857df..726b0e923 100755 --- a/packages/cms/lib/modules/arguments-block-widgets/views/widget.html +++ b/packages/cms/lib/modules/arguments-block-widgets/views/widget.html @@ -13,10 +13,16 @@
+ {% if data.activeResource and data.widget.isClosedButRoleAllows %} +

Reageren is gesloten, maar je kunt nog reageren vanwege je rol als {{ data.openstadUser.role }}

+ + + {% endif %} {% if data.activeResource and data.activeResource.publishDate %}
+ {% elif (data.isAdmin or data.isEditor or data.isModerator) and data.activeResourceType !== 'idea'%} +

Deze widget kan alleen worden gebruikt op pagina`s met een resource waarbij het activeResourceType idea is

{% else %} -

Er kunnen geen argumenten worden gegeven op een concept plan

+

Er kunnen geen argumenten worden gegeven op een concept plan

{% endif %} -
diff --git a/packages/cms/lib/modules/begroot-widgets/index.js b/packages/cms/lib/modules/begroot-widgets/index.js index 3e20b7912..e969aab65 100644 --- a/packages/cms/lib/modules/begroot-widgets/index.js +++ b/packages/cms/lib/modules/begroot-widgets/index.js @@ -165,12 +165,18 @@ const fields = [ def: 'Via onderstaande knop kun je op een aparte pagina je persoonlijke stemcode invullen. Wij controleren de stemcode op geldigheid. Als dat gelukt is kom je terug op deze pagina waarna je kunt stemmen. Alle bewoners van Centrum hebben per post een stemcode ontvangen.' }, { - name: 'step_3_succesfull_auth', - label: 'Step 3: succesfull auth', + name: 'step_3_successful_auth', + label: 'Step 3: successful auth', type: 'string', textarea: true, def: 'Het controleren van je stemcode is gelukt! Je bent bijna klaar. Klik op onderstaande knop om je stem te versturen.' }, + { + name: 'successful_voting_title', + label: 'Message you see when you voted successfully', + type: 'string', + def: 'Gelukt, je hebt gestemd!' + }, { name: 'thankyou_message', label: 'Thank you message', diff --git a/packages/cms/lib/modules/begroot-widgets/views/phase-voting/budgeting.html b/packages/cms/lib/modules/begroot-widgets/views/phase-voting/budgeting.html index 04f94238b..57af62cd9 100644 --- a/packages/cms/lib/modules/begroot-widgets/views/phase-voting/budgeting.html +++ b/packages/cms/lib/modules/begroot-widgets/views/phase-voting/budgeting.html @@ -138,7 +138,7 @@

Vul een andere stemcode in
- {{data.widget.step_3_succesfull_auth}} + {{data.widget.step_3_successful_auth}}
@@ -340,7 +340,7 @@

- {{data.widget.step_3_succesfull_auth}} + {{data.widget.step_3_successful_auth}}

@@ -356,7 +356,7 @@

-

Gelukt, je hebt gestemd!

+

{{data.widget.successful_voting_title or "Gelukt, je hebt gestemd!"}}


{{data.widget.thankyou_message | sanitize | safe | nlbr}} {% if data.widget.showNewsletterButton and data.widget.showNewsletterButton == 'yes' %} diff --git a/packages/cms/lib/modules/idea-map-widgets/index.js b/packages/cms/lib/modules/idea-map-widgets/index.js index 729f65873..9fe494343 100644 --- a/packages/cms/lib/modules/idea-map-widgets/index.js +++ b/packages/cms/lib/modules/idea-map-widgets/index.js @@ -63,6 +63,13 @@ module.exports = { type: 'string', label: 'Counter text', }, + { + name: 'counterUrl', + type: 'string', + label: 'Counter url', + def: 'plannen', + required: false + }, { name: 'useMarkerLinks', type: 'boolean', @@ -115,7 +122,7 @@ module.exports = { { name: 'counter', label: 'Counter', - fields: ['displayCounter', 'counterText'] + fields: ['displayCounter', 'counterText', 'counterUrl'] }, { name: 'content', @@ -169,6 +176,7 @@ module.exports = { widgets.forEach((widget) => { + widget.counterUrl = widget.counterUrl || 'plannen'; widget.ideas = req.data.ideas ? req.data.ideas.map((idea) => { return { location: idea.location, diff --git a/packages/cms/lib/modules/idea-map-widgets/views/numberplate.html b/packages/cms/lib/modules/idea-map-widgets/views/numberplate.html index 0dcbcf6c4..0d3346bc0 100644 --- a/packages/cms/lib/modules/idea-map-widgets/views/numberplate.html +++ b/packages/cms/lib/modules/idea-map-widgets/views/numberplate.html @@ -1,6 +1,6 @@ {% macro numberPlateButton(name, caption, value, href, color="#004699") %} {% if href %} - + {% else %}
{% endif %} diff --git a/packages/cms/lib/modules/idea-map-widgets/views/widget.html b/packages/cms/lib/modules/idea-map-widgets/views/widget.html index c59f86f82..c7dc11c2c 100644 --- a/packages/cms/lib/modules/idea-map-widgets/views/widget.html +++ b/packages/cms/lib/modules/idea-map-widgets/views/widget.html @@ -18,7 +18,7 @@ {% endif %} {% if (data.widget.displayCounter) %} - {{numberPlateButton.numberPlateButton('no-of-locations', data.widget.counterText, data.ideas.length, '#')}} + {{numberPlateButton.numberPlateButton('no-of-locations', data.widget.counterText, data.ideas.length, data.widget.counterUrl)}} {% endif %}
diff --git a/packages/cms/lib/modules/openstad-api/lib/api.js b/packages/cms/lib/modules/openstad-api/lib/api.js index 267c6cbad..89b434c5c 100644 --- a/packages/cms/lib/modules/openstad-api/lib/api.js +++ b/packages/cms/lib/modules/openstad-api/lib/api.js @@ -10,8 +10,12 @@ module.exports = (self, options) => { }; self.updateSiteConfig = async (req, siteConfig, item, apiSyncFields) => { - apiSyncFields.forEach(field => { + if(field.name === 'ideaSlug') { + siteConfig.ideas.feedbackEmail["inzendingPath"] = item.ideaSlug; + siteConfig.ideas.conceptEmail["inzendingPath"] = item.ideaSlug; + siteConfig.ideas.conceptToPublishedEmail["inzendingPath"] = item.ideaSlug; + } //item is the inter global config const value = self.getFieldValue(item, field); self.setApiConfigValue(siteConfig, field.apiSyncField, value); diff --git a/packages/cms/lib/modules/openstad-pages/lib/load-tags.js b/packages/cms/lib/modules/openstad-pages/lib/load-tags.js index 77ce69f5c..dd234fa3d 100644 --- a/packages/cms/lib/modules/openstad-pages/lib/load-tags.js +++ b/packages/cms/lib/modules/openstad-pages/lib/load-tags.js @@ -1,4 +1,5 @@ const rp = require('request-promise'); +const _ = require('lodash'); const moment = require('moment'); // returns the new locale, in this case 'de' const url = require('url'); const internalApiUrl = process.env.INTERNAL_API_URL; @@ -17,17 +18,24 @@ module.exports = function (req, res, next) { */ if (globalData.siteId) { let tags; - + let retrievedEmpty = false; // if cacheIdeas is turned on, get ideas from cache // cacheIdeas is old key, should be refactored, // preferable we always have caching on + if (globalData.cacheIdeas) { let cacheKey = 'tags-' + globalData.siteId; tags = cache.get(cacheKey); + retrievedEmpty = cache.get(globalData.siteId + '-retrieved-tags-empty'); } - + if (Array.isArray(tags)) { req.data.openstadTags = tags; + req.data.groupedOpenstadTags = _.groupBy(tags, function(tag){return tag.type}); + + next(); + } else if(retrievedEmpty) { + req.data.openstadTags = []; next(); } else { @@ -42,9 +50,14 @@ module.exports = function (req, res, next) { //add tags to to the data object so it's available in templates //use openstadTags instead of tags to prevent colliding with Apos req.data.openstadTags = response; + req.data.groupedOpenstadTags = _.groupBy(response, function(tag){return tag.type}); // set the cache if (globalData.cacheIdeas) { + cache.set(globalData.siteId + '-retrieved-tags-empty', response.length === 0, { + life: cacheLifespan + }) + cache.set('tags-' +req.data.global.siteId, response, { life: cacheLifespan }); diff --git a/packages/cms/lib/modules/participatory-budgeting-widgets/index.js b/packages/cms/lib/modules/participatory-budgeting-widgets/index.js index f8e7ee2b8..95f1fab50 100644 --- a/packages/cms/lib/modules/participatory-budgeting-widgets/index.js +++ b/packages/cms/lib/modules/participatory-budgeting-widgets/index.js @@ -27,7 +27,7 @@ module.exports = { { name: 'explanation-texts', label: 'Explanation texts', - fields: ['step_1_intro', 'step_2_intro', 'step_3_intro', 'step_3_succesfull_auth', 'thankyou_message', 'showNewsletterButton', 'newsletterButtonText'] + fields: ['step_1_intro', 'step_2_intro', 'step_3_intro', 'step_3_successful_auth','successful_voting_title', 'thankyou_message', 'showNewsletterButton', 'newsletterButtonText'] }, { name: 'authentication', diff --git a/packages/cms/lib/modules/participatory-budgeting-widgets/lib/fields.js b/packages/cms/lib/modules/participatory-budgeting-widgets/lib/fields.js index 883a91332..516890c1e 100644 --- a/packages/cms/lib/modules/participatory-budgeting-widgets/lib/fields.js +++ b/packages/cms/lib/modules/participatory-budgeting-widgets/lib/fields.js @@ -192,12 +192,18 @@ const fields = [ def: 'Via onderstaande knop kun je op een aparte pagina je persoonlijke stemcode invullen. Wij controleren de stemcode op geldigheid. Als dat gelukt is kom je terug op deze pagina waarna je kunt stemmen. Alle bewoners van Centrum hebben per post een stemcode ontvangen.' }, { - name: 'step_3_succesfull_auth', + name: 'step_3_successful_auth', label: 'Step 3: succesfull auth', type: 'string', textarea: true, def: 'Het controleren van je stemcode is gelukt! Je bent bijna klaar. Klik op onderstaande knop om je stem te versturen.' }, + { + name: 'successful_voting_title', + label: 'Message you see when you voted successfully', + type: 'string', + def: 'Gelukt, je hebt gestemd!' + }, { name: 'thankyou_message', label: 'Thank you message', diff --git a/packages/cms/lib/modules/participatory-budgeting-widgets/views/phase-voting/budgeting.html b/packages/cms/lib/modules/participatory-budgeting-widgets/views/phase-voting/budgeting.html index 8f1be02e3..1998f5109 100644 --- a/packages/cms/lib/modules/participatory-budgeting-widgets/views/phase-voting/budgeting.html +++ b/packages/cms/lib/modules/participatory-budgeting-widgets/views/phase-voting/budgeting.html @@ -150,7 +150,7 @@

Vul een andere stemcode in
- {{data.widget.step_3_succesfull_auth}} + {{data.widget.step_3_successful_auth}}

@@ -352,7 +352,7 @@

- {{data.widget.step_3_succesfull_auth}} + {{data.widget.step_3_successful_auth}}

@@ -368,7 +368,7 @@

-

Gelukt, je hebt gestemd!

+

{{data.widget.successful_voting_title or "Gelukt, je hebt gestemd!"}}


{{data.widget.thankyou_message | sanitize | safe | nlbr}} {% if data.widget.showNewsletterButton and data.widget.showNewsletterButton == 'yes' %} diff --git a/packages/cms/lib/modules/resource-form-widgets/index.js b/packages/cms/lib/modules/resource-form-widgets/index.js index 93ec4c5ce..44e4188b9 100644 --- a/packages/cms/lib/modules/resource-form-widgets/index.js +++ b/packages/cms/lib/modules/resource-form-widgets/index.js @@ -185,6 +185,12 @@ module.exports = { const isReactedTo = activeResource ? (activeResource.yes > 0 || activeResource.no > 0 || activeResource.argumentCount > 0) : false; const isOwnerOrAdmin = ((!isReactedTo || !widget.hideAdminAfterPublicAction) && isOwner) || req.data.hasModeratorRights; + + widget.isTagSelected = function(tagId) { + if(!activeResource || !Array.isArray(activeResource.tags)) return false; + return activeResource.tags.findIndex(t => t.id === tagId) !== -1; + } + widget.mapConfig = self.getMapConfigBuilder(globalData) .setDefaultSettings({ mapCenterLat: (activeResource && activeResource.location && activeResource.location.coordinates && activeResource.location.coordinates[0]) || globalData.mapCenterLat, diff --git a/packages/cms/lib/modules/resource-form-widgets/lib/fields.js b/packages/cms/lib/modules/resource-form-widgets/lib/fields.js index e2839af36..9a84661ca 100644 --- a/packages/cms/lib/modules/resource-form-widgets/lib/fields.js +++ b/packages/cms/lib/modules/resource-form-widgets/lib/fields.js @@ -148,7 +148,7 @@ const fields = [ { value: 'tags', label: "Tags (currently only works for ideas)", - showFields: ['fieldKey', 'fieldRequired', 'fieldMin', 'fieldMax'] + showFields: ['fieldKey', 'fieldRequired', 'tagType', 'showTagTypeLabels', 'fieldMin', 'fieldMax'] }, { value: 'raw', @@ -296,6 +296,27 @@ const fields = [ type: 'string', textarea: true }, + { + name: 'tagType', + label: 'Optionally specify the single type (one word) by which to fetch the tags.', + type: 'string' + }, + { + name: 'showTagTypeLabels', + label: 'When the above option is empty, select if the corresponding types should be shown or not', + type: 'boolean', + choices: [ + { + label: 'Yes', + value: true, + }, + { + label: 'No', + value: false, + } + ], + def: false + }, { name: 'notExtraDataKey', label: 'Save field in root if data object and not in extraData, will only work if column exists in database)', diff --git a/packages/cms/lib/modules/resource-form-widgets/public/js/main.js b/packages/cms/lib/modules/resource-form-widgets/public/js/main.js index 0b97cedad..e5bbee84c 100644 --- a/packages/cms/lib/modules/resource-form-widgets/public/js/main.js +++ b/packages/cms/lib/modules/resource-form-widgets/public/js/main.js @@ -188,7 +188,6 @@ $(document).ready(function () { $(form).find('input[type="submit"]').each(function(index, button) { oldButtonValues.push($(this).val()); - if(button.id === "btnSaveAsConcept" && publishField.val()) { $(this).val('Verzenden...'); } else if(!publishField.val()) { @@ -206,6 +205,12 @@ $(document).ready(function () { success:function(response) { formHasChanged = false; var redirect = $(form).find('.form-redirect-uri').val(); + + // for some reason when you select the dynamic form then the input field with class .form-redirect-uri is not within the form + if(!redirect) { + redirect = document.querySelector('.form-redirect-uri').value; + } + redirect = redirect.replace(':id', response.id); redirect = window.siteUrl + redirect; diff --git a/packages/cms/lib/modules/resource-form-widgets/views/includes/fields/tags.html b/packages/cms/lib/modules/resource-form-widgets/views/includes/fields/tags.html index 1f1aafca9..858c80bdd 100644 --- a/packages/cms/lib/modules/resource-form-widgets/views/includes/fields/tags.html +++ b/packages/cms/lib/modules/resource-form-widgets/views/includes/fields/tags.html @@ -1,17 +1,52 @@
- {% for tag in data.openstadTags %} -
- - + {% if field.tagType + and data.groupedOpenstadTags[field.tagType] + and data.groupedOpenstadTags[field.tagType].length %} + + {% for tag in data.groupedOpenstadTags[field.tagType] %} +
+ + +
+ {% endfor %} + {% endif %}
+ + + {% if field.tagType === '' or field.tagType === undefined %} + {% for key, tagList in data.groupedOpenstadTags %} + {% set outer_loop = loop %} + + {% if field.showTagTypeLabels %} + {% if outer_loop.length > 1 and key !== 'undefined' %} +

{{key}}

+ {% endif %} + + {% if outer_loop.length > 1 and key == 'undefined' %} +

Overig

+ {% endif %} + {% endif %} + + {% for tag in tagList %} +
+ + +
+ {% endfor %} {% endfor %} +{% endif %}
diff --git a/packages/cms/lib/modules/resource-overview-widgets/index.js b/packages/cms/lib/modules/resource-overview-widgets/index.js index 37005a532..d9f9033ed 100644 --- a/packages/cms/lib/modules/resource-overview-widgets/index.js +++ b/packages/cms/lib/modules/resource-overview-widgets/index.js @@ -261,6 +261,8 @@ module.exports = { return Object.assign({}, tag); }) : []; + widget.groupedOpenstadTags = req.data.groupedOpenstadTags; + let response; // if cache is turned on, check if current url is available in cache diff --git a/packages/cms/lib/modules/resource-overview-widgets/lib/arrangeFields.js b/packages/cms/lib/modules/resource-overview-widgets/lib/arrangeFields.js index 9382f176a..2e290ba93 100644 --- a/packages/cms/lib/modules/resource-overview-widgets/lib/arrangeFields.js +++ b/packages/cms/lib/modules/resource-overview-widgets/lib/arrangeFields.js @@ -55,7 +55,7 @@ module.exports = (self, options) => { { name: 'tags', label: 'Tags', - fields: ['displayTagFilters'] + fields: ['displayTagFilters', 'tagType', 'showTagTypeLabels'] }, { name: 'include_exclude', diff --git a/packages/cms/lib/modules/resource-overview-widgets/lib/fields.js b/packages/cms/lib/modules/resource-overview-widgets/lib/fields.js index fede604cc..7743c5616 100644 --- a/packages/cms/lib/modules/resource-overview-widgets/lib/fields.js +++ b/packages/cms/lib/modules/resource-overview-widgets/lib/fields.js @@ -541,6 +541,26 @@ module.exports = [ } ], }, + { + name: 'tagType', + label: 'If specified only show tags belonging to a certain type', + type: 'string', + }, + { + name: 'showTagTypeLabels', + label: 'If no tag type is specified, should the type name be shown per group?', + type: 'boolean', + choices: [ + { + label: 'Yes', + value: true + }, + { + label: 'No', + value: false, + } + ], + }, { name: 'displaySorting', label: 'Display sorting', diff --git a/packages/cms/lib/modules/resource-overview-widgets/views/includes/controls/tags.html b/packages/cms/lib/modules/resource-overview-widgets/views/includes/controls/tags.html index 3ba68c960..6aec1f4ac 100644 --- a/packages/cms/lib/modules/resource-overview-widgets/views/includes/controls/tags.html +++ b/packages/cms/lib/modules/resource-overview-widgets/views/includes/controls/tags.html @@ -5,13 +5,47 @@
diff --git a/packages/cms/lib/modules/resource-representation-widgets/views/display/user-activity.html b/packages/cms/lib/modules/resource-representation-widgets/views/display/user-activity.html index bb0f40381..b3989dd73 100644 --- a/packages/cms/lib/modules/resource-representation-widgets/views/display/user-activity.html +++ b/packages/cms/lib/modules/resource-representation-widgets/views/display/user-activity.html @@ -6,8 +6,8 @@

Activiteit op deze website {{data.nielsisgek}}

    - {% if data.widget.activeResource.activity %} - {% for activity in data.widget.activeResource.activity %} + {% if data.activeResource.activity %} + {% for activity in data.activeResource.activity %} {% if data.global.siteId === activity.site.id %} {% set counterThisSite = counterThisSite + 1 %} @@ -25,8 +25,8 @@

    Activiteit op deze website {{data.nielsisgek}}

    Activiteit op andere websites

      - {% if data.widget.activeResource.activity %} - {% for activity in data.widget.activeResource.activity %} + {% if data.activeResource.activity %} + {% for activity in data.activeResource.activity %} {% if data.global.siteId !== activity.site.id %} {% set counterOtherSites = counterOtherSites + 1 %} diff --git a/packages/cms/lib/modules/section-widgets/index.js b/packages/cms/lib/modules/section-widgets/index.js index de6ff8b26..596970bed 100644 --- a/packages/cms/lib/modules/section-widgets/index.js +++ b/packages/cms/lib/modules/section-widgets/index.js @@ -283,6 +283,11 @@ module.exports = { }, ] }, + { + name: 'sectionName', + type: 'string', + label: 'Name', + }, ], @@ -311,7 +316,7 @@ module.exports = { { name: 'tabs', label: 'Tabs', - fields: ['tabs'] + fields: ['sectionName', 'tabs'] } ]); diff --git a/packages/cms/lib/modules/section-widgets/public/js/main.js b/packages/cms/lib/modules/section-widgets/public/js/main.js index f7e9b2d58..8a8dd9547 100644 --- a/packages/cms/lib/modules/section-widgets/public/js/main.js +++ b/packages/cms/lib/modules/section-widgets/public/js/main.js @@ -7,6 +7,23 @@ apos.define('section-widgets', { } }); +function findMyHash($parent) { + + var hashes = window.location.hash && window.location.hash.match(/#tab-\d+(?:-[^#]+)?/g); + + for (var i = 0; i < hashes.length; i++) { + var hash = hashes[i]; + var match = hash.match(/#tab-(\d+)(?:-([^#]+))?/); + if (match[2] && $parent.find('.section-tabs-'+match[2]).length) return hash; + } + + for (var i = 0; i < hashes.length; i++) { + var hash = hashes[i]; + var match = hash.match(/#tab-(\d+)(?:-([^#]+))?/); + if (!match[2]) return hash; + } + +} function initTabs ($parent) { @@ -15,28 +32,28 @@ function initTabs ($parent) { if ($tabContainers.length > 0) { $tabContainers.hide(); - $(window).on( 'hashchange', function( e ) { - setContainerForHash($parent) + $(window).on('hashchange', function( e ) { + var hash = findMyHash($parent); + if (hash) setContainerForHash($parent, hash) }); - if (!window.location.hash || window.location.hash.length === 0) { + var hash = findMyHash($parent); + if (!hash) { $parent.find('.nav-link').first().get(0).click(); } else { - setContainerForHash($parent); + setContainerForHash($parent, hash); } } } - -function setContainerForHash($parent) { - var hash = window.location.hash; - - if (hash.startsWith('#tab-')) { - $parent.find('.tab-container').hide(); - $parent.find('.nav-link').removeClass('active') - var selector = 'a[href*="'+hash+'"]'; - // console.log('selector', selector, $parent.find(selector)) - $parent.find(selector).addClass('active') - $(hash+'-container').show(); - } +function setContainerForHash($parent, hash) { + var match = hash.match(/#tab-(\d+)(?:-([^#]+))?/); + var tabnumber = match[1]; + var sectionName = match[1][2] || $parent[0].innerHTML.match(/class="section-tabs section-tabs-([^"]*)"/)[1]; + hash = '#tab-' + tabnumber + (sectionName ? '-'+sectionName: ''); + $parent.find('.tab-container').hide(); + $parent.find('.nav-link').removeClass('active') + var selector = 'a[href*="'+'#tab-'+tabnumber+'-'+sectionName+'"]'; + $parent.find(selector).addClass('active') + $parent.find('#tab-'+tabnumber+'-container').show(); } diff --git a/packages/cms/lib/modules/section-widgets/views/types/tabs.html b/packages/cms/lib/modules/section-widgets/views/types/tabs.html index ba66f7c9e..a02276c3b 100644 --- a/packages/cms/lib/modules/section-widgets/views/types/tabs.html +++ b/packages/cms/lib/modules/section-widgets/views/types/tabs.html @@ -1,27 +1,27 @@ -
      -
      -
      - - {% for tab in data.widget.tabs %} - {% if tab.areaName %} -
      - {{ - apos.area(data.widget, tab.areaName, { - widgets: data.widget.contentWidgets - }) - }} -
      - {% endif %} - {% endfor %} -
      +
      +
      +
      + + {% for tab in data.widget.tabs %} + {% if tab.areaName %} +
      + {{ + apos.area(data.widget, tab.areaName, { + widgets: data.widget.contentWidgets + }) + }} +
      + {% endif %} + {% endfor %}
      +