mirror of
https://github.com/codex-team/editor.js
synced 2024-05-09 18:06:59 +02:00
anchors added (#150)
* anchors added * Styles improve and keyboard behavior fix * Styles improve * Translit added * Anchors as default settings * Remove trash changes * Upd * Anchors module added and version updated * styles imroved * remove anchor flag on mobile viewport
This commit is contained in:
parent
f5314dfab6
commit
61fd151568
125
codex-editor.css
125
codex-editor.css
|
@ -143,10 +143,11 @@
|
|||
*/
|
||||
.ce-toolbar__actions{
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
right: 15px;
|
||||
border-radius: 2px;
|
||||
padding: 4px 5px;
|
||||
background: #f9f9fb;
|
||||
padding: 6px 5px;
|
||||
line-height: 1em;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
|
||||
|
@ -167,7 +168,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* Settigns pane
|
||||
* Settigns panel
|
||||
*/
|
||||
.ce-settings,
|
||||
.ce-toolbar__remove-confirmation{
|
||||
|
@ -180,7 +181,7 @@
|
|||
box-shadow: 0px 2px 5px 0px rgba(16, 23, 49, 0.05);
|
||||
border-radius: 3px;
|
||||
white-space: nowrap;
|
||||
color: #707684;
|
||||
color: #2b2d31;
|
||||
font-size: 13.4px;
|
||||
|
||||
/* hidden by default */
|
||||
|
@ -225,11 +226,35 @@
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Plugins settings style helper
|
||||
*/
|
||||
.cdx-plugin-settings--horisontal {
|
||||
display: -webkit-flex;
|
||||
display: -moz-flex;
|
||||
display: -ms-flex;
|
||||
display: -o-flex;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.cdx-plugin-settings__item {
|
||||
flex: 1 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ce-settings__item,
|
||||
.ce-toolbar__remove-confirm
|
||||
.ce-toolbar__remove-cancel {
|
||||
.ce-toolbar__remove-confirm,
|
||||
.ce-toolbar__remove-cancel,
|
||||
.cdx-plugin-settings__item {
|
||||
padding: 15px;
|
||||
cursor: pointer;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.ce-settings__item:hover,
|
||||
.ce-toolbar__remove-cancel:hover,
|
||||
.cdx-plugin-settings__item:hover {
|
||||
background: #edf0f5;
|
||||
}
|
||||
|
||||
.ce-settings.opened,
|
||||
|
@ -238,19 +263,27 @@
|
|||
}
|
||||
|
||||
.ce-settings_plugin{
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #E8EAEE;
|
||||
border-bottom: 1px solid #e7e9f1;
|
||||
}
|
||||
|
||||
.ce-settings_plugin:empty{
|
||||
display: none;
|
||||
}
|
||||
.ce-settings_default{
|
||||
padding: 20px;
|
||||
|
||||
.ce-settings__item:not(:last-of-type) {
|
||||
border-bottom: 1px solid #e7e9f1;
|
||||
}
|
||||
|
||||
.ce-settings__item i {
|
||||
min-width: 16px;
|
||||
margin-right: 1.3em;
|
||||
}
|
||||
|
||||
.ce-settings__item i::before {
|
||||
min-width: 16px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Trash button
|
||||
|
@ -258,25 +291,45 @@
|
|||
.ce-toolbar__remove-btn {
|
||||
cursor: pointer;
|
||||
}
|
||||
.ce-toolbar__remove-confirmation{
|
||||
padding: 5px 0;
|
||||
}
|
||||
.ce-toolbar__remove-confirm,
|
||||
.ce-toolbar__remove-cancel{
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.ce-toolbar__remove-confirm{
|
||||
color: #ea5c5c;
|
||||
}
|
||||
|
||||
.ce-toolbar__remove-confirm:hover{
|
||||
background: #e23d3d;
|
||||
color: #fff;
|
||||
}
|
||||
.ce-toolbar__remove-cancel:hover{
|
||||
background: #edf0f5;
|
||||
|
||||
/** Anchor input */
|
||||
.ce-settings__anchor-wrapper:hover {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.ce-settings__anchor-input {
|
||||
max-width: 100%;
|
||||
border: 0;
|
||||
outline: none;
|
||||
padding: 14px 0;
|
||||
margin: -15px 0;
|
||||
font-size: inherit;
|
||||
color: #000;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.ce-settings__anchor-input::-webkit-input-placeholder {color: rgba(112, 118, 132, 0.5);}
|
||||
.ce-settings__anchor-input::-moz-placeholder {color: rgba(112, 118, 132, 0.5);}
|
||||
.ce-settings__anchor-input:-moz-placeholder {color: rgba(112, 118, 132, 0.5);}
|
||||
.ce-settings__anchor-input:-ms-input-placeholder {color: rgba(112, 118, 132, 0.5);}
|
||||
|
||||
.ce-settings__anchor-hash {
|
||||
display: inline-block;
|
||||
background: url('fonts/codex_editor/icon-hash.svg') no-repeat center center;
|
||||
background-size: contain;
|
||||
height: 11px;
|
||||
width: 10px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overlayed inline toolbar
|
||||
|
@ -352,30 +405,48 @@
|
|||
/**
|
||||
* Base blocks
|
||||
*/
|
||||
.ce-block{
|
||||
.ce-block {
|
||||
margin: 0 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.ce-block--focused{
|
||||
|
||||
.ce-block--focused {
|
||||
background: #f9f9fb;
|
||||
}
|
||||
|
||||
.ce-block--feed-mode{
|
||||
.ce-block--feed-mode {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ce-block--feed-mode:before {
|
||||
content: '\e81b';
|
||||
font-family: "codex_editor";
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
|
||||
left: 17px;
|
||||
top: 13px;
|
||||
font-size: 16px;
|
||||
/*color: #ef4a4a;*/
|
||||
color: #7d6060;
|
||||
}
|
||||
|
||||
.ce-block--anchor {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ce-block--anchor::after {
|
||||
display: inline-block;
|
||||
content: "#" attr(data-anchor);
|
||||
color: #868896;
|
||||
position: absolute;
|
||||
left: 17px;
|
||||
top: 13px;
|
||||
max-width: 100px;
|
||||
word-wrap: break-word;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Block content holder
|
||||
*/
|
||||
|
@ -470,4 +541,8 @@
|
|||
font-size: 13px;
|
||||
}
|
||||
|
||||
.ce-block--anchor::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
codex.js
1
codex.js
|
@ -27,6 +27,7 @@ module.exports = (function (editor) {
|
|||
editor.notifications = require('./modules/notifications');
|
||||
editor.parser = require('./modules/parser');
|
||||
editor.sanitizer = require('./modules/sanitizer');
|
||||
editor.anchors = require('./modules/anchors');
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,14 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<title>CodeX Editor example</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
|
6
fonts/codex_editor/icon-hash.svg
Normal file
6
fonts/codex_editor/icon-hash.svg
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg height="32px" style="enable-background:new 0 0 28 32;" version="1.1" viewBox="0 0 28 32" width="28px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Layer_1"/>
|
||||
<g id="hash">
|
||||
<path d="M28,12V8h-5.004l1-8h-4l-1,8h-7.998l1-8h-4l-1,8H0v4h6.498L5.5,20H0v4h5l-1,8h4l1-8h8l-1.002,8H20 l1-8h7v-4h-6.5l0.996-8H28z M17.5,20h-8l0.998-8h7.998L17.5,20z" style="fill:#707684;"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 569 B |
94
modules/anchors.js
Normal file
94
modules/anchors.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* Codex Editor Anchors module
|
||||
*
|
||||
* @author Codex Team
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
let editor = codex.editor;
|
||||
|
||||
module.exports = function (anchors) {
|
||||
|
||||
anchors.input = null;
|
||||
anchors.currentNode = null;
|
||||
|
||||
const blockWithAnchorClassName = 'ce-block--anchor';
|
||||
|
||||
anchors.settingsOpened = function (currentBlock) {
|
||||
|
||||
anchors.currentNode = currentBlock;
|
||||
anchors.input.value = anchors.currentNode.dataset.anchor || '';
|
||||
|
||||
};
|
||||
|
||||
anchors.anchorChanged = function (e) {
|
||||
|
||||
var newAnchor = e.target.value = anchors.rusToTranslit(e.target.value);
|
||||
|
||||
if (newAnchor.trim() !== '') {
|
||||
|
||||
anchors.currentNode.dataset.anchor = newAnchor;
|
||||
anchors.currentNode.classList.add(blockWithAnchorClassName);
|
||||
|
||||
} else {
|
||||
|
||||
delete anchors.currentNode.dataset.anchor;
|
||||
anchors.currentNode.classList.remove(blockWithAnchorClassName);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
anchors.keyDownOnAnchorInput = function (e) {
|
||||
|
||||
if (e.keyCode == editor.core.keys.ENTER) {
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
e.target.blur();
|
||||
editor.toolbar.settings.close();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
anchors.keyUpOnAnchorInput = function (e) {
|
||||
|
||||
if (e.keyCode >= editor.core.keys.LEFT && e.keyCode <= editor.core.keys.DOWN) {
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
anchors.rusToTranslit = function (string) {
|
||||
|
||||
var ru = [
|
||||
'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й',
|
||||
'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф',
|
||||
'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ь', 'Ы', 'Ь', 'Э', 'Ю', 'Я'
|
||||
],
|
||||
en = [
|
||||
'A', 'B', 'V', 'G', 'D', 'E', 'E', 'Zh', 'Z', 'I', 'Y',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F',
|
||||
'H', 'C', 'Ch', 'Sh', 'Sch', '', 'Y', '', 'E', 'Yu', 'Ya'
|
||||
];
|
||||
|
||||
for (var i = 0; i < ru.length; i++) {
|
||||
|
||||
string = string.split(ru[i]).join(en[i]);
|
||||
string = string.split(ru[i].toLowerCase()).join(en[i].toLowerCase());
|
||||
|
||||
}
|
||||
|
||||
string = string.replace(/[^0-9a-zA-Z_]+/g, '-');
|
||||
|
||||
return string;
|
||||
|
||||
};
|
||||
|
||||
return anchors;
|
||||
|
||||
}({});
|
|
@ -194,6 +194,11 @@ module.exports = (function (content) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving anchor
|
||||
*/
|
||||
newBlock.dataset.anchor = targetBlock.dataset.anchor;
|
||||
|
||||
/** Replacing */
|
||||
editor.nodes.redactor.replaceChild(newBlock, targetBlock);
|
||||
|
||||
|
@ -232,9 +237,10 @@ module.exports = (function (content) {
|
|||
newBlockContent = blockData.block,
|
||||
blockType = blockData.type,
|
||||
cover = blockData.cover,
|
||||
anchor = blockData.anchor,
|
||||
isStretched = blockData.stretched;
|
||||
|
||||
var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched);
|
||||
var newBlock = editor.content.composeNewBlock(newBlockContent, blockType, isStretched, anchor);
|
||||
|
||||
if (cover === true) {
|
||||
|
||||
|
@ -433,7 +439,7 @@ module.exports = (function (content) {
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
content.composeNewBlock = function (block, tool, isStretched) {
|
||||
content.composeNewBlock = function (block, tool, isStretched, anchor) {
|
||||
|
||||
var newBlock = editor.draw.node('DIV', editor.ui.className.BLOCK_CLASSNAME, {}),
|
||||
blockContent = editor.draw.node('DIV', editor.ui.className.BLOCK_CONTENT, {});
|
||||
|
@ -447,7 +453,8 @@ module.exports = (function (content) {
|
|||
|
||||
}
|
||||
|
||||
newBlock.dataset.tool = tool;
|
||||
newBlock.dataset.tool = tool;
|
||||
newBlock.dataset.anchor = anchor || '';
|
||||
return newBlock;
|
||||
|
||||
};
|
||||
|
|
|
@ -150,6 +150,7 @@ module.exports = (function (renderer) {
|
|||
var block,
|
||||
tool = toolData.tool,
|
||||
pluginName = tool.type,
|
||||
anchor = toolData.anchor,
|
||||
cover = tool.cover;
|
||||
|
||||
/** Get first key of object that stores plugin name */
|
||||
|
@ -195,7 +196,8 @@ module.exports = (function (renderer) {
|
|||
type : pluginName,
|
||||
block : block,
|
||||
stretched : stretched,
|
||||
cover : cover
|
||||
cover : cover,
|
||||
anchor : anchor
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -86,7 +86,8 @@ module.exports = (function (saver) {
|
|||
|
||||
saver.makeFormDataFromBlocks = function (block) {
|
||||
|
||||
var pluginName = block.dataset.tool;
|
||||
var pluginName = block.dataset.tool,
|
||||
anchor = block.dataset.anchor;
|
||||
|
||||
/** Check for plugin existance */
|
||||
if (!editor.tools[pluginName]) {
|
||||
|
@ -117,6 +118,7 @@ module.exports = (function (saver) {
|
|||
|
||||
savedData = codex.editor.state.blocks.items[position].data;
|
||||
coverFlag = codex.editor.state.blocks.items[position].cover;
|
||||
anchor = codex.editor.state.blocks.items[position].anchor;
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -138,8 +140,9 @@ module.exports = (function (saver) {
|
|||
}
|
||||
|
||||
output = {
|
||||
type: pluginName,
|
||||
data: savedData
|
||||
type : pluginName,
|
||||
anchor : anchor,
|
||||
data : savedData
|
||||
};
|
||||
|
||||
/** Marks Blocks that will be in main page */
|
||||
|
|
|
@ -67,6 +67,7 @@ module.exports = (function (settings) {
|
|||
if ( !this.opened ) {
|
||||
|
||||
this.open(toolType);
|
||||
editor.anchors.settingsOpened(editor.content.currentNode);
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -82,7 +83,8 @@ module.exports = (function (settings) {
|
|||
settings.addDefaultSettings = function () {
|
||||
|
||||
/** list of default settings */
|
||||
var feedModeToggler;
|
||||
var feedModeToggler,
|
||||
anchorInput;
|
||||
|
||||
/** Clear block and append initialized settings */
|
||||
editor.nodes.defaultSettings.innerHTML = '';
|
||||
|
@ -90,11 +92,17 @@ module.exports = (function (settings) {
|
|||
|
||||
/** Init all default setting buttons */
|
||||
feedModeToggler = editor.toolbar.settings.makeFeedModeToggler();
|
||||
anchorInput = editor.toolbar.settings.makeAnchorInput();
|
||||
|
||||
/**
|
||||
* Fill defaultSettings
|
||||
*/
|
||||
|
||||
/**
|
||||
* Input for anchor for block
|
||||
*/
|
||||
editor.nodes.defaultSettings.appendChild(anchorInput);
|
||||
|
||||
/**
|
||||
* Button that enables/disables Feed-mode
|
||||
* Feed-mode means that block will be showed in articles-feed like cover
|
||||
|
@ -168,6 +176,26 @@ module.exports = (function (settings) {
|
|||
|
||||
};
|
||||
|
||||
settings.makeAnchorInput = function () {
|
||||
|
||||
var anchorWrapper = editor.draw.node('div', 'ce-settings__anchor-wrapper ce-settings__item', {}),
|
||||
hash = editor.draw.node('i', 'ce-settings__anchor-hash', {}),
|
||||
anchor = editor.draw.node('input', 'ce-settings__anchor-input', { placeholder: 'Якорь' });
|
||||
|
||||
anchor.addEventListener('keydown', editor.anchors.keyDownOnAnchorInput );
|
||||
anchor.addEventListener('keyup', editor.anchors.keyUpOnAnchorInput );
|
||||
anchor.addEventListener('input', editor.anchors.anchorChanged );
|
||||
anchor.addEventListener('blur', editor.anchors.anchorChanged );
|
||||
|
||||
anchorWrapper.appendChild(hash);
|
||||
anchorWrapper.appendChild(anchor);
|
||||
|
||||
editor.anchors.input = anchor;
|
||||
|
||||
return anchorWrapper;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Here we will draw buttons and add listeners to components
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "codex.editor",
|
||||
"version": "1.4.3",
|
||||
"version": "1.4.4",
|
||||
"description": "Codex Editor. Native JS, based on API and Open Source",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
|
|
@ -128,18 +128,18 @@ var header = (function(header) {
|
|||
*/
|
||||
header.makeSettings = function () {
|
||||
|
||||
var holder = codex.editor.draw.node('DIV', ['ce_plugin_header--settings'], {} ),
|
||||
var holder = codex.editor.draw.node('DIV', ['cdx-plugin-settings--horisontal'], {} ),
|
||||
types = {
|
||||
h2: 'Заголовок H2',
|
||||
h3: 'Заголовок H3',
|
||||
h4: 'Заголовок H4'
|
||||
h2: 'H2',
|
||||
h3: 'H3',
|
||||
h4: 'H4'
|
||||
},
|
||||
selectTypeButton;
|
||||
|
||||
/** Now add type selectors */
|
||||
for (var type in types){
|
||||
|
||||
selectTypeButton = codex.editor.draw.node('SPAN', ['ce_plugin_header--select_button'], { textContent : types[type] });
|
||||
selectTypeButton = codex.editor.draw.node('SPAN', ['cdx-plugin-settings__item'], { textContent : types[type] });
|
||||
methods_.addSelectTypeClickListener(selectTypeButton, type);
|
||||
holder.appendChild(selectTypeButton);
|
||||
|
||||
|
|
|
@ -134,15 +134,14 @@
|
|||
color: #a1b4ec;
|
||||
}
|
||||
|
||||
.ce-image-settings {
|
||||
padding: 7px 0
|
||||
}
|
||||
.ce-image-settings__item {
|
||||
margin-bottom: 10px;
|
||||
padding: 7px 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ce-image-settings__item:not(:last-of-type){
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.ce-settings-checkbox {
|
||||
display: inline-block;
|
||||
width: 17px;
|
||||
|
|
|
@ -314,7 +314,7 @@ var image = (function(image) {
|
|||
|
||||
setTimeout(function() {
|
||||
codex.editor.toolbar.settings.close();
|
||||
}, 200);
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
};
|
||||
|
@ -340,7 +340,7 @@ var image = (function(image) {
|
|||
var type = files[0].type.split('/');
|
||||
|
||||
var result = validFileExtensions.some(function(ext) {
|
||||
return ext == type[1]
|
||||
return ext == type[1];
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
|
@ -646,7 +646,7 @@ var image = (function(image) {
|
|||
currentImageSettings = currentImageWrapper.dataset;
|
||||
|
||||
/** Add holder classname */
|
||||
holder.className = 'ce_plugin_image--settings';
|
||||
holder.className = 'ce-image-settings';
|
||||
|
||||
/** Now add type selectors */
|
||||
for (var type in types){
|
||||
|
|
|
@ -39,9 +39,9 @@ var quote = (function(quote) {
|
|||
},
|
||||
|
||||
settings : {
|
||||
holder : 'ce_plugin_quote--settings',
|
||||
holder : 'cdx-plugin-settings--horisontal',
|
||||
caption : 'ce_plugin_quote--caption',
|
||||
buttons : 'ce_plugin_quote--select_button',
|
||||
buttons : 'cdx-plugin-settings__item',
|
||||
selectedType : 'ce-quote-settings--selected'
|
||||
}
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue