diff --git a/e2e/__tests__/components/accordion-test.js b/e2e/__tests__/components/accordion-test.js
new file mode 100644
index 000000000..9ceb88f74
--- /dev/null
+++ b/e2e/__tests__/components/accordion-test.js
@@ -0,0 +1,46 @@
+const puppeteer = require('puppeteer');
+const ct = require('../../config/constants');
+let browser;
+let page;
+
+beforeAll(async () => {
+ browser = await puppeteer.launch({headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox']});
+ page = await browser.newPage();
+ await page.setViewport({ width: ct.BT_XL, height: ct.WH });
+});
+
+describe('SWE Components testing', () => {
+ test('Accordion is working as expected', async () => {
+ await page.goto(`${ct.APP_URL}/docs/components/accordion.html`, { waitUntil: 'networkidle0' });
+ // 1. -> accordion exist on the page
+ await page.waitForSelector('.qg-accordion-v2');
+
+ // 2. -> check all the collapsing-sections are closed on page load
+ expect(await page.evaluate('$(\'.collapsing-section\').css(\'display\')')).toBe('none');
+
+ // 3. -> click on a accordion heading and check collapsing section visibility changes
+ await page.click('.acc-heading');
+ expect(await page.evaluate('$(\'.collapsing-section\').css(\'display\')')).not.toBe('none');
+
+ // 4. -> click on collapse all button and check collapsing section visibility changes
+ await page.click('.controls.collapse');
+ await page.waitForTimeout(1000);
+ expect(await page.evaluate('$(\'.collapsing-section\').css(\'display\')')).toBe('none');
+
+ // 5. -> click on expand all button and check collapsing section visibility changes
+ await page.click('.controls.expand');
+ await page.waitForTimeout(1000);
+ expect(await page.evaluate('$(\'.collapsing-section\').css(\'display\')')).not.toBe('none');
+
+ // 6. -> check hashtrigger function by inserting a heading on the URL (#with-icon) and check that particular accordion panel open
+ await page.click('.controls.collapse');
+ await page.goto(`${ct.APP_URL}/docs/components/accordion.html#with-icon`, { waitUntil: 'networkidle0' });
+ await page.reload({ waitUntil: ['networkidle0', 'domcontentloaded'] });
+ await page.waitForTimeout(1000);
+ expect(await page.evaluate('$(".title:contains(\'With icon\')").parents(\'article\').find(\'.collapsing-section\').css(\'display\');')).not.toBe('none');
+ });
+
+ afterAll(async () => {
+ await browser.close();
+ });
+});
diff --git a/e2e/__tests__/components/funnelback-search-test.js b/e2e/__tests__/components/funnelback-search-test.js
index e9d181eb0..2cbe6a794 100644
--- a/e2e/__tests__/components/funnelback-search-test.js
+++ b/e2e/__tests__/components/funnelback-search-test.js
@@ -12,10 +12,10 @@ beforeAll(async () => {
describe('SWE Header testing', () => {
test('Funnelback search is working as expected', async () => {
- expect(await page.evaluate('window.getComputedStyle(document.querySelector(\'.qg-search-concierge-initial\')).getPropertyValue("visibility")')).toBe('hidden');
+ expect(await page.evaluate('$(\'.qg-search-concierge-initial\').css(\'visibility\')')).toBe('hidden');
await page.click('input#qg-search-query');
await page.waitForTimeout(ct.WT);
- expect(await page.evaluate('window.getComputedStyle(document.querySelector(\'.qg-search-concierge-initial\')).getPropertyValue("visibility")')).toBe('visible');
+ expect(await page.evaluate('$(\'.qg-search-concierge-initial\').css(\'visibility\')')).toBe('visible');
await page.type('#qg-search-query', 'jobs', { delay: 20 });
await page.waitForTimeout(ct.WT);
const element = await page.$('.qg-search-concierge-content li button');
diff --git a/src/assets/_project/_blocks/components/accordion/qg-accordion.js b/src/assets/_project/_blocks/components/accordion/qg-accordion.js
index 2bf654a2d..519933614 100644
--- a/src/assets/_project/_blocks/components/accordion/qg-accordion.js
+++ b/src/assets/_project/_blocks/components/accordion/qg-accordion.js
@@ -4,177 +4,174 @@
* - Ability to direct link to each section and expand the linked section
* - Handles aria-expanded values
*/
+export class QgAccordion {
+ constructor () {
+ this.$accordion = $('.qg-accordion');
+ this.$accordion_v2 = $('.qg-accordion-v2');
+ this.$accHeading = $('.acc-heading');
-(function ($) {
- var qgAccordion = {
- config: {
- $accordion: $('.qg-accordion'),
- // qg-accordion-v2 adds accessibility enhancement to the exiting accordion. The reason for creating a new selector is to maintain backward compatibility with the existing accordion (swe2 accordion).
- $accordion_v2: $('.qg-accordion-v2'),
- $accHeading: $('.acc-heading'),
- },
+ if (this.$accordion.length > 0) {
+ this.accordionPanelClick();
+ this.collapseAll();
+ this.expandAll();
+ this.hashTrigger();
+ // enable GA tracking
+ this.gaTracking();
+ // legacyAccordion is to support SWE2 accordion
+ this.legacyAccordion();
+ }
+ }
- /**
- * Initialise qgAccordion
- * @return {undefined}
- **/
- init: function() {
- if (this.config.$accordion.length > 0) {
- this.accordionClick();
- this.collapseAll();
- this.expandAll();
- this.hashTrigger();
- // enable GA tracking
- this.gaTracking();
- // legacyAccordion is to support SWE2 accordion
- this.legacyAccordion();
- }
- },
+ /**
+ * filterSpecialChar
+ * @param {string} value - value to filter
+ * @return {undefined}
+ **/
+ filterSpecialChar(value){
+ return decodeURI(value.toLowerCase().replace(/[^a-zA-Z0-9/]/g, ''));
+ }
- urlHash: function (){
- return decodeURI(window.location.hash.replace(/\/|#|{|}|\+|\\/g, ''));
- },
+ /**
+ * hashTrigger function open matching accordion if it finds #title-Of-Accordion in the url
+ * function trims down the hash value, and then it matches with the titles of the accordion, and if there is a matching title, then it open that panel
+ * @return {undefined}
+ **/
+ hashTrigger(){
+ let self = this;
+ let hashValTrimmed = this.filterSpecialChar(window.location.hash);
+ if (hashValTrimmed.length > 0) {
+ self.$accordion.find('.title').each(function (index, titleEl){
+ if (self.filterSpecialChar($(titleEl).text()) === hashValTrimmed){
+ $(this).parents(self.$accHeading).trigger('click');
+ }
+ });
+ }
+ }
- /**
- * hashTrigger function open matching accordion if it finds #title-Of-Accordion in the url
- * @return {undefined}
- **/
- // TODO check hashTrigger function looks like not working
- hashTrigger: function (){
- let hashVal = this.urlHash();
- if (hashVal.length > 0) {
- let findHashVal = this.config.$accordion.find('#' + hashVal + '');
- findHashVal.click();
- findHashVal.parent('article').find('.acc-heading').focus();
- }
- },
+ /**
+ * toggleOpenCloseClass function toggle the class and 'aria-expanded' value according to the accordion state
+ * @param {selector} curr - target selector
+ * @return {undefined}
+ **/
+ toggleOpenCloseClass(curr){
+ if (curr.hasClass('qg-accordion--open')){
+ curr.removeClass('qg-accordion--open').addClass('qg-accordion--closed');
+ curr.attr('aria-expanded', 'false');
+ } else {
+ curr.removeClass('qg-accordion--closed').addClass('qg-accordion--open');
+ curr.attr('aria-expanded', 'true');
+ }
+ }
- /**
- * toggleOpenCloseClass function toggle the class and 'aria-expanded' value according to the accordion state
- * @param {selector} curr - target selector
- * @return {undefined}
- **/
- toggleOpenCloseClass: function(curr){
- if (curr.hasClass('qg-accordion--open')){
- curr.removeClass('qg-accordion--open').addClass('qg-accordion--closed');
- curr.attr('aria-expanded', 'false');
- } else {
- curr.removeClass('qg-accordion--closed').addClass('qg-accordion--open');
- curr.attr('aria-expanded', 'true');
- }
- },
+ /**
+ * accordionClick -> click on an accordion
+ * @return {undefined}
+ **/
+ accordionPanelClick(){
+ let self = this;
+ let accHeading = self.$accordion_v2.find(self.$accHeading);
+ accHeading.on('click', function (event) {
+ self.toggleOpenCloseClass($(this));
+ });
+ }
- /**
- * accordionClick -> click on an accordion
- * @return {undefined}
- **/
- accordionClick: function(){
- let self = this;
- let accHeading = this.config.$accordion_v2.find(this.config.$accHeading);
- accHeading.on('click', function (event) {
- self.toggleOpenCloseClass($(this));
- });
- },
-
- /**
- * keyboardAccessibility -> accordion to work with keyboard
- * @param {string} event -> click , keypress etc
- * @return {undefined}
- **/
- keyboardAccessibility: function (event){
- if (event.type === 'click') {
+ /**
+ * keyboardAccessibility -> accordion to work with keyboard
+ * @param {string} event -> click , keypress etc
+ * @return {undefined}
+ **/
+ keyboardAccessibility(event){
+ if (event.type === 'click') {
+ return true;
+ } else if (event.type === 'keypress') {
+ var code = event.charCode || event.keyCode;
+ if ((code === 32) || (code === 13)) {
return true;
- } else if (event.type === 'keypress') {
- var code = event.charCode || event.keyCode;
- if ((code === 32) || (code === 13)) {
- return true;
- }
- } else {
- return false;
}
- },
+ } else {
+ return false;
+ }
+ }
- /**
- * collapseAll -> collapse all accordion on a page on clicking 'Collapse all' button
- * @return {undefined}
- **/
- collapseAll: function (){
- var self = this;
- // collapse all click
- // label selector is to provide backward compatibility in case projects are using old markup
- $('.qg-acc-controls .collapse, label[for=\'collapse\']').on('click keypress', function (event) {
- if (self.keyboardAccessibility(event) === true) {
- $(this).parents('.qg-accordion').find('.acc-heading').removeClass('qg-accordion--open').addClass('qg-accordion--closed');
- // backward compatible code to support SWE2 accordion
- $(this).parents('.qg-accordion').find('input:checkbox').prop('checked', false);
- event.preventDefault();
- }
- });
- },
+ /**
+ * collapseAll -> collapse all accordion on a page on clicking 'Collapse all' button
+ * @return {undefined}
+ **/
+ collapseAll(){
+ let self = this;
+ // collapse all click
+ // label selector is to provide backward compatibility in case projects are using old markup
+ $('.qg-acc-controls .collapse, label[for=\'collapse\']').on('click keypress', function (event) {
+ if (self.keyboardAccessibility(event) === true) {
+ $(this).parents('.qg-accordion').find('.acc-heading').removeClass('qg-accordion--open').addClass('qg-accordion--closed');
+ // backward compatible code to support SWE2 accordion
+ $(this).parents('.qg-accordion').find('input:checkbox').prop('checked', false);
+ event.preventDefault();
+ }
+ });
+ }
- /**
- * expandAll -> expand all accordion on a page on clicking 'Expand all' button
- * @return {undefined}
- **/
- expandAll: function (){
- var self = this;
- //expand all click
- // label selector is to provide backward compatibility in case projects are using old markup
- $('.qg-acc-controls .expand, label[for=\'expand\']').on('click keypress', function (event) {
- if (self.keyboardAccessibility(event) === true) {
- $(this).parents('.qg-accordion').find('.acc-heading').removeClass('qg-accordion--closed').addClass('qg-accordion--open');
- // backward compatible code to support SWE2 accordion
- $(this).parents('.qg-accordion').find('input:checkbox').prop('checked', true);
- event.preventDefault();
- }
- });
- },
+ /**
+ * expandAll -> expand all accordion on a page on clicking 'Expand all' button
+ * @return {undefined}
+ **/
+ expandAll(){
+ let self = this;
+ //expand all click
+ // label selector is to provide backward compatibility in case projects are using old markup
+ $('.qg-acc-controls .expand, label[for=\'expand\']').on('click keypress', function (event) {
+ if (self.keyboardAccessibility(event) === true) {
+ $(this).parents('.qg-accordion').find('.acc-heading').removeClass('qg-accordion--closed').addClass('qg-accordion--open');
+ // backward compatible code to support SWE2 accordion
+ $(this).parents('.qg-accordion').find('input:checkbox').prop('checked', true);
+ event.preventDefault();
+ }
+ });
+ }
- /**
- * gaTracking -> enable tracking on accordion, this function adds an attribute 'data-analytics-link-group' with a acc title
- * @return {undefined}
- **/
- gaTracking: function(){
- this.config.$accordion.find('.qg-accordion--ga').each(function(){
- let title = 'accordion title - ' + $(this).find($('.title')).text();
- $(this).attr('data-analytics-link-group', title);
- });
- },
+ /**
+ * gaTracking -> enable tracking on accordion, this function adds an attribute 'data-analytics-link-group' with a acc title
+ * @return {undefined}
+ **/
+ gaTracking(){
+ this.$accordion.find('.qg-accordion--ga').each(function(){
+ let title = 'accordion title - ' + $(this).find($('.title')).text();
+ $(this).attr('data-analytics-link-group', title);
+ });
+ }
- /**
- * legacyAccordion function supports swe2 accordion in use at some places
- * @return {undefined}
- **/
- legacyAccordion: function (){
- let self = this;
- let accItem = $('.qg-accordion:not(.qg-accordion-v2)').find('article');
- accItem.find('.acc-heading').on('keypress', function (event) {
- if (event.target === event.currentTarget) {
- event.preventDefault();
- if (self.keyboardAccessibility(event) === true) {
- let parent = $(this).parent();
- if (parent.find('input[name="tabs"]:checked').length > 0) {
- parent.find('input[name="tabs"]').prop('checked', false);
- } else {
- parent.find('input[name="tabs"]').prop('checked', true);
- }
+ /**
+ * legacyAccordion function supports swe2 accordion in use at some places
+ * @return {undefined}
+ **/
+ legacyAccordion(){
+ let self = this;
+ let accItem = $('.qg-accordion:not(.qg-accordion-v2)').find('article');
+ accItem.find('.acc-heading').on('keypress', function (event) {
+ if (event.target === event.currentTarget) {
+ event.preventDefault();
+ if (self.keyboardAccessibility(event) === true) {
+ let parent = $(this).parent();
+ if (parent.find('input[name="tabs"]:checked').length > 0) {
+ parent.find('input[name="tabs"]').prop('checked', false);
+ } else {
+ parent.find('input[name="tabs"]').prop('checked', true);
}
}
- });
+ }
+ });
- // focus heading on click
- $('input[name=tabs]').click(function () {
- $(this).parent('article').find('.acc-heading').focus();
- });
+ // focus heading on click
+ $('input[name=tabs]').click(function () {
+ $(this).parent('article').find('.acc-heading').focus();
+ });
- // highlight title on hover
- accItem.hover(function () {
- accItem.find('.title').removeClass('ht');
- $(this).find('.title').addClass('ht');
- }, function () {
- accItem.find('.title').removeClass('ht');
- });
- },
- };
- qgAccordion.init();
-}(jQuery));
+ // highlight title on hover
+ accItem.hover(function () {
+ accItem.find('.title').removeClass('ht');
+ $(this).find('.title').addClass('ht');
+ }, function () {
+ accItem.find('.title').removeClass('ht');
+ });
+ }
+}
diff --git a/src/assets/_project/_blocks/components/forms/qg-forms.js b/src/assets/_project/_blocks/components/forms/qg-forms.js
index 137df6e7f..497084524 100644
--- a/src/assets/_project/_blocks/components/forms/qg-forms.js
+++ b/src/assets/_project/_blocks/components/forms/qg-forms.js
@@ -1,7 +1,7 @@
(function ($) {
'use strict';
/**
- * This adds a pattern for radio button and checkbox , more info https://qld-gov-au.github.io/web-template-release/forms.html
+ * This adds a pattern for radio button and checkbox , more info https://qld-gov-au.github.io/web-template-release/forms.html#radio-button-and-checkbox-pattern
**/
var $rcTheme = $('.rc-theme');
function toggleFocus (e) {
diff --git a/src/assets/_project/_blocks/components/qg-components.js b/src/assets/_project/_blocks/components/qg-components.js
index 6fa18b261..4ea15bd82 100644
--- a/src/assets/_project/_blocks/components/qg-components.js
+++ b/src/assets/_project/_blocks/components/qg-components.js
@@ -6,9 +6,9 @@ import './misc/qg-license';
import './carousel/qg-carousel';
import { QgQuickExit } from './quick-exit/qg-quick-exit';
import { QgPrint } from './print/qg-print';
+import { QgAccordion } from './accordion/qg-accordion';
import { QgAddressAutocomplete } from './forms/qg-address-autocomplete';
import './tables';
-import './accordion/qg-accordion';
import './forms/qg-recaptcha';
import './forms/qg-forms';
import './misc/qg-document-links';
@@ -19,14 +19,18 @@ import './site-search/qg-site-search';
import accessibility from './accessibility/qg-accessibility';
accessibility.init();
-// quick exit
+// QG quick exit
const quickExit = new QgQuickExit();
quickExit.init();
-// autocomplete
+// QG autocomplete
// eslint-disable-next-line no-unused-vars
const qgAddressAutocomplete = new QgAddressAutocomplete();
-// print
+// QG print
// eslint-disable-next-line no-unused-vars
const qgPrint = new QgPrint();
+
+// QG accordion
+// eslint-disable-next-line no-unused-vars
+const qgAccordion = new QgAccordion();
diff --git a/src/docs/examples/guide-page.html b/src/docs/examples/guide-page.html
index ad2cd238c..74551df20 100644
--- a/src/docs/examples/guide-page.html
+++ b/src/docs/examples/guide-page.html
@@ -370,8 +370,57 @@
Browse by category
Print
-
Lorem ipsum dolor sit amet
-
Lorem ipsum dolor sit amet
+
+
+
What's this? For government (For gov ) brings the services Queensland Government agencies provide to each other into one central, searchable location. Learn how you can partner with us to publish your content on www.forgov.qld.gov.au .
+
+
+
+
+
+ Sub-franchise & publishing
+
+
+
+
+
Overview You manage a section of For gov content as a franchise team.
Who A small team, part or full time.
Level of expertise You'll need a high level of experience in communications or marketing, user experience, web writing, editorial and Queensland Government web standards.
Cost Currently none.
+
+
+
+
+
+
+ Certified author publishing
+
+
+
+
+
+
Overview You write, edit and publish content for 1 or more pages of For gov .
Who A part-time resource.
Level of expertise You'll need a moderate level of experience in web writing, content management and Queensland Government web standards.
Cost Currently none.
+
+
+
+
+
+
+
+ Subject matter expert
+
+
+
+
+
+
Overview You contribute content to For gov as a subject matter expert.
Who A part-time resource.
Level of expertise You'll need basic writing skills and subject matter expertise.
Cost Free service.
+
+
+
+