silex-website-builder-goodevent
Version:
Free and easy website builder for everyone.
331 lines (317 loc) • 11 kB
text/typescript
/**
* 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
* the Silex menu on the left
* based on closure menu class
*
*/
import { Constants } from '../../Constants';
import { Config } from '../ClientConfig';
import { Controller, Model } from '../types';
import { Keyboard } from '../utils/Keyboard';
/**
* @param element container to render the UI
* @param model model class which holds
* the model instances - views use it for read operation only
* @param controller structure which holds the controller instances
*/
export class Menu {
static SUB_MENU_CLASSES = [
'page-tool-visible', 'about-menu-visible', 'file-menu-visible',
'code-menu-visible', 'add-menu-visible',
];
constructor(public element: HTMLElement, public model: Model, public controller: Controller) {}
elFromCompDef(comp, id) {
// build the dom elements for each comp by category
const iconClassName = comp.faIconClass || 'prodotype-icon';
const baseElementType = comp.baseElement || 'html';
const el = document.createElement('div');
el.classList.add('sub-menu-item');
el.title = `${comp.name}`;
el.setAttribute('data-menu-action', 'insert.' + baseElementType);
el.setAttribute('data-comp-id', id);
el.innerHTML = `
<span class="icon fa-inverse ${iconClassName}"></span>
${comp.name}
`;
return el;
}
/**
* create the menu with closure API
* called by the app constructor
*/
buildUi() {
const keyboard = new Keyboard(document);
// Shortcuts
Config.shortcuts.forEach((shortcut) => {
keyboard.addShortcut(shortcut, (e) => this.onMenuEvent(shortcut.id));
});
// components
this.model.component.ready(() => {
// **
const list = this.element.querySelector('.add-menu-container');
const componentsDef = this.model.component.getComponentsDef(Constants.COMPONENT_TYPE);
// build a list of component categories
const elements = {};
for (const id in componentsDef) {
const comp = componentsDef[id];
if (comp.isPrivate !== true) {
if (!elements[comp.category]) {
elements[comp.category] = [this.elFromCompDef(comp, id)];
} else {
elements[comp.category].push(this.elFromCompDef(comp, id));
}
}
}
for (const id in elements) {
// create a label for the category
const label = document.createElement('div');
label.classList.add('label');
label.innerHTML = id;
list.appendChild(label);
// attach each comp's element
elements[id].forEach((el) => list.appendChild(el));
}
});
// event handling
this.element.onclick = (e) => {
const action = (e.target as HTMLElement).getAttribute('data-menu-action') ||
(e.target as HTMLElement).parentElement.getAttribute('data-menu-action');
const componentId = (e.target as HTMLElement).getAttribute('data-comp-id') ||
(e.target as HTMLElement).parentElement.getAttribute('data-comp-id');
this.onMenuEvent(action, componentId);
if ((e.target as HTMLElement).parentElement &&
!(e.target as HTMLElement).parentElement.classList.contains('menu-container') &&
!(e.target as HTMLElement).parentElement.classList.contains('silex-menu')) {
// not a first level menu => close sub menus
this.closeAllSubMenu();
}
};
}
/**
* redraw the menu
* @param selectedElements the elements currently selected
* @param pageNames the names of the pages which appear in the current HTML
* file
* @param currentPageName the name of the current page
*/
redraw() {
if (this.controller.editMenuController.hasUndo()) {
this.element.querySelector('.undo').classList.remove('off');
} else {
this.element.querySelector('.undo').classList.add('off');
}
if (this.controller.editMenuController.hasRedo()) {
this.element.querySelector('.redo').classList.remove('off');
} else {
this.element.querySelector('.redo').classList.add('off');
}
}
closeAllSubMenu() {
Menu.SUB_MENU_CLASSES.forEach((className) => {
document.body.classList.remove(className);
});
}
toggleSubMenu(classNameToToggle) {
Menu.SUB_MENU_CLASSES.forEach((className) => {
if (classNameToToggle === className) {
document.body.classList.toggle(className);
} else {
document.body.classList.remove(className);
}
});
}
/**
* handles click events
* calls onStatus to notify the controller
* @param opt_componentName the component type if it is a component
* TODO: use redux for this
*/
onMenuEvent(type: string, opt_componentName?: string) {
let added = null;
switch (type) {
case 'show.pages':
this.toggleSubMenu('page-tool-visible');
break;
case 'show.about.menu':
this.toggleSubMenu('about-menu-visible');
break;
case 'show.file.menu':
this.toggleSubMenu('file-menu-visible');
break;
case 'show.code.menu':
this.toggleSubMenu('code-menu-visible');
break;
case 'show.add.menu':
this.toggleSubMenu('add-menu-visible');
break;
case 'file.new':
this.controller.fileMenuController.newFile();
break;
case 'file.saveas':
this.controller.fileMenuController.save();
break;
case 'file.publish.settings':
this.controller.fileMenuController.view.settingsDialog.open();
this.controller.fileMenuController.view.workspace.redraw(
this.controller.fileMenuController.view);
break;
case 'file.fonts':
this.controller.fileMenuController.view.settingsDialog.open(
null, 'fonts-pane');
this.controller.fileMenuController.view.workspace.redraw(
this.controller.fileMenuController.view);
break;
case 'file.publish':
this.controller.fileMenuController.publish();
break;
case 'file.save':
this.controller.fileMenuController.save(
this.controller.fileMenuController.model.file.getFileInfo());
break;
case 'file.open':
this.controller.fileMenuController.openFile();
break;
case 'view.file':
this.controller.viewMenuController.preview();
break;
case 'view.file.responsize':
this.controller.viewMenuController.previewResponsize();
break;
case 'view.open.fileExplorer':
this.controller.viewMenuController.view.fileExplorer.openFile();
break;
case 'view.open.cssEditor':
this.controller.viewMenuController.openCssEditor();
break;
case 'view.open.jsEditor':
this.controller.viewMenuController.openJsEditor();
break;
case 'view.open.htmlHeadEditor':
this.controller.viewMenuController.openHtmlHeadEditor();
break;
case 'tools.advanced.activate':
this.controller.toolMenuController.toggleAdvanced();
break;
case 'tools.mobile.mode':
this.controller.toolMenuController.toggleMobileMode();
break;
case 'tools.mobile.mode.on':
this.controller.toolMenuController.setMobileMode(true);
break;
case 'tools.mobile.mode.off':
this.controller.toolMenuController.setMobileMode(false);
break;
case 'insert.page':
this.controller.insertMenuController.createPage();
break;
case 'insert.text':
added = this.controller.insertMenuController.addElement(
Constants.TYPE_TEXT, opt_componentName);
break;
case 'insert.section':
added = this.controller.insertMenuController.addElement(
Constants.TYPE_SECTION, opt_componentName);
break;
case 'insert.html':
added = this.controller.insertMenuController.addElement(
Constants.TYPE_HTML, opt_componentName);
break;
case 'insert.image':
// FIXME: add opt_componentName param to browseAndAddImage
this.controller.insertMenuController.browseAndAddImage();
break;
case 'insert.container':
added = this.controller.insertMenuController.addElement(
Constants.TYPE_CONTAINER, opt_componentName);
break;
case 'edit.delete.selection':
this.controller.editMenuController.removeSelectedElements();
break;
case 'edit.empty.selection':
this.controller.editMenuController.emptySelection();
break;
case 'edit.copy.selection':
this.controller.editMenuController.copySelection();
break;
case 'edit.paste.selection':
this.controller.editMenuController.pasteClipBoard();
break;
case 'edit.duplicate.selection':
this.controller.editMenuController.duplicate();
break;
case 'edit.undo':
this.controller.editMenuController.undo();
break;
case 'edit.redo':
this.controller.editMenuController.redo();
break;
case 'edit.move.up':
this.controller.editMenuController.moveUp();
break;
case 'edit.move.down':
this.controller.editMenuController.moveDown();
break;
case 'edit.move.to.top':
this.controller.editMenuController.moveToTop();
break;
case 'edit.move.to.bottom':
this.controller.editMenuController.moveToBottom();
break;
case 'edit.delete.page':
this.controller.pageToolController.removePage();
break;
case 'edit.rename.page':
this.controller.pageToolController.renamePage();
break;
// Help menu
case 'help.wiki':
window.open(Config.WIKI_SILEX);
break;
case 'help.crowdfunding':
window.open(Config.CROWD_FUNDING);
break;
case 'help.issues':
window.open(Config.ISSUES_SILEX);
break;
case 'help.downloads.widget':
window.open(Config.DOWNLOADS_WIDGET_SILEX);
break;
case 'help.downloads.template':
window.open(Config.DOWNLOADS_TEMPLATE_SILEX);
break;
case 'help.aboutSilexLabs':
window.open(Config.ABOUT_SILEX_LABS);
break;
case 'help.newsLetter':
window.open(Config.SUBSCRIBE_SILEX_LABS);
break;
case 'help.diaspora':
window.open(Config.SOCIAL_DIASPORA);
break;
case 'help.twitter':
window.open(Config.SOCIAL_TWITTER);
break;
case 'help.facebook':
window.open(Config.SOCIAL_FB);
break;
case 'help.forkMe':
window.open(Config.FORK_CODE);
break;
case 'help.contribute':
window.open(Config.CONTRIBUTE);
break;
default:
console.warn('menu type not found', type);
}
}
}