CCM NG: Code cleanup

git-svn-id: https://svn.libreccm.org/ccm/ccm_ng@5227 8810af33-2d31-482b-a856-94f89814c4df
pull/2/head
jensp 2018-02-01 15:08:42 +00:00
parent 665752dade
commit 284803b6ea
2 changed files with 211 additions and 119 deletions

View File

@ -68,6 +68,14 @@
padding: 0.5em 0.3em; padding: 0.5em 0.3em;
} }
.ccm-editor-error {
color: #f00;
border: 2px solid #ff0;
border-radius: 0.4em;
}
.ccm-editor-hidden { .ccm-editor-hidden {
display: none; display: none;
} }
@ -90,7 +98,7 @@
width: 70em; width: 70em;
height: 40em; height: 40em;
overflow: scroll; overflow: auto;
} }
.ccm-editor-selectdialog h1 { .ccm-editor-selectdialog h1 {

View File

@ -2,7 +2,7 @@ import { CCMEditor, CCMEditorCommand, CCMEditorCommandType } from "./ccm-editor"
export class InsertInternalLinkCommand extends CCMEditorCommand { export class InsertInternalLinkCommand extends CCMEditorCommand {
private button: Element; private button: HTMLElement;
constructor(editor: CCMEditor, settings: any) { constructor(editor: CCMEditor, settings: any) {
super(editor, settings); super(editor, settings);
@ -10,17 +10,19 @@ export class InsertInternalLinkCommand extends CCMEditorCommand {
this.button = this.fragment this.button = this.fragment
.appendChild(document.createElement("button")); .appendChild(document.createElement("button"));
const icon: Element = this.button const icon: HTMLElement = this.button
.appendChild(document.createElement("i")); .appendChild(document.createElement("i"));
icon.className = "fa fa-link"; icon.className = "fa fa-link";
const text: Element = this.button const text: HTMLElement = this.button
.appendChild(document.createElement("span")); .appendChild(document.createElement("span"));
this.button this.button
.setAttribute("title", "Insert a link to a ContentItem"); .setAttribute("title", "Insert a link to a ContentItem");
text.textContent = "Create internal link"; text.textContent = "Create internal link";
text.className = "ccm-editor-accessibility"; text.className = "ccm-editor-accessibility";
const command = this;
this.button.addEventListener("click", function(event){ this.button.addEventListener("click", function(event){
event.preventDefault(); event.preventDefault();
@ -29,10 +31,10 @@ export class InsertInternalLinkCommand extends CCMEditorCommand {
const dialogFragment: DocumentFragment = document const dialogFragment: DocumentFragment = document
.createDocumentFragment(); .createDocumentFragment();
const dialogElem: Element = dialogFragment const dialogElem: HTMLElement = dialogFragment
.appendChild(document.createElement("div")); .appendChild(document.createElement("div"));
dialogElem.className = "ccm-editor-selectdialog"; dialogElem.className = "ccm-editor-selectdialog";
const dialogTitleElem: Element = dialogElem const dialogTitleElem: HTMLElement = dialogElem
.appendChild(document.createElement("h1")); .appendChild(document.createElement("h1"));
dialogTitleElem.textContent = "Insert link to a Content Item"; dialogTitleElem.textContent = "Insert link to a Content Item";
@ -49,9 +51,9 @@ export class InsertInternalLinkCommand extends CCMEditorCommand {
return false; return false;
}); });
const filterForm: Element = dialogElem const filterForm: HTMLElement = dialogElem
.appendChild(document.createElement("div")); .appendChild(document.createElement("div"));
const contentSectionSelectLabel: Element = filterForm const contentSectionSelectLabel: HTMLElement = filterForm
.appendChild(document.createElement("label")); .appendChild(document.createElement("label"));
contentSectionSelectLabel contentSectionSelectLabel
.setAttribute("for", "ccm-editor-contentsection-select"); .setAttribute("for", "ccm-editor-contentsection-select");
@ -60,7 +62,7 @@ export class InsertInternalLinkCommand extends CCMEditorCommand {
.appendChild(document.createElement("select")); .appendChild(document.createElement("select"));
contentSectionSelect contentSectionSelect
.setAttribute("id", "ccm-editor-contentsection-select"); .setAttribute("id", "ccm-editor-contentsection-select");
const filterInputLabel: Element = filterForm const filterInputLabel: HTMLElement = filterForm
.appendChild(document.createElement("label")); .appendChild(document.createElement("label"));
filterInputLabel.setAttribute("id", "ccm-editor-assetfilter"); filterInputLabel.setAttribute("id", "ccm-editor-assetfilter");
filterInputLabel.textContent = "Filter items"; filterInputLabel.textContent = "Filter items";
@ -68,14 +70,14 @@ export class InsertInternalLinkCommand extends CCMEditorCommand {
.appendChild(document.createElement("input")); .appendChild(document.createElement("input"));
filterInput.setAttribute("id", "ccm-editor-assetfilter"); filterInput.setAttribute("id", "ccm-editor-assetfilter");
filterInput.setAttribute("type", "text"); filterInput.setAttribute("type", "text");
const applyFiltersButton: Element = filterForm const applyFiltersButton: HTMLElement = filterForm
.appendChild(document.createElement("button")); .appendChild(document.createElement("button"));
applyFiltersButton.textContent = "Clear filters"; applyFiltersButton.textContent = "Apply filters";
applyFiltersButton.addEventListener("click", function(event){ applyFiltersButton.addEventListener("click", function(event){
event.preventDefault(); event.preventDefault();
return false; return false;
}); });
const clearFiltersButton: Element = filterForm const clearFiltersButton: HTMLElement = filterForm
.appendChild(document.createElement("button")); .appendChild(document.createElement("button"));
clearFiltersButton.textContent = "Clear filters"; clearFiltersButton.textContent = "Clear filters";
clearFiltersButton.addEventListener("click", function(event){ clearFiltersButton.addEventListener("click", function(event){
@ -84,121 +86,84 @@ export class InsertInternalLinkCommand extends CCMEditorCommand {
return false; return false;
}); });
const table: Element = dialogElem const table: HTMLElement = dialogElem
.appendChild(document.createElement("table")); .appendChild(document.createElement("table"));
const tableHead: Element = table const tableHead: HTMLElement = table
.appendChild(document.createElement("thead")); .appendChild(document.createElement("thead"));
const headerRow: Element = tableHead const headerRow: HTMLElement = tableHead
.appendChild(document.createElement("tr")); .appendChild(document.createElement("tr"));
const titleColHeader: Element = headerRow const titleColHeader: HTMLElement = headerRow
.appendChild(document.createElement("th")); .appendChild(document.createElement("th"));
const typeColHeader: Element = headerRow const typeColHeader: HTMLElement = headerRow
.appendChild(document.createElement("th")); .appendChild(document.createElement("th"));
const placeColHeader: Element = headerRow const placeColHeader: HTMLElement = headerRow
.appendChild(document.createElement("th")); .appendChild(document.createElement("th"));
titleColHeader.textContent = "Title"; titleColHeader.textContent = "Title";
typeColHeader.textContent = "Type"; typeColHeader.textContent = "Type";
placeColHeader.textContent = "Place"; placeColHeader.textContent = "Place";
const tableBody: Element = table const tableBody: HTMLElement = table
.appendChild(document.createElement("tbody")); .appendChild(document.createElement("tbody"));
const contextPrefix = editor.getDataAttribute("context-prefix"); const contextPrefix = editor.getDataAttribute("context-prefix");
// Get content sections // Get content sections
const currentSection = editor const currentSection = editor
.getDataAttribute("current-contentsection-primaryurl"); .getDataAttribute("current-contentsection-primaryurl");
const sectionsUrl = contextPrefix + "/content-sections/"; const sectionsUrl = `${contextPrefix}/content-sections/`;
const sectionsRequest = new XMLHttpRequest(); fetch(sectionsUrl, { credentials: "include" }).then((response) => {
sectionsRequest.open("GET", sectionsUrl); if (response.ok) {
sectionsRequest.withCredentials = true; response.json().then((data) => {
sectionsRequest.addEventListener("load", function(event){ for (const section of data) {
if (sectionsRequest.status >= 200 const option: HTMLOptionElement
&& sectionsRequest.status <= 300) { = contentSectionSelect
.appendChild(document
const sections = JSON.parse(sectionsRequest.responseText); .createElement("option"));
for(let i = 0; i < sections.length; ++i) { option.value = section.primaryUrl;
const section = sections[i]; option.textContent = section.primaryUrl;
const option: Element = contentSectionSelect if (section.primaryUrl === currentSection) {
.appendChild(document.createElement("option")); option.selected = true;
option.setAttribute("value", section["primaryUrl"]);
option.textContent = section["primaryUrl"];
if (section["primaryUrl"] === currentSection) {
option.setAttribute("selected", "selected");
}
} }
} }
}); });
sectionsRequest.send();
console.log("Current sections is \"" + currentSection + "\"");
// Get items
let itemsUrl = contextPrefix
+ "/content-sections";
if (!(new RegExp("^/.*").test(currentSection))) {
console.log("Current sections does not start with an \"/\", adding one...");
itemsUrl += "/";
}
itemsUrl += currentSection;
if (!(new RegExp(".*/$").test(currentSection))) {
console.log("Current sections does not end with an \"/\", adding one...");
itemsUrl += "/";
}
itemsUrl += "items";
if (filterInput.value !== null && filterInput.value.length > 0) {
itemsUrl + "?query=" + filterInput.value;
}
const itemsRequest = new XMLHttpRequest();
itemsRequest.open("GET", itemsUrl);
itemsRequest.withCredentials = true;
itemsRequest.addEventListener("load", function(event){
if (itemsRequest.status >= 200 && itemsRequest.status <= 300) {
const items = JSON.parse(itemsRequest.responseText);
for(let i = 0; i < items.length; ++i) {
const item = items[i];
const row: Element = tableBody
.appendChild(document.createElement("tr"));
const dataTitle = row
.appendChild(document.createElement("td"));
const dataType = row
.appendChild(document.createElement("td"));
const dataPlace =
row.appendChild(document.createElement("td"));
const selectItemButton = dataTitle
.appendChild(document.createElement("button"));
if (item["title"] === null
|| item["title"].length <= 0) {
selectItemButton.textContent = item["name"];
} else { } else {
selectItemButton.textContent = item["title"]; const errorMsgElement: HTMLElement = dialogElem
.appendChild(document.createElement("div"));
errorMsgElement.classList.add("ccm-editor-error");
errorMsgElement.textContent = `Failed to fetch available
content sections from "${sectionsUrl}". Status: ${response.status}.
Status text: ${response.statusText}`;
} }
selectItemButton },
.addEventListener("click", function(event) { (failure) => {
const errorMsgElement: HTMLElement = dialogElem
.appendChild(document.createElement("div"));
errorMsgElement.classList.add("ccm-editor-error");
errorMsgElement.textContent = `Failed to fetch available
content sections from "${sectionsUrl}". Failure: ${failure}`;
});
contentSectionSelect.addEventListener("click", (event) => {
command.fetchItems(dialogElem,
contentSectionSelect.value,
filterInput.value,
tableBody,
currentRange);
});
applyFiltersButton.addEventListener("click", (event) => {
event.preventDefault(); event.preventDefault();
const bodyElem = document command.fetchItems(dialogElem,
.getElementsByTagName("body") contentSectionSelect.value,
.item(0); filterInput.value,
bodyElem.removeChild(dialogElem); tableBody,
document.getSelection().removeAllRanges(); currentRange);
document.getSelection().addRange(currentRange);
document.execCommand("createLink",
false,
contextPrefix
+ "/redirect/?oid="
+ item["itemId"]);
return false;
}); });
dataType.textContent = item["typeLabel"]; command.fetchItems(dialogElem,
dataType.textContent = item["place"]; currentSection,
} filterInput.value,
} tableBody,
}); currentRange);
itemsRequest.send();
const bodyElem = document.getElementsByTagName("body").item(0); const bodyElem = document.getElementsByTagName("body").item(0);
bodyElem.appendChild(dialogFragment); bodyElem.appendChild(dialogFragment);
@ -207,6 +172,109 @@ export class InsertInternalLinkCommand extends CCMEditorCommand {
}); });
} }
private fetchItems(dialogElem: HTMLElement,
contentSection: string,
query: string,
itemsTableBodyElem: HTMLElement,
currentRange: Range) {
const itemsUrl = this.generateItemsUrl(contentSection, query);
fetch(itemsUrl, { credentials: "include" }).then((response) => {
if (response.ok) {
itemsTableBodyElem.innerHTML = "";
response.json().then((data) => {
for (const item of data) {
const row: HTMLElement = itemsTableBodyElem
.appendChild(document.createElement("tr"));
const dataTitle = row
.appendChild(document.createElement("td"));
const dataType = row
.appendChild(document.createElement("td"));
const dataPlace = row
.appendChild(document.createElement("td"));
const selectItemButton: HTMLButtonElement = dataTitle
.appendChild(document.createElement("button"));
if (item.title === null || item.title.length <= 0) {
selectItemButton.textContent = item.name;
} else {
selectItemButton.textContent = item.title;
}
selectItemButton.addEventListener("click", (event) => {
event.preventDefault();
const bodyElem = document
.getElementsByTagName("body")
.item[0];
bodyElem.removeChild(dialogElem);
document.getSelection().removeAllRanges();
document.getSelection().addRange(currentRange);
const contextPrefix = this.editor
.getDataAttribute("context-prefix");
document.execCommand(
"createLink",
false,
`${contextPrefix}/redirect/?oid${item.itemId}`);
});
dataType.textContent = item.typeLabel;
dataPlace.textContent = item.place;
}
});
} else {
const dialogElem: HTMLElement = itemsTableBodyElem
.parentNode.parentNode as HTMLElement;
const errorMsgElement: HTMLElement = dialogElem
.insertBefore(document.createElement("div"),
itemsTableBodyElem.parentNode);
errorMsgElement.classList.add("ccm-editor-error");
errorMsgElement.textContent = `Failed to fetch items for
content section "${contentSection}" and query "${query}"
from "${itemsUrl}".
Status code: ${response.status}.
Status text: ${response.statusText}`;
}
},
(failure) => {
const dialogElem: HTMLElement = itemsTableBodyElem
.parentNode.parentNode as HTMLElement;
const errorMsgElement: HTMLElement = dialogElem
.insertBefore(document.createElement("div"),
itemsTableBodyElem.parentNode);
errorMsgElement.classList.add("ccm-editor-error");
errorMsgElement.textContent = `Failed to fetch items for
content section "${contentSection}" and query "${query}"
from "${itemsUrl}".
Failure message: ${failure}.`;
});
}
private generateItemsUrl(contentSection: string, query?: string) {
const contextPrefix = this.editor.getDataAttribute("context-prefix");
let itemsUrl = `${contextPrefix}/content-sections`;
if (!(new RegExp("^/.*").test(contentSection))) {
itemsUrl = `${itemsUrl}/`;
}
itemsUrl = `${itemsUrl}${contentSection}`;
if (!(new RegExp(".*/$").test(contentSection))) {
itemsUrl = `${itemsUrl}/`;
}
itemsUrl = `${itemsUrl}items`;
if (query) {
itemsUrl = `${itemsUrl}?query=${query}`;
}
return itemsUrl;
}
getCommandType(): CCMEditorCommandType { getCommandType(): CCMEditorCommandType {
return CCMEditorCommandType.INSERT_INLINE; return CCMEditorCommandType.INSERT_INLINE;
} }
@ -243,11 +311,11 @@ export class InsertMediaAssetCommand extends CCMEditorCommand {
this.button = this.fragment this.button = this.fragment
.appendChild(document.createElement("button")); .appendChild(document.createElement("button"));
const icon: Element = this.button const icon: HTMLElement = this.button
.appendChild(document.createElement("i")); .appendChild(document.createElement("i"));
icon.className = "fa fa-file-image-o"; icon.className = "fa fa-file-image-o";
const text: Element = this.button const text: HTMLElement = this.button
.appendChild(document.createElement("span")); .appendChild(document.createElement("span"));
this.button.setAttribute("title", this.button.setAttribute("title",
"Insert media content (image, audio, video)"); "Insert media content (image, audio, video)");
@ -268,7 +336,7 @@ export class InsertMediaAssetCommand extends CCMEditorCommand {
const dialogElem: HTMLElement = dialogFragment const dialogElem: HTMLElement = dialogFragment
.appendChild(document.createElement("div")); .appendChild(document.createElement("div"));
dialogElem.className = "ccm-editor-selectdialog"; dialogElem.className = "ccm-editor-selectdialog";
const dialogTitleElem: Element = dialogElem const dialogTitleElem: HTMLElement = dialogElem
.appendChild(document.createElement("h1")); .appendChild(document.createElement("h1"));
dialogTitleElem.textContent = "Insert media"; dialogTitleElem.textContent = "Insert media";
@ -331,7 +399,7 @@ export class InsertMediaAssetCommand extends CCMEditorCommand {
option.textContent = typeOption.label option.textContent = typeOption.label
typeSelect.appendChild(option); typeSelect.appendChild(option);
} }
const filterInputLabel: Element = filterForm const filterInputLabel: HTMLElement = filterForm
.appendChild(document.createElement("label")); .appendChild(document.createElement("label"));
filterInputLabel.setAttribute("id", "ccm-editor-assetfilter"); filterInputLabel.setAttribute("id", "ccm-editor-assetfilter");
filterInputLabel.textContent = "Filter items"; filterInputLabel.textContent = "Filter items";
@ -339,11 +407,11 @@ export class InsertMediaAssetCommand extends CCMEditorCommand {
.appendChild(document.createElement("input")); .appendChild(document.createElement("input"));
filterInput.setAttribute("id", "ccm-editor-assetfilter"); filterInput.setAttribute("id", "ccm-editor-assetfilter");
filterInput.setAttribute("type", "text"); filterInput.setAttribute("type", "text");
const applyFiltersButton: Element = filterForm const applyFiltersButton: HTMLElement = filterForm
.appendChild(document.createElement("button")); .appendChild(document.createElement("button"));
applyFiltersButton.textContent = "Clear filters"; applyFiltersButton.textContent = "Clear filters";
const clearFiltersButton: Element = filterForm const clearFiltersButton: HTMLElement = filterForm
.appendChild(document.createElement("button")); .appendChild(document.createElement("button"));
clearFiltersButton.textContent = "Clear filters"; clearFiltersButton.textContent = "Clear filters";
clearFiltersButton.addEventListener("click", function(event){ clearFiltersButton.addEventListener("click", function(event){
@ -359,9 +427,9 @@ export class InsertMediaAssetCommand extends CCMEditorCommand {
.appendChild(document.createElement("tr")); .appendChild(document.createElement("tr"));
const titleColHeader: HTMLElement = headerRow const titleColHeader: HTMLElement = headerRow
.appendChild(document.createElement("th")); .appendChild(document.createElement("th"));
const typeColHeader: Element = headerRow const typeColHeader: HTMLElement = headerRow
.appendChild(document.createElement("th")); .appendChild(document.createElement("th"));
const placeColHeader: Element = headerRow const placeColHeader: HTMLElement = headerRow
.appendChild(document.createElement("th")); .appendChild(document.createElement("th"));
titleColHeader.textContent = "Title"; titleColHeader.textContent = "Title";
typeColHeader.textContent = "Type"; typeColHeader.textContent = "Type";
@ -379,16 +447,32 @@ export class InsertMediaAssetCommand extends CCMEditorCommand {
if (response.ok) { if (response.ok) {
response.json().then((data) => { response.json().then((data) => {
for(const section of data) { for(const section of data) {
const option: HTMLElement = contentSectionSelect const option: HTMLOptionElement
.appendChild(document.createElement("option")); = contentSectionSelect
option.setAttribute("value", section.primaryUrl); .appendChild(document
.createElement("option"));
option.value = section.primaryUrl;
option.textContent = section.primaryUrl; option.textContent = section.primaryUrl;
if (section.primaryUrl === currentSection) { if (section.primaryUrl === currentSection) {
option.setAttribute("selected", "selected"); option.selected = true;
} }
} }
}); });
} else {
const errorMsgElement: HTMLElement = dialogElem
.appendChild(document.createElement("div"));
errorMsgElement.classList.add("ccm-editor-error");
errorMsgElement.textContent = `Failed to fetch available
content sections. Status: ${response.status}.
Status text: ${response.statusText}`;
} }
},
(failure) => {
const errorMsgElement: HTMLElement = dialogElem
.appendChild(document.createElement("div"));
errorMsgElement.classList.add("ccm-editor-error");
errorMsgElement.textContent = `Failed to fetch available
content sections. Failure: ${failure}`;
}); });
contentSectionSelect.addEventListener("change", (event) => { contentSectionSelect.addEventListener("change", (event) => {