diff --git a/modules/helfi_toc/assets/js/tableOfContents.js b/modules/helfi_toc/assets/js/tableOfContents.js index 634903968..5ace846b2 100644 --- a/modules/helfi_toc/assets/js/tableOfContents.js +++ b/modules/helfi_toc/assets/js/tableOfContents.js @@ -1,21 +1,23 @@ 'use strict'; -(function (Drupal, once) { +(function (Drupal, once, drupalSettings) { Drupal.behaviors.table_of_contents = { attach: function attach() { function findAvailableId(name, reserved, anchors, count) { let newName = name; if (count > 0) { // Only when headings are not unique on page we want to add counter - newName += '-' + count; + newName += `-${count}`; } if (reserved.includes(newName)) { - return findAvailableId(name, reserved, anchors, ++count); - } else if (anchors.includes(newName)) { + return findAvailableId(name, reserved, anchors, count + 1); + } + + if (anchors.includes(newName)) { if (count === 0) { - count++; // When reserved heading is visible on page, lets start counting from 2 instead of 1 + count += 1; // When reserved heading is visible on page, lets start counting from 2 instead of 1 } - return findAvailableId(name, reserved, anchors, ++count); + return findAvailableId(name, reserved, anchors, count + 1); } return newName; } @@ -32,33 +34,125 @@ // Exclude elements from TOC that are not content: // e.g. TOC, sidebar, cookie compliency-banner etc. - const exclusions = '' + + const exclusions = + '' + ':not(.layout-sidebar-first *)' + ':not(.layout-sidebar-second *)' + ':not(.tools__container *)' + ':not(.breadcrumb__container *)' + ':not(#helfi-toc-table-of-contents *)' + ':not(.embedded-content-cookie-compliance *)' + - ':not(.react-and-share-cookie-compliance *)' + ':not(.react-and-share-cookie-compliance *)'; const titleComponents = [ - 'h2'+exclusions, - 'h3'+exclusions, - 'h4'+exclusions, - 'h5'+exclusions, - 'h6'+exclusions, + `h2${exclusions}`, + `h3${exclusions}`, + `h4${exclusions}`, + `h5${exclusions}`, + `h6${exclusions}`, ]; + const mainLanguages = [ + 'en', + 'fi', + 'sv', + ]; + + const swaps = { + '0': '[°₀۰0]', + '1': '[¹₁۱1]', + '2': '[²₂۲2]', + '3': '[³₃۳3]', + '4': '[⁴₄۴٤4]', + '5': '[⁵₅۵٥5]', + '6': '[⁶₆۶٦6]', + '7': '[⁷₇۷7]', + '8': '[⁸₈۸8]', + '9': '[⁹₉۹9]', + 'a': '[àáảãạăắằẳẵặâấầẩẫậāąåαάἀἁἂἃἄἅἆἇᾀᾁᾂᾃᾄᾅᾆᾇὰᾰᾱᾲᾳᾴᾶᾷаأအာါǻǎªაअاaä]', + 'b': '[бβبဗბbब]', + 'c': '[çćčĉċc©]', + 'd': '[ďðđƌȡɖɗᵭᶁᶑдδدضဍဒდdᴅᴆ]', + 'e': '[éèẻẽẹêếềểễệëēęěĕėεέἐἑἒἓἔἕὲеёэєəဧေဲეएإئe]', + 'f': '[фφفƒფf]', + 'g': '[ĝğġģгґγဂგگg]', + 'h': '[ĥħηήحهဟှჰh]', + 'i': '[íìỉĩịîïīĭįıιίϊΐἰἱἲἳἴἵἶἷὶῐῑῒῖῗіїиဣိီည်ǐიइیii̇ϒ]', + 'j': '[ĵјჯجj]', + 'k': '[ķĸкκقكကკქکk]', + 'l': '[łľĺļŀлλلလლlल]', + 'm': '[мμمမმm]', + 'n': '[ñńňņʼnŋνнنနნn]', + 'o': '[óòỏõọôốồổỗộơớờởỡợøōőŏοὀὁὂὃὄὅὸόоوθိုǒǿºოओoöө]', + 'p': '[пπပპپp]', + 'q': '[ყq]', + 'r': '[ŕřŗрρرრr]', + 's': '[śšşсσșςسصစſსsŝ]', + 't': '[ťţтτțتطဋတŧთტt]', + 'u': '[úùủũụưứừửữựûūůűŭųµуဉုူǔǖǘǚǜუउuўü]', + 'v': '[вვϐv]', + 'w': '[ŵωώဝွw]', + 'x': '[χξx]', + 'y': '[ýỳỷỹỵÿŷйыυϋύΰيယyῠῡὺ]', + 'z': '[źžżзζزဇზz]', + 'aa': '[عआآ]', + 'ae': '[æǽ]', + 'ai': '[ऐ]', + 'ch': '[чჩჭچ]', + 'dj': '[ђđ]', + 'dz': '[џძ]', + 'ei': '[ऍ]', + 'gh': '[غღ]', + 'ii': '[ई]', + 'ij': '[ij]', + 'kh': '[хخხ]', + 'lj': '[љ]', + 'nj': '[њ]', + 'oe': '[öœؤ]', + 'oi': '[ऑ]', + 'oii': '[ऒ]', + 'ps': '[ψ]', + 'sh': '[шშش]', + 'shch': '[щ]', + 'ss': '[ß]', + 'sx': '[ŝ]', + 'th': '[þϑثذظ]', + 'ts': '[цცწ]', + 'ue': '[ü]', + 'uu': '[ऊ]', + 'ya': '[я]', + 'yu': '[ю]', + 'zh': '[жჟژ]', + 'gx': '[ĝ]', + 'hx': '[ĥ]', + 'jx': '[ĵ]', + }; + // Craft table of contents. once('table-of-contents', titleComponents.join(','), mainContent) .forEach(function (content) { - const name = content.textContent + let name = content.textContent .toLowerCase() - .trim() - .replace(/ä/gi, 'a') - .replace(/ö/gi, 'o') - .replace(/å/gi, 'a') + .trim(); + + // To ensure backwards compatibility, this is done only to "other" languages. + if (!mainLanguages.includes(drupalSettings.path.currentLanguage)) { + Object.keys(swaps).forEach((swap) => { + name = name.replace(new RegExp(swaps[swap], 'g'), swap); + }); + } + else { + name = name + .replace(/ä/gi, 'a') + .replace(/ö/gi, 'o') + .replace(/å/gi, 'a'); + } + + name = name + // Replace any remaining non-word character including whitespace with '-'. + // This leaves only characters matching [A-Za-z0-9-_] to the name. .replace(/\W/g, '-') + // Use underscore at the end of the string: 'example-1' -> 'example_1'. .replace(/-(\d+)$/g, '_$1'); let nodeName = content.nodeName.toLowerCase(); @@ -73,13 +167,13 @@ anchors.push(anchorName); // Create table of contents if component is enabled. - if (tableOfContentsList && nodeName === "h2") { + if (tableOfContentsList && nodeName === 'h2') { let listItem = document.createElement('li'); listItem.classList.add('table-of-contents__item'); let link = document.createElement('a'); link.classList.add('table-of-contents__link'); - link.href = '#' + anchorName; + link.href = `#${anchorName}`; link.textContent = content.textContent.trim(); listItem.appendChild(link); @@ -98,4 +192,4 @@ } }, }; -})(Drupal, once); +})(Drupal, once, drupalSettings);