/**
* Silex, live web creation
* http://projects.silexlabs.org/?/silex/
*
* Copyright (c) 2012 Silex Labs
* http://www.silexlabs.org/
*
* Silex is available under the GPL license
* http://www.silexlabs.org/silex/silex-licensing/
*/
/**
* @fileoverview
* This class represents a the page model of the html file being edited
* It has methods to manipulate the pages
*
*/
import { Constants } from '../../Constants';
import { Model, View } from '../types';
import { SilexNotification } from '../utils/notification';
/**
* structure to store all of a page data
* @struct
*/
export class PageData {
name: string = '';
displayName: string = '';
linkName: string = '';
idx: number = -1;
}
/**
* @param model model class which holds the other models
* @param view view class which holds the other views
*/
export class Page {
constructor(public model: Model, public view: View) {}
/**
* retrieve the first parent which is visible only on some pages
* @return null or the element or one of its parents which has the css class
* silex.model.Constants.PAGED_CLASS_NAME
*/
getParentPage(element: HTMLElement): HTMLElement {
let parent = element.parentElement as HTMLElement;
while (parent && !parent.classList.contains(Constants.PAGED_CLASS_NAME)) {
parent = parent.parentElement as HTMLElement;
}
return (parent as HTMLElement | null);
}
/**
* get the pages from the dom
* @return an array of the page names I have found in the DOM
*/
getPages(): string[] {
// retrieve all page names from the head section
const pages = [];
const bodyElement = this.model.body.getBodyElement();
if (!bodyElement) {
console.warn('Can not get pages, the body element is null');
return [];
}
const elements = bodyElement.querySelectorAll(`a[data-silex-type="${Constants.TYPE_PAGE}"]`);
elements.forEach((element) => {
pages.push(element.getAttribute('id'));
});
return pages;
}
/**
* get the currently opened page from the dom
* @return name of the page currently opened
*/
getCurrentPage(): string {
// tslint:disable:no-string-literal
if (!this.model.file.getContentWindow()['jQuery']) {
throw new Error('JQuery not loaded in the opened website');
}
const bodyElement = this.model.body.getBodyElement();
let pageName = null;
try {
if (this.model.file.getContentWindow()['jQuery'](bodyElement).pageable) {
pageName = this.model.file.getContentWindow()['jQuery'](bodyElement).pageable('option', 'currentPage');
}
} catch (e) {
// there was a problem in the pageable plugin, return the first page
console.warn(
`warning, could not retrieve the current page, I will return the first page (${
this.getPages()})`);
pageName = this.getPages()[0];
}
return pageName;
}
/**
* refresh the view
*/
refreshView() {
const pages = this.getPages();
const currentPage = this.getCurrentPage();
const selectedElements = this.model.body.getSelection();
const states = this.view.stageWrapper.getSelection();
this.view.contextMenu.redraw(selectedElements, pages, currentPage);
this.view.pageTool.redraw(selectedElements, pages, currentPage);
this.view.propertyTool.redraw(states, pages, currentPage);
this.view.textFormatBar.redraw(selectedElements, pages, currentPage);
this.view.stageWrapper.redraw();
}
/**
* open the page
* this is a static method, a helper
* @param pageName name of the page to open
*/
setCurrentPage(pageName: string) {
// tslint:disable:no-string-literal
const bodyElement = this.model.body.getBodyElement();
if (this.model.file.getContentWindow()['jQuery'](bodyElement).pageable) {
this.model.file.getContentWindow()['jQuery'](bodyElement).pageable({
currentPage: pageName,
});
}
this.view.stageWrapper.reset();
}
/**
* get a page from the dom by its name
* @param pageName a page name
* @return the page corresponding to the given page name
*/
getDisplayName(pageName: string): string {
let displayName = '';
const pageElement = this.model.file.getContentDocument().getElementById(pageName);
if (pageElement) {
displayName = pageElement.innerHTML;
}
return displayName;
}
/**
* remove a page from the dom
* elements which are only in this page should be deleted
*/
removePage(pageName: string) {
let pages = this.getPages();
const pageDisplayName = this.getDisplayName(pageName);
if (pages.length < 2) {
SilexNotification.notifyError(
'I could not delete this page because it is the only page!');
} else {
// remove the DOM element
const pageElements = Array.from(this.model.body.getBodyElement().querySelectorAll(`a[data-silex-type="${Constants.TYPE_PAGE}"]`));
pageElements.forEach((element) => {
if (element.getAttribute('id') === pageName) {
element.parentElement.removeChild(element);
}
});
// remove the links to this page
const linkElements = Array.from(this.model.body.getBodyElement().querySelectorAll('*[data-silex-href="#!' + pageName + '"]'));
linkElements.forEach((element) => {
element.removeAttribute('data-silex-href');
});
// check elements which were only visible on this page
// and returns them in this case
const elementsOnlyOnThisPage = [];
const elementsOfThisPage = Array.from(this.model.body.getBodyElement().getElementsByClassName(pageName));
elementsOfThisPage.forEach((element: HTMLElement) => {
element.remove();
const pagesOfElement = this.getPagesForElement(element);
if (pagesOfElement.length <= 0) {
elementsOnlyOnThisPage.push(element);
}
});
// update the page list
pages = this.getPages();
// open default/first page
this.setCurrentPage(pages[0]);
// handle elements which should be deleted
if (elementsOnlyOnThisPage.length > 0) {
SilexNotification.confirm('Delete elements' , `
${elementsOnlyOnThisPage.length} elements were only visible on this page (${pageDisplayName}).