Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript support #14

Merged
merged 5 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,31 @@ jekyllTabs.init({
```

Default styles for the toast message are present in the [css file](https://github.com/Ovski4/jekyll-tabs/blob/master/docs/tabs.css#L50-L70).

Development
-----------

### Building the script

Execute:

```bash
npm run build
```

The add the following content to the `tabs.js` file.

```js
window.addEventListener('load', function () {
jekyllTabs.init();
});
```

### Building and pushing the gem

Update the version number in `jekyll-tabs/version.rb`, then execute:

```bash
gem build jekyll-tabs.gemspec
gem push jekyll-tabs-{version_here}.gem
```
2 changes: 1 addition & 1 deletion docs/tabs.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/** @type {import('jest').Config} */
const config = {
preset: 'ts-jest',
verbose: true,
testEnvironment: 'jsdom',
collectCoverage: true,
Expand Down
10 changes: 5 additions & 5 deletions js/domHelpers.js → js/domHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
*
* Then getChildPosition(document.querySelector('.one')) would return 1.
*/
const getChildPosition = (element) => {
const getChildPosition = (element: HTMLElement) => {
const parent = element.parentNode;

for (let i = 0; i < parent.children.length; i++) {
Expand All @@ -24,7 +24,7 @@ const getChildPosition = (element) => {
/**
* Returns a list of elements that match the given selector and text content.
*/
const findElementsWithTextContent = (selector, text) => {
const findElementsWithTextContent = (selector: string, text: string) => {
const elementsMatchingSelector = document.querySelectorAll(selector);
const elementsWithTextContent = [];

Expand All @@ -42,7 +42,7 @@ const findElementsWithTextContent = (selector, text) => {
/**
* Create a javascript element from HTML markup.
*/
const createElementFromHTML = (html) => {
const createElementFromHTML = (html: string) => {
const template = document.createElement('template');
template.innerHTML = html.trim();

Expand All @@ -52,7 +52,7 @@ const createElementFromHTML = (html) => {
/**
* Add the class on the given element for the duration of the timeout.
*/
const addClass = (element, addedClass, timeout) => {
const addClass = (element: HTMLElement, addedClass: string, timeout: number) => {
element.className = element.className
? `${element.className} ${addedClass}`
: addedClass;
Expand All @@ -63,7 +63,7 @@ const addClass = (element, addedClass, timeout) => {
}, timeout);
}

module.exports = {
export {
getChildPosition,
findElementsWithTextContent,
createElementFromHTML,
Expand Down
29 changes: 22 additions & 7 deletions js/jekyllTabs.js → js/jekyllTabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,23 @@ const {
appendToastMessageHTML,
} = require('./tabsHelpers');

const init = (overriddenConfiguration = {}) => {
const defaultConfiguration = {
interface CopyToClipboardSettings {
buttonHTML: string,
showToastMessageOnCopy: boolean,
toastMessage: string,
toastDuration: number,
}

interface Configuration {
syncTabsWithSameLabels: boolean;
activateTabFromUrl: boolean;
addCopyToClipboardButtons: boolean;
copyToClipboardSettings: CopyToClipboardSettings;
}

const init = (overriddenConfiguration: any = {}) => {

const defaultConfiguration: Configuration = {
syncTabsWithSameLabels: false,
activateTabFromUrl: false,
addCopyToClipboardButtons: false,
Expand All @@ -20,7 +35,7 @@ const init = (overriddenConfiguration = {}) => {
}
};

const configuration = {
const configuration: Configuration = {
...defaultConfiguration,
...overriddenConfiguration,
copyToClipboardSettings: {
Expand All @@ -29,10 +44,10 @@ const init = (overriddenConfiguration = {}) => {
}
};

const tabLinks = document.querySelectorAll('ul.tab > li > a');
const tabLinks: NodeList = document.querySelectorAll('ul.tab > li > a');

Array.prototype.forEach.call(tabLinks, (link) => {
link.addEventListener('click', (event) => {
Array.prototype.forEach.call(tabLinks, (link: HTMLAnchorElement) => {
link.addEventListener('click', (event: MouseEvent) => {
event.preventDefault();

handleTabClicked(link);
Expand Down Expand Up @@ -62,6 +77,6 @@ const init = (overriddenConfiguration = {}) => {
}
};

module.exports = {
export {
init,
}
41 changes: 22 additions & 19 deletions js/tabsHelpers.js → js/tabsHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ const {
/**
* Remove all "active" classes on li elements that belong to the given ul element.
*/
const removeActiveClasses = (ulElement) => {
const removeActiveClasses = (ulElement: HTMLUListElement) => {
const liElements = ulElement.querySelectorAll('ul > li');

Array.prototype.forEach.call(liElements, (liElement) => {
Array.prototype.forEach.call(liElements, (liElement: HTMLLIElement) => {
liElement.classList.remove('active');
});
}

/**
* Handle adding or removing active classes on tab list items.
*/
const handleTabClicked = (link) => {
const liTab = link.parentNode;
const ulTab = liTab.parentNode;
const handleTabClicked = (link: HTMLAnchorElement) => {
const liTab = link.parentNode as HTMLLIElement;
const ulTab = liTab.parentNode as HTMLUListElement;
const liPositionInUl = getChildPosition(liTab);

if (liTab.className.includes('active')) {
Expand All @@ -34,7 +34,7 @@ const handleTabClicked = (link) => {
return;
}

const tabContentElement = document.getElementById(tabContentId);
const tabContentElement = document.getElementById(tabContentId) as HTMLUListElement;

// Remove all "active" classes first.
removeActiveClasses(ulTab);
Expand All @@ -50,7 +50,7 @@ const handleTabClicked = (link) => {
*
* See https://stackoverflow.com/questions/51805395/navigator-clipboard-is-undefined
*/
const copyToClipboard = (text, callBack) => {
const copyToClipboard = (text: string, callBack: Function) => {
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(text);
} else {
Expand Down Expand Up @@ -105,7 +105,7 @@ const activateTabFromUrl = () => {
return;
}

const tabLink = targetedTabs.querySelector('li#' + tabIdToActivate + ' > a');
const tabLink = targetedTabs.querySelector('li#' + tabIdToActivate + ' > a') as HTMLAnchorElement;

if (!tabLink) {
return;
Expand All @@ -117,9 +117,9 @@ const activateTabFromUrl = () => {
/**
* Update the url when clicking on a tab. See method activateTabFromUrl above.
*/
const updateUrlWithActiveTab = (link) => {
const liTab = link.parentNode;
const ulTab = liTab.parentNode;
const updateUrlWithActiveTab = (link: HTMLAnchorElement) => {
const liTab = link.parentNode as HTMLLIElement;
const ulTab = liTab.parentNode as HTMLUListElement;

const searchParams = new URLSearchParams(window.location.search);
searchParams.set('active_tab', liTab.id);
Expand All @@ -131,12 +131,15 @@ const updateUrlWithActiveTab = (link) => {
/**
* Add the "Copy to clipboard" button on the top right hand side of tabs with embedded code (<pre> tags).
*/
const addCopyToClipboardButtons = ({ buttonHTML, showToastMessageOnCopy, toastDuration }) => {
const preElements = document.querySelectorAll('ul.tab-content > li pre');
const addCopyToClipboardButtons = (
{ buttonHTML, showToastMessageOnCopy, toastDuration }:
{ buttonHTML: string, showToastMessageOnCopy: boolean, toastDuration: number }
) => {
const preElements = document.querySelectorAll('ul.tab-content > li pre') as NodeListOf<HTMLPreElement>;

for(let i = 0; i < preElements.length; i++) {
const preElement = preElements[i];
const preParentNode = preElement.parentNode;
const preParentNode = preElement.parentNode as HTMLElement;
const button = createElementFromHTML(buttonHTML);

preParentNode.style.position = 'relative';
Expand All @@ -146,7 +149,7 @@ const addCopyToClipboardButtons = ({ buttonHTML, showToastMessageOnCopy, toastDu

preParentNode.appendChild(button);

let copyToClipboardCallBack;
let copyToClipboardCallBack: Function;

if (showToastMessageOnCopy) {
copyToClipboardCallBack = () => {
Expand All @@ -163,7 +166,7 @@ const addCopyToClipboardButtons = ({ buttonHTML, showToastMessageOnCopy, toastDu
/**
* Insert a div that contains the toast message at the end of the <body> tag.
*/
const appendToastMessageHTML = (toastMessage) => {
const appendToastMessageHTML = (toastMessage: string) => {
const toastMessageDiv = document.createElement('div');

toastMessageDiv.id = 'jekyll-tabs-copy-to-clipboard-message';
Expand All @@ -175,14 +178,14 @@ const appendToastMessageHTML = (toastMessage) => {
/**
* Set '.show' class on the div that contains the toast message for the given duration.
*/
const showToastMessage = (toastDuration) => {
const showToastMessage = (toastDuration: number) => {
addClass(document.getElementById('jekyll-tabs-copy-to-clipboard-message'), 'show', toastDuration);
}

/**
* Activate tabs that have the same label as the one related to the given link.
*/
const syncTabsWithSameLabels = (link) => {
const syncTabsWithSameLabels = (link: HTMLAnchorElement) => {
const linksWithSameName = findElementsWithTextContent('a', link.textContent);

for(let i = 0; i < linksWithSameName.length; i++) {
Expand All @@ -192,7 +195,7 @@ const syncTabsWithSameLabels = (link) => {
}
}

module.exports = {
export {
removeActiveClasses,
handleTabClicked,
copyToClipboard,
Expand Down
Loading
Loading