/* This file is part of Ezra Bible App.
Copyright (C) 2019 - 2023 Ezra Bible App Development Team <contact@ezrabibleapp.net>
Ezra Bible App is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
Ezra Bible App is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Ezra Bible App. See the file LICENSE.
If not, see <http://www.gnu.org/licenses/>. */
const { html } = require('../../helpers/ezra_helper.js');
const eventController = require('../../controllers/event_controller.js');
const UiHelper = require('../../helpers/ui_helper.js');
const tagGroupValidator = require('./tag_group_validator.js');
const template = html`
<!-- FONT AWESOME STYLES -->
<link rel="preload" href="node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff2" as="font" type="font/woff2">
<link href="node_modules/@fortawesome/fontawesome-free/css/solid.min.css" rel="stylesheet" type="text/css" />
<link href="node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css" rel="stylesheet" type="text/css" />
<!-- JQUERY STYLES -->
<link id="theme-css" href="css/jquery-ui/cupertino/jquery-ui.css" media="screen" rel="stylesheet" type="text/css" />
<link href="css/main.css" media="screen" rel="stylesheet" type="text/css" />
<link href="css/tool_panel.css" media="screen" rel="stylesheet" type="text/css" />
<link href="css/mobile.css" media="screen" rel="stylesheet" type="text/css" />
<style>
#tag-list-menu.box-style {
padding: 0.7em;
padding-bottom: 0.9em;
border: 1px solid var(--border-color);
border-top: 0;
}
#tag-list-menu {
padding-top: 0.7em;
padding-bottom: 0.7em;
user-select: none;
box-sizing: border-box;
height: 3em;
}
#tag-list-menu-navigation {
display: flex;
align-items: center;
float: left;
}
#tag-group-nav-arrow {
display: inline-block;
margin-left: 0.3em;
margin-right: 0.3em;
}
.darkmode--activated #tag-list-menu {
border: 1px solid #555555;
}
#tag-list-menu a:link,
#tag-list-menu a:visited {
text-decoration: none;
color: var(--accent-color);
}
#tag-list-menu.darkmode--activated a:link,
#tag-list-menu.darkmode--activated a:visited {
color: var(--accent-color-darkmode);
}
#tag-list-menu a:hover {
text-decoration: underline;
}
#tag-group-list-link.list-tag-groups:link,
#tag-group-list-link.list-tag-groups:visited,
#tag-group-list-link.list-tag-groups:hover {
color: black;
text-decoration: none;
cursor: default;
}
.darkmode--activated #tag-group-list-link.list-tag-groups:link,
.darkmode--activated #tag-group-list-link.list-tag-groups:visited,
.darkmode--activated #tag-group-list-link.list-tag-groups:hover {
color: var(--text-color)
}
#add-tag-group-button {
float: right;
padding: 0.4em;
display: none;
cursor: pointer;
}
#new-standard-tag-button {
float: right;
margin-left: 1em;
margin-right: 0.5em;
padding: 0.2em;
padding-left: 0.4em;
padding-right: 0.4em;
cursor: pointer;
display: flex;
align-items: center;
font-size: 1em;
}
.Android #new-standard-tag-button {
height: unset !important;
font-size: 0.9em;
}
#tag-list-menu:not(.with-buttons) .add-element-button {
display: none;
}
</style>
<div id="tag-list-menu">
<div id="tag-list-menu-navigation">
<a id="tag-group-list-link" href="" i18n="tags.tag-groups"></a>
<div id="tag-group-nav-arrow">
<i class="fa-solid fa-angle-right"></i>
</div>
<span id="tag-group-label" i18n="tags.all-tags"></span>
</div>
<button id="add-tag-group-button" i18n="tags.add-tag-group" class="add-element-button fg-button ui-state-default ui-corner-all"></button>
<div id="new-standard-tag-button" i18n="[title]tags.new-tag" class="add-element-button button-small">
<i class="fas fa-plus fa-xs"></i> <i class="fas fa-tag fa-sm"></i>
</div>
</div>
`;
/**
* The TagListMenu is a web component that shows the currently selected tag groups as well as buttons for adding a tag group or adding a tag.
*
* The respective element is <tag-list-menu></tag-list-menu>.
*
* The user can switch between two views:
* - One when the list of tag groups are shown (triggers the event provided via the attribute tag-group-link-event).
* - One when a tag group gets selected (triggered by the event provided via the attribute tag-group-selection-event).
*
* The following attributes are supported:
* - tag-group-link-event: Fired when the user clicks on the "Tag Groups" link.
* - tag-group-creation-event: Fired when the user creates a new tag group.
* - tag-group-selection-event: The component will subscribe to this event and react once it gets fired.
*/
class TagListMenu extends HTMLElement {
constructor() {
super();
this.uiHelper = new UiHelper();
}
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' });
shadow.appendChild(template.content.cloneNode(true));
let rootElement = this.shadowRoot.getElementById('tag-list-menu');
platformHelper.addPlatformCssClass(rootElement);
this.getTagGroupListLink().addEventListener('click', (event) => {
event.preventDefault();
this.onTagGroupListLinkClicked();
});
this.getAddTagGroupButton().addEventListener('click', () => {
this.onAddTagGroupButtonClicked();
});
this._tagGroupLinkEvent = this.getAttribute('tag-group-link-event');
this._tagGroupCreationEvent = this.getAttribute('tag-group-creation-event');
this._tagGroupSelectionEvent = this.getAttribute('tag-group-selection-event');
if (this.getAttribute('box') == 'true') {
rootElement.classList.add('box-style');
}
if (this.getAttribute('add-element-buttons') == 'true') {
this._addElementButtons = true;
rootElement.classList.add('with-buttons');
} else {
this._addElementButtons = false;
}
eventController.subscribe(this._tagGroupSelectionEvent, (tagGroup) => {
this.selectTagGroup(tagGroup);
});
eventController.subscribe('on-locale-changed', async () => {
this.localize();
});
eventController.subscribe('on-theme-changed', (theme) => {
if (theme == 'dark') {
this.uiHelper.switchToDarkTheme(this.shadowRoot, 'tag-list-menu');
} else {
this.uiHelper.switchToRegularTheme(this.shadowRoot, 'tag-list-menu');
}
});
eventController.subscribe(this._tagGroupLinkEvent, () => {
this.hideTagGroupDisplay();
this.getTagGroupListLink().classList.add('list-tag-groups');
if (this._addElementButtons) {
this.showAddTagGroupButton();
}
this.hideAddTagButton();
});
this.localize();
this.shadowRoot.getElementById('new-standard-tag-button').addEventListener('click', async function(event) {
setTimeout(() => { tags_controller.handleNewTagButtonClick(event); }, 100);
});
this.uiHelper.configureButtonStyles(this.shadowRoot.getElementById('tag-list-menu'));
}
localize() {
try {
$(this.shadowRoot.getElementById('tag-list-menu')).localize();
} catch (e) {
console.warn("Could not localize tag-list-menu!");
}
}
onTagGroupListLinkClicked() {
eventController.publishAsync(this._tagGroupLinkEvent);
}
async onAddTagGroupButtonClicked() {
eventController.publish('on-button-clicked');
const addTagGroupTitle = i18n.t('tags.title');
const dialogBoxTemplate = html`
<div id="add-tag-group-dialog" style="padding-top: 2em;">
<label id="add-tag-group-title">${addTagGroupTitle}:</label>
<input id="tag-group-title-value" type="text" label="" style="width: 25em; border: 1px solid lightgray; border-radius: 4px;"/>
<emoji-button-trigger></emoji-button-trigger>
</div>
`;
return new Promise((resolve) => {
document.querySelector('#boxes').appendChild(dialogBoxTemplate.content);
const $dialogBox = $('#add-tag-group-dialog');
var width = 400;
var height = 200;
var draggable = true;
var position = [55, 120];
let dialogOptions = uiHelper.getDialogOptions(width, height, draggable, position);
dialogOptions.title = i18n.t('tags.add-tag-group');
dialogOptions.dialogClass = 'ezra-dialog add-tag-group-dialog';
dialogOptions.close = () => {
$dialogBox.dialog('destroy');
$dialogBox.remove();
resolve();
};
let createTagGroup = () => {
let tagGroupTitle = document.getElementById('tag-group-title-value').value;
eventController.publishAsync(this._tagGroupCreationEvent, tagGroupTitle);
$dialogBox.dialog('close');
};
dialogOptions.buttons = {};
dialogOptions.buttons[i18n.t('general.cancel')] = function() {
$dialogBox.dialog('close');
};
dialogOptions.buttons[i18n.t('tags.create-tag-group')] = {
id: 'create-tag-group-button',
text: i18n.t('tags.create-tag-group'),
click: () => {
createTagGroup();
}
};
document.getElementById('tag-group-title-value').addEventListener('keyup', async (event) => {
await tagGroupValidator.validateNewTagGroupTitle('tag-group-title-value', 'create-tag-group-button');
if (event.key == 'Enter') {
createTagGroup();
}
});
$dialogBox.dialog(dialogOptions);
uiHelper.fixDialogCloseIconOnAndroid('add-tag-group-dialog');
tagGroupValidator.validateNewTagGroupTitle('tag-group-title-value', 'create-tag-group-button');
document.getElementById('tag-group-title-value').focus();
});
}
selectTagGroup(tagGroup) {
if (tagGroup != null) {
this.getTagGroupListLink().classList.remove('list-tag-groups');
this.getTagGroupLabel().innerText = tagGroup.title;
this.showTagGroupDisplay();
this.hideAddTagGroupButton();
if (this._addElementButtons) {
this.showAddTagButton();
}
}
}
hideTagGroupDisplay() {
this.getTagGroupNavArrow().style.display = 'none';
this.getTagGroupLabel().style.display = 'none';
}
showTagGroupDisplay() {
this.getTagGroupNavArrow().style.display = '';
this.getTagGroupLabel().style.display = '';
}
showAddTagGroupButton() {
this.getAddTagGroupButton().style.display = 'block';
}
hideAddTagGroupButton() {
this.getAddTagGroupButton().style.display = 'none';
}
showAddTagButton() {
this.getAddTagButton().style.display = 'flex';
}
hideAddTagButton() {
this.getAddTagButton().style.display = 'none';
}
getAddTagButton() {
return this.shadowRoot.getElementById('new-standard-tag-button');
}
getTagGroupListLink() {
return this.shadowRoot.getElementById('tag-group-list-link');
}
getTagGroupLabel() {
return this.shadowRoot.getElementById('tag-group-label');
}
getTagGroupNavArrow() {
return this.shadowRoot.getElementById('tag-group-nav-arrow');
}
getAddTagGroupButton() {
return this.shadowRoot.getElementById('add-tag-group-button');
}
}
customElements.define('tag-list-menu', TagListMenu);
module.exports = TagListMenu;
Source