/** * 3D Foundation Project * Copyright 2025 Smithsonian Institution * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { customElement, html, property } from "@ff/ui/CustomElement"; import sanitizeHtml from 'sanitize-html'; import List from "@ff/ui/List"; import MessageBox from "@ff/ui/MessageBox"; import { ILineEditChangeEvent } from "@ff/ui/LineEdit"; import Article from "../../models/Article"; import CVArticlesTask from "../../components/CVArticlesTask"; import { TaskView } from "../../components/CVTask"; import { DEFAULT_LANGUAGE, ELanguageType } from "client/schema/common"; //////////////////////////////////////////////////////////////////////////////// @customElement("sv-articles-task-view") export default class ArticlesTaskView extends TaskView { protected connected() { super.connected(); this.task.outs.article.on("value", this.onArticleChange, this); this.activeDocument.setup.language.ins.primarySceneLanguage.on("value", this.onUpdate, this); } protected disconnected() { this.task.outs.article.off("value", this.onArticleChange, this); this.activeDocument.setup.language.ins.primarySceneLanguage.off("value", this.onUpdate, this); super.disconnected(); } protected render() { if(!this.activeDocument) { return; } const task = this.task; const articles = task.articles; const activeArticle = task.activeArticle; const languageManager = this.activeDocument.setup.language; const activeLanguage = ELanguageType[languageManager.ins.activeLanguage.value]; const primarySceneLanguage = ELanguageType[languageManager.ins.primarySceneLanguage.value]; if (!articles) { return html`
${languageManager.getUILocalizedString("Please select a scene or model node to edit its articles.")}
`; } const detailView = activeArticle ? html`
Title
Tags
Lead
` : null; const uri = activeArticle ? activeArticle.uri : null; // Trying article UI without edit button // return html`
${languageManager.getUILocalizedString("Default:") + " " + primarySceneLanguage}
${languageManager.getUILocalizedString("Active:") + " " + activeLanguage}
${detailView}
` } protected onClickCreate() { this.task.ins.create.set(); } protected onClickEdit() { this.task.ins.edit.set(); } protected onClickDelete() { MessageBox.show("Delete Article", "Are you sure?", "warning", "ok-cancel").then(result => { if (result.ok) { this.task.ins.delete.set(); } }); } protected onClickUp() { this.task.ins.moveArticleUp.set(); } protected onClickDown() { this.task.ins.moveArticleDown.set(); } protected onTextEdit(event: ILineEditChangeEvent) { const task = this.task; const target = event.target; const text = event.detail.text; if (target.name === "lead") { task.ins.lead.setValue(text); } else if (target.name === "tags") { task.ins.tags.setValue(text); } else if (target.name === "title") { task.ins.title.setValue(sanitizeHtml(text, { allowedTags: [ 'i' ], } )); } } protected onSelectArticle(event: ISelectArticleEvent) { const article = event.detail.article; this.task.reader.ins.articleId.setValue(article ? article.id : ""); } protected onEditArticle(event: IEditArticleEvent) { this.task.ins.edit.set(); } protected onArticleChange() { this.onUpdate(); //this.task.ins.edit.set(); } } //////////////////////////////////////////////////////////////////////////////// export interface ISelectArticleEvent extends CustomEvent { target: ArticleList; detail: { article: Article; } } export interface IEditArticleEvent extends CustomEvent { target: ArticleList; detail: { article: Article; } } @customElement("sv-article-list") export class ArticleList extends List
{ @property({ attribute: false }) selectedItem: Article = null; @property({type: ELanguageType}) activeLanguage: ELanguageType = ELanguageType[DEFAULT_LANGUAGE]; @property({type: ELanguageType}) primarySceneLanguage: ELanguageType = ELanguageType[DEFAULT_LANGUAGE]; protected firstConnected() { super.firstConnected(); this.classList.add("sv-document-list"); } protected renderItem(item: Article) { const primaryTitle = item.titleIn(this.primarySceneLanguage); const activeTitle = item.titleIn(this.activeLanguage); const missingTitle = html `Missing content` return html`
${ primaryTitle? primaryTitle : missingTitle}
${activeTitle ? activeTitle : missingTitle}
` } protected isItemSelected(item: Article) { return item === this.selectedItem; } protected onClickItem(event: MouseEvent, item: Article) { this.dispatchEvent(new CustomEvent("select", { detail: { article: item } })); } protected onDblClickItem(event: MouseEvent, item: Article, index: number) { this.dispatchEvent(new CustomEvent("edit", { detail: { article: item } })); } protected onClickEmpty(event: MouseEvent) { this.dispatchEvent(new CustomEvent("select", { detail: { article: null } })); } }