editor.js/modules/ui.js
2017-08-30 06:48:52 +03:00

432 lines
12 KiB
JavaScript

/**
* Codex Editor UI module
*
* @author Codex Team
* @version 1.2.0
*/
module.exports = (function (ui) {
let editor = codex.editor;
/**
* Basic editor classnames
*/
ui.className = {
/**
* @const {string} BLOCK_CLASSNAME - redactor blocks name
*/
BLOCK_CLASSNAME : 'ce-block',
/**
* @const {String} wrapper for plugins content
*/
BLOCK_CONTENT : 'ce-block__content',
/**
* @const {String} BLOCK_STRETCHED - makes block stretched
*/
BLOCK_STRETCHED : 'ce-block--stretched',
/**
* @const {String} BLOCK_HIGHLIGHTED - adds background
*/
BLOCK_HIGHLIGHTED : 'ce-block--focused',
/**
* @const {String} - for all default settings
*/
SETTINGS_ITEM : 'ce-settings__item'
};
/**
* @protected
*
* Making main interface
*/
ui.prepare = function () {
return new Promise(function (resolve) {
let wrapper = editor.draw.wrapper(),
redactor = editor.draw.redactor(),
toolbar = makeToolBar_();
wrapper.appendChild(toolbar);
wrapper.appendChild(redactor);
/** Save created ui-elements to static nodes state */
editor.nodes.wrapper = wrapper;
editor.nodes.redactor = redactor;
/** Append editor wrapper with redactor zone into holder */
editor.nodes.holder.appendChild(wrapper);
resolve();
})
/** Add toolbox tools */
.then(addTools_)
/** Make container for inline toolbar */
.then(makeInlineToolbar_)
/** Add inline toolbar tools */
.then(addInlineToolbarTools_)
/** Draw wrapper for notifications */
.then(makeNotificationHolder_)
/** Add eventlisteners to redactor elements */
.then(bindEvents_)
.catch( function () {
editor.core.log("Can't draw editor interface");
});
};
/**
* @private
* Draws inline toolbar zone
*/
var makeInlineToolbar_ = function () {
var container = editor.draw.inlineToolbar();
/** Append to redactor new inline block */
editor.nodes.inlineToolbar.wrapper = container;
/** Draw toolbar buttons */
editor.nodes.inlineToolbar.buttons = editor.draw.inlineToolbarButtons();
/** Buttons action or settings */
editor.nodes.inlineToolbar.actions = editor.draw.inlineToolbarActions();
/** Append to inline toolbar buttons as part of it */
editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.buttons);
editor.nodes.inlineToolbar.wrapper.appendChild(editor.nodes.inlineToolbar.actions);
editor.nodes.wrapper.appendChild(editor.nodes.inlineToolbar.wrapper);
};
var makeToolBar_ = function () {
let toolbar = editor.draw.toolbar(),
blockButtons = makeToolbarSettings_(),
toolbarContent = makeToolbarContent_();
/** Appending first-level block buttons */
toolbar.appendChild(blockButtons);
/** Append toolbarContent to toolbar */
toolbar.appendChild(toolbarContent);
/** Make toolbar global */
editor.nodes.toolbar = toolbar;
return toolbar;
};
var makeToolbarContent_ = function () {
let toolbarContent = editor.draw.toolbarContent(),
toolbox = editor.draw.toolbox(),
plusButton = editor.draw.plusButton();
/** Append plus button */
toolbarContent.appendChild(plusButton);
/** Appending toolbar tools */
toolbarContent.appendChild(toolbox);
/** Make Toolbox and plusButton global */
editor.nodes.toolbox = toolbox;
editor.nodes.plusButton = plusButton;
return toolbarContent;
};
var makeToolbarSettings_ = function () {
let blockSettings = editor.draw.blockSettings(),
blockButtons = editor.draw.blockButtons(),
defaultSettings = editor.draw.defaultSettings(),
showSettingsButton = editor.draw.settingsButton(),
showTrashButton = editor.toolbar.settings.makeRemoveBlockButton(),
pluginSettings = editor.draw.pluginsSettings();
/** Add default and plugins settings */
blockSettings.appendChild(pluginSettings);
blockSettings.appendChild(defaultSettings);
/**
* Make blocks buttons
* This block contains settings button and remove block button
*/
blockButtons.appendChild(showSettingsButton);
blockButtons.appendChild(showTrashButton);
blockButtons.appendChild(blockSettings);
/** Make BlockSettings, PluginSettings, DefaultSettings global */
editor.nodes.blockSettings = blockSettings;
editor.nodes.pluginSettings = pluginSettings;
editor.nodes.defaultSettings = defaultSettings;
editor.nodes.showSettingsButton = showSettingsButton;
editor.nodes.showTrashButton = showTrashButton;
return blockButtons;
};
/** Draw notifications holder */
var makeNotificationHolder_ = function () {
/** Append block with notifications to the document */
editor.nodes.notifications = editor.notifications.createHolder();
};
/**
* @private
* Append tools passed in editor.tools
*/
var addTools_ = function () {
var tool,
toolName,
toolButton;
for ( toolName in editor.settings.tools ) {
tool = editor.settings.tools[toolName];
editor.tools[toolName] = tool;
if (!tool.iconClassname && tool.displayInToolbox) {
editor.core.log('Toolbar icon classname missed. Tool %o skipped', 'warn', toolName);
continue;
}
if (typeof tool.render != 'function') {
editor.core.log('render method missed. Tool %o skipped', 'warn', toolName);
continue;
}
if (!tool.displayInToolbox) {
continue;
} else {
/** if tools is for toolbox */
toolButton = editor.draw.toolbarButton(toolName, tool.iconClassname);
editor.nodes.toolbox.appendChild(toolButton);
editor.nodes.toolbarButtons[toolName] = toolButton;
}
}
};
var addInlineToolbarTools_ = function () {
var tools = {
bold: {
icon : 'ce-icon-bold',
command : 'bold'
},
italic: {
icon : 'ce-icon-italic',
command : 'italic'
},
link: {
icon : 'ce-icon-link',
command : 'createLink'
}
};
var toolButton,
tool;
for(var name in tools) {
tool = tools[name];
toolButton = editor.draw.toolbarButtonInline(name, tool.icon);
editor.nodes.inlineToolbar.buttons.appendChild(toolButton);
/**
* Add callbacks to this buttons
*/
editor.ui.setInlineToolbarButtonBehaviour(toolButton, tool.command);
}
};
/**
* @private
* Bind editor UI events
*/
var bindEvents_ = function () {
editor.core.log('ui.bindEvents fired', 'info');
// window.addEventListener('error', function (errorMsg, url, lineNumber) {
// editor.notifications.errorThrown(errorMsg, event);
// }, false );
/** All keydowns on Document */
editor.listeners.add(document, 'keydown', editor.callback.globalKeydown, false);
/** All keydowns on Redactor zone */
editor.listeners.add(editor.nodes.redactor, 'keydown', editor.callback.redactorKeyDown, false);
/** All keydowns on Document */
editor.listeners.add(document, 'keyup', editor.callback.globalKeyup, false );
/**
* Mouse click to radactor
*/
editor.listeners.add(editor.nodes.redactor, 'click', editor.callback.redactorClicked, false );
/**
* Clicks to the Plus button
*/
editor.listeners.add(editor.nodes.plusButton, 'click', editor.callback.plusButtonClicked, false);
/**
* Clicks to SETTINGS button in toolbar
*/
editor.listeners.add(editor.nodes.showSettingsButton, 'click', editor.callback.showSettingsButtonClicked, false );
/** Bind click listeners on toolbar buttons */
for (var button in editor.nodes.toolbarButtons) {
editor.listeners.add(editor.nodes.toolbarButtons[button], 'click', editor.callback.toolbarButtonClicked, false);
}
};
ui.addBlockHandlers = function (block) {
if (!block) return;
/**
* Block keydowns
*/
editor.listeners.add(block, 'keydown', editor.callback.blockKeydown, false);
/**
* Pasting content from another source
* We have two type of sanitization
* First - uses deep-first search algorithm to get sub nodes,
* sanitizes whole Block_content and replaces cleared nodes
* This method is deprecated
* Method is used in editor.callback.blockPaste(event)
*
* Secont - uses Mutation observer.
* Observer "observe" DOM changes and send changings to callback.
* Callback gets changed node, not whole Block_content.
* Inserted or changed node, which we've gotten have been cleared and replaced with diry node
*
* Method is used in editor.callback.blockPasteViaSanitize(event)
*
* @uses html-janitor
* @example editor.callback.blockPasteViaSanitize(event), the second method.
*
*/
editor.listeners.add(block, 'paste', editor.paste.blockPasteCallback, false);
/**
* Show inline toolbar for selected text
*/
editor.listeners.add(block, 'mouseup', editor.toolbar.inline.show, false);
editor.listeners.add(block, 'keyup', editor.toolbar.inline.show, false);
};
/** getting all contenteditable elements */
ui.saveInputs = function () {
var redactor = editor.nodes.redactor;
editor.state.inputs = [];
/** Save all inputs in global variable state */
var inputs = redactor.querySelectorAll('[contenteditable], input, textarea');
Array.prototype.map.call(inputs, function (current) {
if (!current.type || current.type == 'text' || current.type == 'textarea') {
editor.state.inputs.push(current);
}
});
};
/**
* Adds first initial block on empty redactor
*/
ui.addInitialBlock = function () {
var initialBlockType = editor.settings.initialBlockPlugin,
initialBlock;
if ( !editor.tools[initialBlockType] ) {
editor.core.log('Plugin %o was not implemented and can\'t be used as initial block', 'warn', initialBlockType);
return;
}
initialBlock = editor.tools[initialBlockType].render();
initialBlock.setAttribute('data-placeholder', editor.settings.placeholder);
editor.content.insertBlock({
type : initialBlockType,
block : initialBlock
});
editor.content.workingNodeChanged(initialBlock);
};
ui.setInlineToolbarButtonBehaviour = function (button, type) {
editor.listeners.add(button, 'mousedown', function (event) {
editor.toolbar.inline.toolClicked(event, type);
}, false);
};
return ui;
})({});