Implement enhanced UI elements with library detection and fallback
- Add modal implementation with automatic detection for four specific libraries. - Introduce inline tooltips with library compatibility. - Implement a default stand-alone fallback for environments without supported libraries.
This commit is contained in:
parent
5bbd1ed1f6
commit
d9f5a1aebc
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules
|
||||||
|
coverage
|
||||||
|
.idea
|
11
README.md
11
README.md
@ -1,8 +1,8 @@
|
|||||||
# GetBible Tooltips Integration Guide
|
# GetBible Loader Integration Guide
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
GetBible Tooltips is an intuitive and lightweight JavaScript solution for embedding Bible scripture tooltips into your website. By simply adding the `getBible` class to any element on your webpage, you can enable users to see the full scripture text in a tooltip when they hover over a reference.
|
GetBible loader is an intuitive and lightweight JavaScript solution for embedding Bible scripture into your website. By simply adding the `getBible` class to any element that has a scripture reference on your webpage, you can enable users to see the full scripture text as inline text, a tooltip or a modal.
|
||||||
|
|
||||||
## How to Add GetBible Tooltips to Your Website
|
## How to Add GetBible Tooltips to Your Website
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ GetBible Tooltips is an intuitive and lightweight JavaScript solution for embedd
|
|||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- Include the GetBible tooltips script from jsDelivr CDN -->
|
<!-- Include the GetBible tooltips script from jsDelivr CDN -->
|
||||||
<script src="https://cdn.jsdelivr.net/gh/getbible/loader@2.0.2/dist/js/getBible.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/gh/getbible/loader@3.0.0/dist/js/getBible.min.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Markup Your Scripture References:**
|
2. **Markup Your Scripture References:**
|
||||||
@ -27,12 +27,13 @@ GetBible Tooltips is an intuitive and lightweight JavaScript solution for embedd
|
|||||||
</ul>
|
</ul>
|
||||||
```
|
```
|
||||||
|
|
||||||
For a detailed example, check out the [basic usage example](https://git.vdm.dev/getBible/loader/src/branch/master/example/basic.html) in the `getbible/loader` repository.
|
For a detailed examples, check out the [tests](https://git.vdm.dev/getBible/loader/src/branch/master/tests/) in the `getbible/loader` repository.
|
||||||
|
|
||||||
## Utilizing Data Attributes
|
## Utilizing Data Attributes
|
||||||
|
|
||||||
Data attributes allow you to customize the behavior and display of the scripture tooltips.
|
Data attributes allow you to customize the behavior and display of the scripture.
|
||||||
|
|
||||||
|
- `data-format`: Specify the format you would like to load (e.g., `modal`). There are three options `modal`, `inline`, and `tooltip` you can just select one at a time.
|
||||||
- `data-translation`: Specify the Bible translations to use, separated by semicolons (e.g., `kjv;aov`). The tooltip will fetch the scripture from each translation listed.
|
- `data-translation`: Specify the Bible translations to use, separated by semicolons (e.g., `kjv;aov`). The tooltip will fetch the scripture from each translation listed.
|
||||||
- `data-show-translation`: Set to `1` to display the translation name in the tooltip.
|
- `data-show-translation`: Set to `1` to display the translation name in the tooltip.
|
||||||
- `data-show-abbreviation`: Set to `1` to display the abbreviation of the translation in the tooltip.
|
- `data-show-abbreviation`: Set to `1` to display the abbreviation of the translation in the tooltip.
|
||||||
|
1022
dist/js/getBible.js
vendored
1022
dist/js/getBible.js
vendored
File diff suppressed because it is too large
Load Diff
3
dist/js/getBible.min.js
vendored
3
dist/js/getBible.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,27 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>GetBible Tooltips (2.0.2) Example</title>
|
|
||||||
|
|
||||||
<!-- getBible JS -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/gh/getbible/loader@2.0.2/dist/js/getBible.min.js"></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<h1>Scripture References</h1>
|
|
||||||
|
|
||||||
<p>Hover over the references to see the scripture text:</p>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
<li class="getBible" data-translation="kjv;aov" data-show-translation="1" data-show-language="1">John 3:16,19</li>
|
|
||||||
<li class="getBible" data-show-abbreviation="1">John 3:16-17; 1 John 3:16-19,22</li>
|
|
||||||
<li class="getBible" data-translation="kjv;codex" data-show-language="1">Genesis 1:1</li>
|
|
||||||
<li class="getBible" data-translation="kjv;codex" data-show-language="1">Psalms 23:1-4</li>
|
|
||||||
<li class="getBible">Romans 8:28,31-39</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
2987
package-lock.json
generated
Normal file
2987
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
32
package.json
Normal file
32
package.json
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "getbible.loader",
|
||||||
|
"title": "getBible",
|
||||||
|
"description": "GetBible is an intuitive and lightweight JavaScript solution for embedding Bible scripture into your website.",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"main": "dist/js/getBible.min.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "rollup -c"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://git.vdm.dev/getBible/loader.git"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://git.vdm.dev/getBible/support"
|
||||||
|
},
|
||||||
|
"homepage": "https://getbible.net/biblekit",
|
||||||
|
"dependencies": {
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.15.0",
|
||||||
|
"@babel/preset-env": "^7.15.0",
|
||||||
|
"@rollup/plugin-babel": "^5.3.0",
|
||||||
|
"@rollup/plugin-commonjs": "^21.0.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||||
|
"rollup": "^2.60.0",
|
||||||
|
"rollup-plugin-terser": "^7.0.0",
|
||||||
|
"rollup-plugin-license": "^2.3.0",
|
||||||
|
"@rollup/plugin-replace": "^5.0.5"
|
||||||
|
}
|
||||||
|
}
|
58
rollup.config.js
Normal file
58
rollup.config.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import { babel } from '@rollup/plugin-babel';
|
||||||
|
import { terser } from 'rollup-plugin-terser';
|
||||||
|
import license from 'rollup-plugin-license';
|
||||||
|
import replace from '@rollup/plugin-replace';
|
||||||
|
|
||||||
|
const licenseLine = {
|
||||||
|
banner: `/*! getBible Loader v${require('./package.json').version} | https://getbible.net | (c) 2014 - ${new Date().getFullYear()} Llewellyn van der Merwe | MIT License */`
|
||||||
|
};
|
||||||
|
|
||||||
|
const licenseHeader = {
|
||||||
|
banner: `/**
|
||||||
|
* getBible Loader v${require('./package.json').version}
|
||||||
|
* https://getbible.net
|
||||||
|
* (c) 2014 - ${new Date().getFullYear()} Llewellyn van der Merwe
|
||||||
|
* MIT License
|
||||||
|
**/
|
||||||
|
`};
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
input: 'src/js/getBible.js',
|
||||||
|
plugins: [
|
||||||
|
license(licenseHeader),
|
||||||
|
replace({
|
||||||
|
'process.env.DEBUG': true,
|
||||||
|
preventAssignment: true,
|
||||||
|
})],
|
||||||
|
output: {
|
||||||
|
file: 'dist/js/getBible.js',
|
||||||
|
format: 'umd',
|
||||||
|
name: 'getBible',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'src/js/getBible.js',
|
||||||
|
plugins: [
|
||||||
|
resolve(),
|
||||||
|
commonjs(),
|
||||||
|
babel({
|
||||||
|
babelHelpers: 'bundled',
|
||||||
|
presets: ['@babel/preset-env'],
|
||||||
|
}),
|
||||||
|
terser(),
|
||||||
|
license(licenseLine),
|
||||||
|
replace({
|
||||||
|
'process.env.DEBUG': false,
|
||||||
|
preventAssignment: true,
|
||||||
|
})
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
file: 'dist/js/getBible.min.js',
|
||||||
|
format: 'umd',
|
||||||
|
name: 'getBible',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
57
src/js/core/Api.js
Normal file
57
src/js/core/Api.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { Memory } from './Memory.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for handling API calls to fetch scripture data.
|
||||||
|
*/
|
||||||
|
export class Api {
|
||||||
|
/**
|
||||||
|
* Constructs an Api instance with a default or specified API endpoint.
|
||||||
|
*
|
||||||
|
* @param {string} apiEndpoint - The endpoint URL for the API.
|
||||||
|
*/
|
||||||
|
constructor(apiEndpoint = 'https://query.getbible.net/v2/') {
|
||||||
|
this.apiEndpoint = apiEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches scripture from the API, using local storage to cache responses.
|
||||||
|
*
|
||||||
|
* @param {string} reference - The scripture reference.
|
||||||
|
* @param {string} translation - The translation.
|
||||||
|
* @returns {Promise<Object>} A promise that resolves with the scripture data.
|
||||||
|
* @throws {Error} If the API request fails.
|
||||||
|
*/
|
||||||
|
async get(reference, translation) {
|
||||||
|
try {
|
||||||
|
const localStorageData = await Memory.get(reference, translation);
|
||||||
|
if (localStorageData !== null) {
|
||||||
|
return localStorageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await fetch(this.#url(reference, translation));
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`${response.status} - ${response.statusText || 'Failed to fetch scripture'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
await Memory.set(reference, translation, data);
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching data:', error);
|
||||||
|
throw new Error(error.message || 'Error fetching scripture');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the URL for the API call.
|
||||||
|
*
|
||||||
|
* @param {string} reference - The scripture reference.
|
||||||
|
* @param {string} translation - The translation.
|
||||||
|
* @returns {string} The constructed URL for the API request.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#url(reference, translation) {
|
||||||
|
return `${this.apiEndpoint}${encodeURIComponent(translation)}/${encodeURIComponent(reference)}`;
|
||||||
|
}
|
||||||
|
}
|
72
src/js/core/Loader.js
Normal file
72
src/js/core/Loader.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { Api } from './Api.js';
|
||||||
|
import { Format } from '../formats/Format.js';
|
||||||
|
import { Element } from '../elements/Element.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loader class responsible for handling the loading of Bible references.
|
||||||
|
*/
|
||||||
|
export class Loader {
|
||||||
|
/**
|
||||||
|
* Constructs a Loader instance.
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
this.api = new Api();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the Bible references into the specified HTML element.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element - The element to load Bible references into.
|
||||||
|
*/
|
||||||
|
load(element) {
|
||||||
|
const references = element.innerHTML.split(';');
|
||||||
|
if (references) {
|
||||||
|
this.#init(element);
|
||||||
|
const translations = (element.dataset.translation || 'kjv').toLowerCase().split(';');
|
||||||
|
this.showBookName = element.dataset.showBookName ? parseInt(element.dataset.showBookName, 10) : 1;
|
||||||
|
this.showTranslation = element.dataset.showTranslation ? parseInt(element.dataset.showTranslation, 10) : 0;
|
||||||
|
this.showAbbreviation = element.dataset.showAbbreviation ? parseInt(element.dataset.showAbbreviation, 10) : 0;
|
||||||
|
this.showLanguage = element.dataset.showLanguage ? parseInt(element.dataset.showLanguage, 10) : 0;
|
||||||
|
|
||||||
|
references.forEach(reference => {
|
||||||
|
translations.forEach(translation => {
|
||||||
|
this.api.get(reference.trim(), translation.trim()).then(scripture => {
|
||||||
|
if (scripture) {
|
||||||
|
this.#load(scripture);
|
||||||
|
}
|
||||||
|
}).catch(error => console.error(error));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the target format and element for loading the Bible.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} element - The element to be initialized.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#init(element) {
|
||||||
|
const format = (element.dataset.format || 'inline').toLowerCase();
|
||||||
|
this.element = new Element(element, format);
|
||||||
|
this.format = new Format(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the Bible data in the target format into the initialized element.
|
||||||
|
*
|
||||||
|
* @param {Object} data - The data containing verses and their details.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
#load(data) {
|
||||||
|
this.element.load(
|
||||||
|
this.format.get(
|
||||||
|
data,
|
||||||
|
this.showBookName,
|
||||||
|
this.showTranslation,
|
||||||
|
this.showAbbreviation,
|
||||||
|
this.showLanguage
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
78
src/js/core/Memory.js
Normal file
78
src/js/core/Memory.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Class for managing local storage of scripture data.
|
||||||
|
*/
|
||||||
|
export class Memory {
|
||||||
|
// Constant representing one month in milliseconds.
|
||||||
|
static ONE_MONTH_IN_MILLISECONDS = 30 * 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores scripture data in local storage.
|
||||||
|
*
|
||||||
|
* @param {string} reference - The scripture reference.
|
||||||
|
* @param {string} translation - The translation.
|
||||||
|
* @param {Object} data - The scripture data to be stored.
|
||||||
|
* @throws {Error} If storing data fails.
|
||||||
|
*/
|
||||||
|
static set(reference, translation, data) {
|
||||||
|
const key = this.#key(reference, translation);
|
||||||
|
const item = {
|
||||||
|
data,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
localStorage.setItem(key, JSON.stringify(item));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error storing data in local storage:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves scripture data from local storage.
|
||||||
|
*
|
||||||
|
* @param {string} reference - The scripture reference.
|
||||||
|
* @param {string} translation - The translation.
|
||||||
|
* @returns {Promise<Object|null>} The scripture data or null if not found.
|
||||||
|
*/
|
||||||
|
static async get(reference, translation) {
|
||||||
|
return this.#get(reference, translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method to check local storage for scripture data.
|
||||||
|
*
|
||||||
|
* @param {string} reference - The scripture reference.
|
||||||
|
* @param {string} translation - The translation.
|
||||||
|
* @returns {Object|null} The stored data or null if not found.
|
||||||
|
* @throws {Error} If parsing or retrieval from local storage fails.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static #get(reference, translation) {
|
||||||
|
const key = this.#key(reference, translation);
|
||||||
|
try {
|
||||||
|
const storedItem = localStorage.getItem(key);
|
||||||
|
if (storedItem) {
|
||||||
|
const { data, timestamp } = JSON.parse(storedItem);
|
||||||
|
if (timestamp > Date.now() - Memory.ONE_MONTH_IN_MILLISECONDS) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error parsing or retrieving data from local storage:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a key for scripture data storage.
|
||||||
|
*
|
||||||
|
* @param {string} reference - The scripture reference.
|
||||||
|
* @param {string} translation - The translation.
|
||||||
|
* @returns {string} A unique key for local storage.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static #key(reference, translation) {
|
||||||
|
return `getBible-${translation}-${reference}`;
|
||||||
|
}
|
||||||
|
}
|
43
src/js/elements/Element.js
Normal file
43
src/js/elements/Element.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { ModalElement } from './ModalElement.js';
|
||||||
|
import { InlineElement } from './InlineElement.js';
|
||||||
|
import { TooltipElement } from './TooltipElement.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Element class responsible for creating and managing different types of elements
|
||||||
|
* based on the specified format.
|
||||||
|
*/
|
||||||
|
export class Element {
|
||||||
|
/**
|
||||||
|
* Constructs an Element instance based on the given format.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} triggerElement - The trigger element.
|
||||||
|
* @param {string} format - The format type.
|
||||||
|
*/
|
||||||
|
constructor(triggerElement, format = 'tooltip') {
|
||||||
|
if (!(triggerElement instanceof HTMLElement)) {
|
||||||
|
throw new Error("triggerElement must be an instance of HTMLElement.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const elementTypes = {
|
||||||
|
'modal': ModalElement,
|
||||||
|
'inline': InlineElement,
|
||||||
|
'tooltip': TooltipElement
|
||||||
|
};
|
||||||
|
|
||||||
|
const ElementType = elementTypes[format] || TooltipElement;
|
||||||
|
this.element = new ElementType(triggerElement);
|
||||||
|
|
||||||
|
if (process.env.DEBUG) {
|
||||||
|
console.log(`${format} element selected`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the content into the element.
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to load.
|
||||||
|
*/
|
||||||
|
load(content) {
|
||||||
|
this.element.load(content);
|
||||||
|
}
|
||||||
|
}
|
28
src/js/elements/InlineElement.js
Normal file
28
src/js/elements/InlineElement.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* InlineElement class responsible for adding inline elements.
|
||||||
|
*/
|
||||||
|
export class InlineElement {
|
||||||
|
/**
|
||||||
|
* Creates an instance of InlineElement.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} triggerElement - The element that triggers the inline display.
|
||||||
|
*/
|
||||||
|
constructor(triggerElement) {
|
||||||
|
if (!(triggerElement instanceof HTMLElement)) {
|
||||||
|
throw new Error("triggerElement must be an instance of HTMLElement.");
|
||||||
|
}
|
||||||
|
this.triggerElement = triggerElement;
|
||||||
|
// Clear initial content
|
||||||
|
this.triggerElement.innerHTML = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads content into the trigger element. Appends new content if existing content is present.
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to load into the trigger element.
|
||||||
|
*/
|
||||||
|
load(content) {
|
||||||
|
const existingContent = this.triggerElement.innerHTML;
|
||||||
|
this.triggerElement.innerHTML = existingContent ? `${existingContent}\n ${content}` : content;
|
||||||
|
}
|
||||||
|
}
|
59
src/js/elements/ModalElement.js
Normal file
59
src/js/elements/ModalElement.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { BaseModal } from './modals/BaseModal.js';
|
||||||
|
import { UikitModal } from './modals/UikitModal.js';
|
||||||
|
import { BootstrapModal } from './modals/BootstrapModal.js';
|
||||||
|
import { FoundationModal } from './modals/FoundationModal.js';
|
||||||
|
import { TailwindModal } from './modals/TailwindModal.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ModalElement class responsible for creating and managing modal elements.
|
||||||
|
* It dynamically selects the appropriate modal style based on the available UI framework.
|
||||||
|
*/
|
||||||
|
export class ModalElement {
|
||||||
|
/**
|
||||||
|
* Constructs an instance of ModalElement with the appropriate modal type
|
||||||
|
* based on the detected UI framework.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} triggerElement - The element that triggers the modal.
|
||||||
|
*/
|
||||||
|
constructor(triggerElement) {
|
||||||
|
this.modal = ModalElement.framework(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads content into the modal.
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to load into the modal.
|
||||||
|
*/
|
||||||
|
load(content) {
|
||||||
|
this.modal.load(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the appropriate modal implementation based on the available UI framework.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} triggerElement - The element triggering the modal.
|
||||||
|
* @returns {BaseModal|BootstrapModal|UikitModal|FoundationModal|TailwindModal} The modal instance.
|
||||||
|
*/
|
||||||
|
static framework(triggerElement) {
|
||||||
|
const frameworks = {
|
||||||
|
'UIkit': UikitModal,
|
||||||
|
'bootstrap': BootstrapModal,
|
||||||
|
'Foundation': FoundationModal,
|
||||||
|
'tailwind': TailwindModal
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [key, ModalType] of Object.entries(frameworks)) {
|
||||||
|
if (typeof window[key] !== 'undefined' || (key === 'tailwind' && document.querySelector('.tailwind-class') !== null)) {
|
||||||
|
if (process.env.DEBUG) {
|
||||||
|
console.log(`${key} modal selected`);
|
||||||
|
}
|
||||||
|
return new ModalType(triggerElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.DEBUG) {
|
||||||
|
console.log(`base modal selected`);
|
||||||
|
}
|
||||||
|
return new BaseModal(triggerElement);
|
||||||
|
}
|
||||||
|
}
|
60
src/js/elements/TooltipElement.js
Normal file
60
src/js/elements/TooltipElement.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { BaseTooltip } from './tooltip/BaseTooltip.js';
|
||||||
|
import { BootstrapTooltip } from './tooltip/BootstrapTooltip.js';
|
||||||
|
import { UikitTooltip } from './tooltip/UikitTooltip.js';
|
||||||
|
import { FoundationTooltip } from './tooltip/FoundationTooltip.js';
|
||||||
|
import { TailwindTooltip } from './tooltip/TailwindTooltip.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TooltipElement class responsible for creating and managing tooltip elements.
|
||||||
|
* It dynamically selects the appropriate tooltip style based on the available UI framework.
|
||||||
|
*/
|
||||||
|
export class TooltipElement {
|
||||||
|
/**
|
||||||
|
* Constructs an instance of TooltipElement with the appropriate tooltip type
|
||||||
|
* based on the detected UI framework.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} triggerElement - The element that triggers the tooltip.
|
||||||
|
*/
|
||||||
|
constructor(triggerElement) {
|
||||||
|
this.tooltip = TooltipElement.framework(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads content into the tooltip.
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to load into the tooltip.
|
||||||
|
*/
|
||||||
|
load(content) {
|
||||||
|
this.tooltip.load(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the appropriate tooltip implementation based on the available UI framework.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} triggerElement - The element triggering the tooltip.
|
||||||
|
* @returns {BaseTooltip|BootstrapTooltip|UikitTooltip|FoundationTooltip|TailwindTooltip} The tooltip instance.
|
||||||
|
* @param debug
|
||||||
|
*/
|
||||||
|
static framework(triggerElement) {
|
||||||
|
const frameworks = {
|
||||||
|
'UIkit': UikitTooltip,
|
||||||
|
'bootstrap': BootstrapTooltip,
|
||||||
|
'Foundation': FoundationTooltip,
|
||||||
|
'tailwind': TailwindTooltip
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [key, TooltipType] of Object.entries(frameworks)) {
|
||||||
|
if (typeof window[key] !== 'undefined' || (key === 'tailwind' && document.querySelector('.tailwind-class') !== null)) {
|
||||||
|
if (process.env.DEBUG) {
|
||||||
|
console.log(`${key} tooltip selected`);
|
||||||
|
}
|
||||||
|
return new TooltipType(triggerElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.DEBUG) {
|
||||||
|
console.log(`base tooltip selected`);
|
||||||
|
}
|
||||||
|
return new BaseTooltip(triggerElement);
|
||||||
|
}
|
||||||
|
}
|
77
src/js/elements/modals/BaseModal.js
Normal file
77
src/js/elements/modals/BaseModal.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
export class BaseModal {
|
||||||
|
/**
|
||||||
|
* Creates a new BaseModal instance.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} triggerElement - The elements that triggers the modal.
|
||||||
|
*/
|
||||||
|
constructor(triggerElement) {
|
||||||
|
this.modalId = `modal-${Math.random().toString(36).slice(2, 11)}`;
|
||||||
|
this.triggerElement = triggerElement;
|
||||||
|
this.triggerElement.style.cursor = 'pointer';
|
||||||
|
this.initializeTrigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads content into the modal.
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to load into the modal.
|
||||||
|
*/
|
||||||
|
load(content) {
|
||||||
|
const existingModal = document.getElementById(this.modalId);
|
||||||
|
// Check if modal already exists
|
||||||
|
if (existingModal) {
|
||||||
|
// Update the content of the existing modal
|
||||||
|
const contentDiv = document.getElementById(`${this.modalId}-content`);
|
||||||
|
if (contentDiv) {
|
||||||
|
contentDiv.innerHTML += content;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If modal doesn't exist, create it with the new content
|
||||||
|
this.create(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert HTML into the dom.
|
||||||
|
*
|
||||||
|
* @param {string} html - The html to insert.
|
||||||
|
*/
|
||||||
|
insertIntoDOM(html) {
|
||||||
|
document.body.insertAdjacentHTML('beforeend', html);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the modal.
|
||||||
|
*
|
||||||
|
* @param {string} content - The initial content of the modal.
|
||||||
|
*/
|
||||||
|
create(content) {
|
||||||
|
const modalHtml = `
|
||||||
|
<div id="${this.modalId}" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background-color:rgba(0, 0, 0, 0.5); justify-content:center; align-items:center;">
|
||||||
|
<div style="position:relative; background-color:white; padding:20px; border-radius:5px; max-width:300px;">
|
||||||
|
<button class="getbible-modal-close" type="button" onclick="document.getElementById('${this.modalId}').style.display='none'" style="position:absolute; top:10px; right:10px; border:none; background:transparent; font-size:24px; cursor:pointer;">✖</button>
|
||||||
|
<div id="${this.modalId}-content">
|
||||||
|
${content}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
this.insertIntoDOM(modalHtml);
|
||||||
|
|
||||||
|
const modalElement = document.getElementById(this.modalId);
|
||||||
|
modalElement.addEventListener('click', (event) => {
|
||||||
|
if (event.target === modalElement) {
|
||||||
|
modalElement.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the modal trigger.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
initializeTrigger() {
|
||||||
|
this.triggerElement.addEventListener('click', () => {
|
||||||
|
document.getElementById(this.modalId).style.display = 'flex';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
41
src/js/elements/modals/BootstrapModal.js
Normal file
41
src/js/elements/modals/BootstrapModal.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { BaseModal } from './BaseModal.js';
|
||||||
|
|
||||||
|
export class BootstrapModal extends BaseModal {
|
||||||
|
constructor(triggerElement) {
|
||||||
|
super(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
const modal = new bootstrap.Modal(document.getElementById(this.modalId));
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
const modal = bootstrap.Modal.getInstance(document.getElementById(this.modalId));
|
||||||
|
if (modal) {
|
||||||
|
modal.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create(content) {
|
||||||
|
const modalHtml = `
|
||||||
|
<div class="modal fade" id="${this.modalId}" tabindex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content p-3">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div id="${this.modalId}-content" class="modal-body">
|
||||||
|
${content}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
this.insertIntoDOM(modalHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTrigger() {
|
||||||
|
this.triggerElement.setAttribute('data-bs-toggle', 'modal');
|
||||||
|
this.triggerElement.setAttribute('data-bs-target', `#${this.modalId}`);
|
||||||
|
}
|
||||||
|
}
|
38
src/js/elements/modals/FoundationModal.js
Normal file
38
src/js/elements/modals/FoundationModal.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { BaseModal } from './BaseModal.js';
|
||||||
|
|
||||||
|
export class FoundationModal extends BaseModal {
|
||||||
|
constructor(triggerElement) {
|
||||||
|
super(triggerElement);
|
||||||
|
this.modalElement = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
if (this.modalElement) {
|
||||||
|
this.modalElement.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
if (this.modalElement) {
|
||||||
|
this.modalElement.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create(content) {
|
||||||
|
const modalHtml = `
|
||||||
|
<div class="reveal" id="${this.modalId}" data-reveal>
|
||||||
|
<div id="${this.modalId}-content">
|
||||||
|
${content}
|
||||||
|
</div>
|
||||||
|
<button class="close-button" data-close aria-label="Close modal" type="button">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>`;
|
||||||
|
this.insertIntoDOM(modalHtml);
|
||||||
|
this.modalElement = new Foundation.Reveal(document.getElementById(this.modalId));
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTrigger() {
|
||||||
|
this.triggerElement.setAttribute('data-open', this.modalId);
|
||||||
|
}
|
||||||
|
}
|
35
src/js/elements/modals/TailwindModal.js
Normal file
35
src/js/elements/modals/TailwindModal.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { BaseModal } from './BaseModal.js';
|
||||||
|
|
||||||
|
export class TailwindModal extends BaseModal {
|
||||||
|
constructor(triggerElement) {
|
||||||
|
super(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
document.getElementById(this.modalId).classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
document.getElementById(this.modalId).classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
create(content) {
|
||||||
|
const modalHtml = `
|
||||||
|
<div class="modal hidden fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full" id="${this.modalId}">
|
||||||
|
<div class="modal-content container mx-auto p-5 bg-white">
|
||||||
|
<div id="${this.modalId}-content">
|
||||||
|
${content}
|
||||||
|
</div>
|
||||||
|
<button class="close-button" onclick="document.getElementById('${this.modalId}').classList.add('hidden')">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
this.insertIntoDOM(modalHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTrigger(triggerElement) {
|
||||||
|
this.triggerElement.addEventListener('click', () => {
|
||||||
|
document.getElementById(this.modalId).classList.remove('hidden');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
33
src/js/elements/modals/UikitModal.js
Normal file
33
src/js/elements/modals/UikitModal.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { BaseModal } from './BaseModal.js';
|
||||||
|
|
||||||
|
export class UikitModal extends BaseModal {
|
||||||
|
constructor(triggerElement) {
|
||||||
|
super(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
UIkit.modal(`#${this.modalId}`).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
UIkit.modal(`#${this.modalId}`).hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
create(content) {
|
||||||
|
const modalHtml = `
|
||||||
|
<div id="${this.modalId}" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body">
|
||||||
|
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||||
|
<div id="${this.modalId}-content">
|
||||||
|
${content}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
this.insertIntoDOM(modalHtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeTrigger() {
|
||||||
|
this.triggerElement.setAttribute('uk-toggle', `target: #${this.modalId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
24
src/js/elements/tooltip/BaseTooltip.js
Normal file
24
src/js/elements/tooltip/BaseTooltip.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export class BaseTooltip {
|
||||||
|
/**
|
||||||
|
* Creates a new BaseTooltip instance.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} triggerElement - The elements that triggers the tooltip.
|
||||||
|
*/
|
||||||
|
constructor(triggerElement) {
|
||||||
|
this.triggerElement = triggerElement;
|
||||||
|
this.triggerElement.style.cursor = 'help';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads content into the tooltip. If the trigger elements already has a title,
|
||||||
|
* the new content is appended to it.
|
||||||
|
*
|
||||||
|
* @param {string} content - The content to load into the tooltip.
|
||||||
|
* @throws {Error} Throws an error if the trigger elements is not valid.
|
||||||
|
*/
|
||||||
|
load(content) {
|
||||||
|
const existingTitle = this.triggerElement.getAttribute('title');
|
||||||
|
const newTitle = existingTitle ? existingTitle + "\n" + content : content;
|
||||||
|
this.triggerElement.setAttribute('title', newTitle);
|
||||||
|
}
|
||||||
|
}
|
19
src/js/elements/tooltip/BootstrapTooltip.js
Normal file
19
src/js/elements/tooltip/BootstrapTooltip.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { BaseTooltip } from './BaseTooltip.js';
|
||||||
|
|
||||||
|
export class BootstrapTooltip extends BaseTooltip {
|
||||||
|
constructor(triggerElement) {
|
||||||
|
super(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
load(content) {
|
||||||
|
try {
|
||||||
|
super.load(content);
|
||||||
|
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||||
|
const tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||||
|
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading BootstrapTooltip:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
src/js/elements/tooltip/FoundationTooltip.js
Normal file
33
src/js/elements/tooltip/FoundationTooltip.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { BaseTooltip } from './BaseTooltip.js';
|
||||||
|
|
||||||
|
export class FoundationTooltip extends BaseTooltip {
|
||||||
|
constructor(triggerElement) {
|
||||||
|
super(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
load(content) {
|
||||||
|
try {
|
||||||
|
this.triggerElement.setAttribute('data-tooltip', '');
|
||||||
|
super.load(content);
|
||||||
|
this.triggerElement.classList.add('has-tip');
|
||||||
|
|
||||||
|
new Foundation.Tooltip(this.triggerElement, {
|
||||||
|
// Default options
|
||||||
|
disableHover: false, // Allows tooltip to be hoverable
|
||||||
|
fadeOutDuration: 150, // Duration of fade out animation in milliseconds
|
||||||
|
fadeInDuration: 150, // Duration of fade in animation in milliseconds
|
||||||
|
showOn: 'all', // Can be 'all', 'large', 'medium', 'small'
|
||||||
|
templateClasses: '', // Custom class(es) to be added to the tooltip template
|
||||||
|
tipText: () => this.triggerElement.getAttribute('title'), // Function to define tooltip text
|
||||||
|
triggerClass: 'has-tip', // Class to be added on the trigger elements
|
||||||
|
touchCloseText: 'tap to close', // Text for close button on touch devices
|
||||||
|
positionClass: 'top', // Position of tooltip, can be 'top', 'bottom', 'left', 'right', etc.
|
||||||
|
vOffset: 10, // Vertical offset
|
||||||
|
hOffset: 12, // Horizontal offset
|
||||||
|
allowHtml: false // Allow HTML in tooltip content
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading FoundationTooltip:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
src/js/elements/tooltip/TailwindTooltip.js
Normal file
44
src/js/elements/tooltip/TailwindTooltip.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { BaseTooltip } from './BaseTooltip.js';
|
||||||
|
|
||||||
|
export class TailwindTooltip extends BaseTooltip {
|
||||||
|
constructor(triggerElement) {
|
||||||
|
super(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
load(content) {
|
||||||
|
try {
|
||||||
|
super.load(content);
|
||||||
|
this._createTooltipElement();
|
||||||
|
this._initializeEvents();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading TailwindTooltip:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_createTooltipElement() {
|
||||||
|
this.tooltipElement = document.createElement('div');
|
||||||
|
this.tooltipElement.id = this.tooltipId;
|
||||||
|
this.tooltipElement.className = 'absolute invisible bg-gray-800 text-white text-xs px-2 py-1 rounded-md';
|
||||||
|
this.tooltipElement.style.transition = 'visibility 0.3s linear, opacity 0.3s linear';
|
||||||
|
this.tooltipElement.textContent = this.triggerElement.getAttribute('title');
|
||||||
|
document.body.appendChild(this.tooltipElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
_initializeEvents() {
|
||||||
|
this.triggerElement.addEventListener('mouseenter', () => {
|
||||||
|
const rect = this.triggerElement.getBoundingClientRect();
|
||||||
|
this._title = this.triggerElement.getAttribute('title');
|
||||||
|
this.tooltipElement.style.left = `${rect.left + window.scrollX}px`;
|
||||||
|
this.tooltipElement.style.top = `${rect.bottom + 5 + window.scrollY}px`;
|
||||||
|
this.tooltipElement.classList.remove('invisible');
|
||||||
|
this.tooltipElement.classList.add('opacity-100');
|
||||||
|
this.triggerElement.setAttribute('title', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.triggerElement.addEventListener('mouseleave', () => {
|
||||||
|
this.tooltipElement.classList.add('invisible');
|
||||||
|
this.tooltipElement.classList.remove('opacity-100');
|
||||||
|
this.triggerElement.setAttribute('title', this._title);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
16
src/js/elements/tooltip/UikitTooltip.js
Normal file
16
src/js/elements/tooltip/UikitTooltip.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { BaseTooltip } from './BaseTooltip.js';
|
||||||
|
|
||||||
|
export class UikitTooltip extends BaseTooltip {
|
||||||
|
constructor(triggerElement) {
|
||||||
|
super(triggerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
load(content) {
|
||||||
|
try {
|
||||||
|
super.load(content);
|
||||||
|
UIkit.tooltip(this.triggerElement);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading UikitTooltip:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/js/formats/BaseFormat.js
Normal file
16
src/js/formats/BaseFormat.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export class BaseFormat {
|
||||||
|
/**
|
||||||
|
* Get formats the verses.
|
||||||
|
*
|
||||||
|
* @param {Object} data - The data containing verses and their details.
|
||||||
|
* @param {boolean} showBook - Whether to show book names.
|
||||||
|
* @param {boolean} showTrans - Whether to show translations.
|
||||||
|
* @param {boolean} showAbbr - Whether to show abbreviations.
|
||||||
|
* @param {boolean} showLang - Whether to show languages.
|
||||||
|
* @returns {string} The formatted verses.
|
||||||
|
* @abstract
|
||||||
|
*/
|
||||||
|
get(data, showBook, showTrans, showAbbr, showLang) {
|
||||||
|
throw new Error("The 'get' method must be implemented in BaseFormat subclass.");
|
||||||
|
}
|
||||||
|
}
|
56
src/js/formats/BlockFormat.js
Normal file
56
src/js/formats/BlockFormat.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { BaseFormat } from './BaseFormat.js';
|
||||||
|
|
||||||
|
export class BlockFormat extends BaseFormat {
|
||||||
|
/**
|
||||||
|
* Formats the verses for HTML block elements.
|
||||||
|
*
|
||||||
|
* @param {Object} data - The data containing verses and their details.
|
||||||
|
* @param {boolean} showBook - Whether to show book names.
|
||||||
|
* @param {boolean} showTrans - Whether to show translations.
|
||||||
|
* @param {boolean} showAbbr - Whether to show abbreviations.
|
||||||
|
* @param {boolean} showLang - Whether to show languages.
|
||||||
|
* @returns {string} The formatted HTML string.
|
||||||
|
*/
|
||||||
|
get(data, showBook, showTrans, showAbbr, showLang) {
|
||||||
|
let formattedHtml = '';
|
||||||
|
let setBookName = new Set();
|
||||||
|
let setTranslation = new Set();
|
||||||
|
let setAbbreviation = new Set();
|
||||||
|
let setLanguage = new Set();
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
if (!data.hasOwnProperty(key)) continue;
|
||||||
|
|
||||||
|
let headerParts = [];
|
||||||
|
if (showTrans && !setTranslation.has(key)) {
|
||||||
|
headerParts.push(`<span class="getbible-translation">${data[key].translation}</span>`);
|
||||||
|
setTranslation.add(key);
|
||||||
|
}
|
||||||
|
if (showAbbr && !setAbbreviation.has(key)) {
|
||||||
|
headerParts.push(`<span class="getbible-abbreviation">${data[key].abbreviation}</span>`);
|
||||||
|
setAbbreviation.add(key);
|
||||||
|
}
|
||||||
|
if (showBook && !setBookName.has(key)) {
|
||||||
|
headerParts.push(`<span class="getbible-book-name">${data[key].name}</span>`);
|
||||||
|
setBookName.add(key);
|
||||||
|
}
|
||||||
|
if (showLang && !setLanguage.has(key)) {
|
||||||
|
headerParts.push(`<span class="getbible-language">${data[key].language}</span>`);
|
||||||
|
setLanguage.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the header
|
||||||
|
if (headerParts.length > 0) {
|
||||||
|
formattedHtml += `<div class="getbible-header">[${headerParts.join(' - ')}]</div>\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add verses
|
||||||
|
const verses = data[key].verses
|
||||||
|
.map(verse => `<span class="getbible-verse">${verse.verse}. ${verse.text}</span>`)
|
||||||
|
.join("<br />");
|
||||||
|
formattedHtml += `<div class="getbible-verses">${verses}</div><br />`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<div class="getbible-element getbible-block">${formattedHtml}</div>`;
|
||||||
|
}
|
||||||
|
}
|
39
src/js/formats/Format.js
Normal file
39
src/js/formats/Format.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { BlockFormat } from './BlockFormat.js';
|
||||||
|
import { InlineFormat } from './InlineFormat.js';
|
||||||
|
import { PlainFormat } from './PlainFormat.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format class responsible for creating and managing different types of formats
|
||||||
|
* based on the specified type.
|
||||||
|
*/
|
||||||
|
export class Format {
|
||||||
|
/**
|
||||||
|
* Constructs a Format instance based on the given type.
|
||||||
|
*
|
||||||
|
* @param {string} formatType - The format type.
|
||||||
|
*/
|
||||||
|
constructor(formatType = 'tooltip') {
|
||||||
|
const formatTypes = {
|
||||||
|
'modal': BlockFormat,
|
||||||
|
'inline': InlineFormat,
|
||||||
|
'tooltip': PlainFormat
|
||||||
|
};
|
||||||
|
|
||||||
|
const FormatType = formatTypes[formatType] || PlainFormat;
|
||||||
|
this.format = new FormatType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the formatted verses.
|
||||||
|
*
|
||||||
|
* @param {Object} data - The data containing verses and their details.
|
||||||
|
* @param {boolean} showBook - Whether to show book names.
|
||||||
|
* @param {boolean} showTrans - Whether to show translations.
|
||||||
|
* @param {boolean} showAbbr - Whether to show abbreviations.
|
||||||
|
* @param {boolean} showLang - Whether to show languages.
|
||||||
|
* @returns {string} The formatted verses.
|
||||||
|
*/
|
||||||
|
get(data, showBook, showTrans, showAbbr, showLang) {
|
||||||
|
return this.format.get(data, showBook, showTrans, showAbbr, showLang);
|
||||||
|
}
|
||||||
|
}
|
56
src/js/formats/InlineFormat.js
Normal file
56
src/js/formats/InlineFormat.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { BaseFormat } from './BaseFormat.js';
|
||||||
|
|
||||||
|
export class InlineFormat extends BaseFormat {
|
||||||
|
/**
|
||||||
|
* Formats the verses for HTML inline elements.
|
||||||
|
*
|
||||||
|
* @param {Object} data - The data containing verses and their details.
|
||||||
|
* @param {boolean} showBook - Whether to show book names.
|
||||||
|
* @param {boolean} showTrans - Whether to show translations.
|
||||||
|
* @param {boolean} showAbbr - Whether to show abbreviations.
|
||||||
|
* @param {boolean} showLang - Whether to show languages.
|
||||||
|
* @returns {string} The formatted HTML string.
|
||||||
|
*/
|
||||||
|
get(data, showBook, showTrans, showAbbr, showLang) {
|
||||||
|
let formattedHtml = '';
|
||||||
|
let setBookName = new Set();
|
||||||
|
let setTranslation = new Set();
|
||||||
|
let setAbbreviation = new Set();
|
||||||
|
let setLanguage = new Set();
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
if (!data.hasOwnProperty(key)) continue;
|
||||||
|
|
||||||
|
let footerParts = [];
|
||||||
|
if (showTrans && !setTranslation.has(key)) {
|
||||||
|
footerParts.push(`<span class="getbible-translation">${data[key].translation}</span>`);
|
||||||
|
setTranslation.add(key);
|
||||||
|
}
|
||||||
|
if (showAbbr && !setAbbreviation.has(key)) {
|
||||||
|
footerParts.push(`<span class="getbible-abbreviation">${data[key].abbreviation}</span>`);
|
||||||
|
setAbbreviation.add(key);
|
||||||
|
}
|
||||||
|
if (showBook && !setBookName.has(key)) {
|
||||||
|
footerParts.push(`<span class="getbible-book-name">${data[key].name}</span>`);
|
||||||
|
setBookName.add(key);
|
||||||
|
}
|
||||||
|
if (showLang && !setLanguage.has(key)) {
|
||||||
|
footerParts.push(`<span class="getbible-language">${data[key].language}</span>`);
|
||||||
|
setLanguage.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add verses
|
||||||
|
const verses = data[key].verses
|
||||||
|
.map(verse => `<span class="getbible-verse">${verse.verse}. ${verse.text}</span>`)
|
||||||
|
.join("\n");
|
||||||
|
formattedHtml += `<span class="getbible-verses">${verses}</span>\n`;
|
||||||
|
|
||||||
|
// Construct the footer
|
||||||
|
if (footerParts.length > 0) {
|
||||||
|
formattedHtml += `<span class="getbible-footer">[${footerParts.join(' - ')}]</span>\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<span class="getbible-element getbible-inline">${formattedHtml}</span>`;
|
||||||
|
}
|
||||||
|
}
|
54
src/js/formats/PlainFormat.js
Normal file
54
src/js/formats/PlainFormat.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { BaseFormat } from './BaseFormat.js';
|
||||||
|
|
||||||
|
export class PlainFormat extends BaseFormat {
|
||||||
|
/**
|
||||||
|
* Formats the verses for plain text display.
|
||||||
|
*
|
||||||
|
* @param {Object} data - The data containing verses and their details.
|
||||||
|
* @param {boolean} showBook - Whether to show book names.
|
||||||
|
* @param {boolean} showTrans - Whether to show translations.
|
||||||
|
* @param {boolean} showAbbr - Whether to show abbreviations.
|
||||||
|
* @param {boolean} showLang - Whether to show languages.
|
||||||
|
* @returns {string} The formatted text.
|
||||||
|
*/
|
||||||
|
get(data, showBook, showTrans, showAbbr, showLang) {
|
||||||
|
let formattedText = '';
|
||||||
|
let setBookName = new Set();
|
||||||
|
let setTranslation = new Set();
|
||||||
|
let setAbbreviation = new Set();
|
||||||
|
let setLanguage = new Set();
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
if (!data.hasOwnProperty(key)) continue; // Ensure processing only own properties
|
||||||
|
|
||||||
|
let headerParts = [];
|
||||||
|
if (showTrans && !setTranslation.has(key)) {
|
||||||
|
headerParts.push(data[key].translation);
|
||||||
|
setTranslation.add(key);
|
||||||
|
}
|
||||||
|
if (showAbbr && !setAbbreviation.has(key)) {
|
||||||
|
headerParts.push(data[key].abbreviation);
|
||||||
|
setAbbreviation.add(key);
|
||||||
|
}
|
||||||
|
if (showBook && !setBookName.has(key)) {
|
||||||
|
headerParts.push(data[key].name);
|
||||||
|
setBookName.add(key);
|
||||||
|
}
|
||||||
|
if (showLang && !setLanguage.has(key)) {
|
||||||
|
headerParts.push(data[key].language);
|
||||||
|
setLanguage.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the header
|
||||||
|
if (headerParts.length > 0) {
|
||||||
|
formattedText += '[' + headerParts.join(' - ') + "]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add verses
|
||||||
|
const verses = data[key].verses.map(verse => `${verse.verse}. ${verse.text}`).join("\n");
|
||||||
|
formattedText += verses + "\n\n"; // Add extra newline for separation
|
||||||
|
}
|
||||||
|
|
||||||
|
return formattedText.trim();
|
||||||
|
}
|
||||||
|
}
|
14
src/js/getBible.js
Normal file
14
src/js/getBible.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Loader } from "./core/Loader.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point to load Bible references.
|
||||||
|
* Attaches event listener to DOMContentLoaded to find elements with class 'getBible'
|
||||||
|
* and initializes Loader for each element.
|
||||||
|
*/
|
||||||
|
document.addEventListener('DOMContentLoaded', (event) => {
|
||||||
|
const elements = document.querySelectorAll('.getBible');
|
||||||
|
elements.forEach(element => {
|
||||||
|
const loader = new Loader();
|
||||||
|
loader.load(element);
|
||||||
|
});
|
||||||
|
});
|
29
tests/basic.html
Normal file
29
tests/basic.html
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Basic GetBible Test</title>
|
||||||
|
|
||||||
|
<!-- getBible JS -->
|
||||||
|
<script src="../dist/js/getBible.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Scripture References</h1>
|
||||||
|
|
||||||
|
<p>Hover over the references to see the scripture text:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li class="getBible" data-translation="kjv;aov" data-show-translation="1" data-show-language="1"
|
||||||
|
data-format="tooltip">John 3:16,19
|
||||||
|
</li>
|
||||||
|
<li class="getBible" data-show-abbreviation="1" data-format="modal">John 3:16-17; 1 John 3:16-19,22</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="modal">Genesis 1:1</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="inline">Psalms 23:1-4</li>
|
||||||
|
<li class="getBible">Romans 8:28,31-39</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
38
tests/bootstrap.html
Normal file
38
tests/bootstrap.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Bootstrap Tooltips Test | GetBible</title>
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
|
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"
|
||||||
|
integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"
|
||||||
|
integrity="sha384-BBtl+eGJRgqQAUMxJ7pMwbEyER4l1g+O15P+16Ep7Q9Q+zqX6gSbd85u4mG4QzX+"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<!-- getBible JS -->
|
||||||
|
<script src="../dist/js/getBible.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Scripture References</h1>
|
||||||
|
|
||||||
|
<p>Hover over the references to see the scripture text:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li class="getBible" data-translation="kjv;aov" data-show-translation="1" data-show-language="1"
|
||||||
|
data-format="tooltip">John 3:16,19
|
||||||
|
</li>
|
||||||
|
<li class="getBible" data-show-abbreviation="1" data-format="modal">John 3:16-17; 1 John 3:16-19,22</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="modal">Genesis 1:1</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="tooltip">Psalms 23:1-4</li>
|
||||||
|
<li class="getBible">Romans 8:28,31-39</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
42
tests/foundation.html
Normal file
42
tests/foundation.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="no-js" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<title>Foundation Tooltips Test | GetBible</title>
|
||||||
|
|
||||||
|
<!-- Compressed CSS -->
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.8.1/dist/css/foundation.min.css"
|
||||||
|
crossorigin="anonymous">
|
||||||
|
|
||||||
|
<!-- getBible JS -->
|
||||||
|
<script src="../dist/js/getBible.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Scripture References</h1>
|
||||||
|
|
||||||
|
<p>Hover over the references to see the scripture text:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li class="getBible" data-translation="kjv;aov" data-show-translation="1" data-show-language="1"
|
||||||
|
data-format="tooltip">John 3:16,19
|
||||||
|
</li>
|
||||||
|
<li class="getBible" data-show-abbreviation="1" data-format="modal">John 3:16-17; 1 John 3:16-19,22</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="modal">Genesis 1:1</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="tooltip">Psalms 23:1-4</li>
|
||||||
|
<li class="getBible">Romans 8:28,31-39</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- Compressed JavaScript -->
|
||||||
|
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||||
|
<!-- Compressed JavaScript -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/foundation-sites@6.8.1/dist/js/foundation.min.js"
|
||||||
|
crossorigin="anonymous"></script>
|
||||||
|
<script>
|
||||||
|
$(document).foundation();
|
||||||
|
</script>
|
||||||
|
<h3>Please help us!!! We are not getting this to work, because of jQuery, or so it seems.</h3>
|
||||||
|
</body>
|
||||||
|
</html>
|
35
tests/tailwind.html
Normal file
35
tests/tailwind.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Tailwind Tooltips Test | GetBible</title>
|
||||||
|
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
|
||||||
|
<!-- getBible JS -->
|
||||||
|
<script src="../dist/js/getBible.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<header class="bg-blue-500 text-white text-lg p-4">
|
||||||
|
<div class="container mx-auto flex justify-between items-center">
|
||||||
|
<h1 class="font-bold">Scripture References</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<p>Hover over the references to see the scripture text:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li class="getBible" data-translation="kjv;aov" data-show-translation="1" data-show-language="1"
|
||||||
|
data-format="tooltip">John 3:16,19
|
||||||
|
</li>
|
||||||
|
<li class="getBible" data-show-abbreviation="1" data-format="modal">John 3:16-17; 1 John 3:16-19,22</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="modal">Genesis 1:1</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="tooltip">Psalms 23:1-4</li>
|
||||||
|
<li class="getBible">Romans 8:28,31-39</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
36
tests/uikit.html
Normal file
36
tests/uikit.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Uikit Tooltips Test | GetBible</title>
|
||||||
|
|
||||||
|
<!-- UIkit CSS -->
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/uikit@3.17.10/dist/css/uikit.min.css"/>
|
||||||
|
|
||||||
|
<!-- UIkit JS -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/uikit@3.17.10/dist/js/uikit.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/uikit@3.17.10/dist/js/uikit-icons.min.js"></script>
|
||||||
|
|
||||||
|
<!-- getBible JS -->
|
||||||
|
<script src="../dist/js/getBible.min.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Scripture References</h1>
|
||||||
|
|
||||||
|
<p>Hover over the references to see the scripture text:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li class="getBible" data-translation="kjv;aov" data-show-translation="1" data-show-language="1"
|
||||||
|
data-format="tooltip">John 3:16,19
|
||||||
|
</li>
|
||||||
|
<li class="getBible" data-show-abbreviation="1" data-format="modal">John 3:16-17; 1 John 3:16-19,22</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="modal">Genesis 1:1</li>
|
||||||
|
<li class="getBible" data-translation="kjv;codex" data-show-language="1" data-format="tooltip">Psalms 23:1-4</li>
|
||||||
|
<li class="getBible">Romans 8:28,31-39</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user