From 98fbe56248eb22aa068af3356c0dea18a8a7f0e1 Mon Sep 17 00:00:00 2001 From: firm1 Date: Wed, 22 Jan 2020 22:55:22 +0100 Subject: [PATCH 1/6] allow dropdown menu on toolbar to group secondary buttons --- README.md | 40 +++++++++++++++++++++++++++++++++ src/css/easymde.css | 24 +++++++++++++++----- src/js/easymde.js | 55 ++++++++++++++++++++++++++++++--------------- 3 files changed, 96 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index b68caba..87938be 100644 --- a/README.md +++ b/README.md @@ -346,6 +346,46 @@ var easyMDE = new EasyMDE({ }); ``` +Put some buttons on dropdown menu + +```Javascript +var easyMDE = new EasyMDE({ + toolbar: [{ + name: "heading", + action: EasyMDE.toggleHeadingSmaller, + className: "fa fa-header", + title: "Headers", + }, + "|", + { + name: "others", + className: "fa fa-blind", + title: "others buttons", + children: [ + { + name: "image", + action: EasyMDE.drawImage, + className: "fa fa-picture-o", + title: "Image", + }, + { + name: "quote", + action: EasyMDE.toggleBlockquote, + className: "fa fa-percent", + title: "Quote", + }, + { + name: "link", + action: EasyMDE.drawLink, + className: "fa fa-link", + title: "Link", + } + ] + }, + // [, ...] + ] +}); +``` ### Keyboard shortcuts diff --git a/src/css/easymde.css b/src/css/easymde.css index a027a14..96805e5 100644 --- a/src/css/easymde.css +++ b/src/css/easymde.css @@ -22,7 +22,7 @@ right: 0; bottom: 0; height: auto; - z-index: 9; + z-index: 8; border-right: none !important; border-bottom-right-radius: 0 !important; } @@ -72,9 +72,6 @@ .editor-toolbar.fullscreen { width: 100%; height: 50px; - overflow-x: auto; - overflow-y: hidden; - white-space: nowrap; padding-top: 10px; padding-bottom: 10px; box-sizing: border-box; @@ -119,7 +116,7 @@ padding: 0; } -.editor-toolbar button { +.editor-toolbar button, .editor-toolbar .easymde-dropdown { background: transparent; display: inline-block; text-align: center; @@ -316,3 +313,20 @@ color: #7f8c8d; font-style: italic; } + +.easymde-dropdown { + position: relative; +} + +.easymde-dropdown-content { + display: none; + position: absolute; + background-color: #f9f9f9; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + padding: 8px 8px; + z-index: 2; +} + +.easymde-dropdown:hover .easymde-dropdown-content { + display: block; +} diff --git a/src/js/easymde.js b/src/js/easymde.js index 4e0a2f6..5fdd25e 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -110,15 +110,30 @@ function fixShortcut(name) { return name; } +/** + * Create dropdown block + */ +function createToolbarDropdown(options, enableTooltips, shortcuts, parent) { + var el = createToolbarButton(options, enableTooltips, shortcuts, 'div'); + el.className += ' easymde-dropdown'; + var content = document.createElement('div'); + content.className = 'easymde-dropdown-content'; + for (var childrenIndex = 0; childrenIndex < options.children.length; childrenIndex++) { + var child = createToolbarButton(options.children[childrenIndex], enableTooltips, shortcuts, 'button', parent); + content.appendChild(child); + } + el.appendChild(content); + return el; +} /** * Create button element for toolbar. */ -function createToolbarButton(options, enableTooltips, shortcuts) { +function createToolbarButton(options, enableTooltips, shortcuts, markup, parent) { options = options || {}; - var el = document.createElement('button'); + var el = document.createElement(markup); el.className = options.name; - el.setAttribute('type', 'button'); + el.setAttribute('type', markup); enableTooltips = (enableTooltips == undefined) ? true : enableTooltips; // Properly hande custom shortcuts @@ -167,6 +182,20 @@ function createToolbarButton(options, enableTooltips, shortcuts) { } el.appendChild(icon); + if (options.action) { + if (typeof options.action === 'function') { + el.onclick = function (e) { + e.preventDefault(); + options.action(parent); + }; + } else if (typeof options.action === 'string') { + el.onclick = function (e) { + e.preventDefault(); + window.open(options.action, '_blank'); + }; + } + } + return el; } @@ -2254,24 +2283,14 @@ EasyMDE.prototype.createToolbar = function (items) { if (item === '|') { el = createSep(); } else { - el = createToolbarButton(item, self.options.toolbarTips, self.options.shortcuts); - } - - // bind events, special for info - if (item.action) { - if (typeof item.action === 'function') { - el.onclick = function (e) { - e.preventDefault(); - item.action(self); - }; - } else if (typeof item.action === 'string') { - el.onclick = function (e) { - e.preventDefault(); - window.open(item.action, '_blank'); - }; + if (item.children) { + el = createToolbarDropdown(item, self.options.toolbarTips, self.options.shortcuts, self); + } else { + el = createToolbarButton(item, self.options.toolbarTips, self.options.shortcuts, 'button', self); } } + toolbarData[item.name || item] = el; bar.appendChild(el); From eea2917be1a516cf239b0411a9fadf7f3a39d0f9 Mon Sep 17 00:00:00 2001 From: firm1 Date: Thu, 23 Jan 2020 08:35:29 +0100 Subject: [PATCH 2/6] @situphen 's review --- src/css/easymde.css | 2 +- src/js/easymde.js | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/css/easymde.css b/src/css/easymde.css index 96805e5..46305e5 100644 --- a/src/css/easymde.css +++ b/src/css/easymde.css @@ -323,7 +323,7 @@ position: absolute; background-color: #f9f9f9; box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - padding: 8px 8px; + padding: 8px; z-index: 2; } diff --git a/src/js/easymde.js b/src/js/easymde.js index 5fdd25e..cabc8ce 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -114,7 +114,7 @@ function fixShortcut(name) { * Create dropdown block */ function createToolbarDropdown(options, enableTooltips, shortcuts, parent) { - var el = createToolbarButton(options, enableTooltips, shortcuts, 'div'); + var el = createToolbarButton(options, enableTooltips, shortcuts, 'div', parent); el.className += ' easymde-dropdown'; var content = document.createElement('div'); content.className = 'easymde-dropdown-content'; @@ -2282,12 +2282,10 @@ EasyMDE.prototype.createToolbar = function (items) { var el; if (item === '|') { el = createSep(); + } else if (item.children) { + el = createToolbarDropdown(item, self.options.toolbarTips, self.options.shortcuts, self); } else { - if (item.children) { - el = createToolbarDropdown(item, self.options.toolbarTips, self.options.shortcuts, self); - } else { - el = createToolbarButton(item, self.options.toolbarTips, self.options.shortcuts, 'button', self); - } + el = createToolbarButton(item, self.options.toolbarTips, self.options.shortcuts, 'button', self); } From 6f4225ccb27ad1286b51eb1a24906234c94aebd0 Mon Sep 17 00:00:00 2001 From: firm1 Date: Sun, 26 Jan 2020 20:45:38 +0100 Subject: [PATCH 3/6] update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bad0b0..28b605f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added - `inputStyle` and `nativeSpellcheck` options to manage the native language of the browser (Thanks to [@firm1], [#143]). +- Group buttons in drop-down lists by adding a sub-option `children` for the items in the toolbar (Thanks to [@firm1], [#141]). ### Changed - Delay before assuming that submit of the form as failed is `autosave.submit_delay` instead of `autosave.delay` (Thanks to [@Situphen], [#139]). From 26d2da9e29dd02be1b0ded20bec6323214acf708 Mon Sep 17 00:00:00 2001 From: firm1 Date: Tue, 28 Jan 2020 18:52:43 +0100 Subject: [PATCH 4/6] @Ionaru 's review : disable actions on top of dropdown, add dropdown icon and open on clic --- src/css/easymde.css | 23 ++++++++++++++++++++--- src/js/easymde.js | 13 ++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/css/easymde.css b/src/css/easymde.css index 46305e5..98b205d 100644 --- a/src/css/easymde.css +++ b/src/css/easymde.css @@ -121,7 +121,6 @@ display: inline-block; text-align: center; text-decoration: none !important; - width: 30px; height: 30px; margin: 0; padding: 0; @@ -130,6 +129,10 @@ cursor: pointer; } +.editor-toolbar button { + width: 30px; +} + .editor-toolbar button.active, .editor-toolbar button:hover { background: #fcfcfc; @@ -314,8 +317,9 @@ font-style: italic; } -.easymde-dropdown { +.editor-toolbar .easymde-dropdown { position: relative; + width: 45px; } .easymde-dropdown-content { @@ -325,8 +329,21 @@ box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); padding: 8px; z-index: 2; + top: 30px; } -.easymde-dropdown:hover .easymde-dropdown-content { +.easymde-dropdown:active .easymde-dropdown-content, +.easymde-dropdown:focus .easymde-dropdown-content{ display: block; } + +.down { + transform: rotate(45deg); + -webkit-transform: rotate(45deg); + border: solid #777; + border-width: 0 3px 3px 0; + display: inline-block; + padding: 2px; + margin-left: 8px; + margin-bottom: 3px; +} diff --git a/src/js/easymde.js b/src/js/easymde.js index cabc8ce..e4d4ccf 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -114,14 +114,17 @@ function fixShortcut(name) { * Create dropdown block */ function createToolbarDropdown(options, enableTooltips, shortcuts, parent) { - var el = createToolbarButton(options, enableTooltips, shortcuts, 'div', parent); + var el = createToolbarButton(options, false, enableTooltips, shortcuts, 'button', parent); el.className += ' easymde-dropdown'; var content = document.createElement('div'); content.className = 'easymde-dropdown-content'; for (var childrenIndex = 0; childrenIndex < options.children.length; childrenIndex++) { - var child = createToolbarButton(options.children[childrenIndex], enableTooltips, shortcuts, 'button', parent); + var child = createToolbarButton(options.children[childrenIndex], true, enableTooltips, shortcuts, 'button', parent); content.appendChild(child); } + var dropIcon = document.createElement('i'); + dropIcon.className = 'down'; + el.appendChild(dropIcon); el.appendChild(content); return el; } @@ -129,7 +132,7 @@ function createToolbarDropdown(options, enableTooltips, shortcuts, parent) { /** * Create button element for toolbar. */ -function createToolbarButton(options, enableTooltips, shortcuts, markup, parent) { +function createToolbarButton(options, enableActions, enableTooltips, shortcuts, markup, parent) { options = options || {}; var el = document.createElement(markup); el.className = options.name; @@ -182,7 +185,7 @@ function createToolbarButton(options, enableTooltips, shortcuts, markup, parent) } el.appendChild(icon); - if (options.action) { + if (options.action && enableActions) { if (typeof options.action === 'function') { el.onclick = function (e) { e.preventDefault(); @@ -2285,7 +2288,7 @@ EasyMDE.prototype.createToolbar = function (items) { } else if (item.children) { el = createToolbarDropdown(item, self.options.toolbarTips, self.options.shortcuts, self); } else { - el = createToolbarButton(item, self.options.toolbarTips, self.options.shortcuts, 'button', self); + el = createToolbarButton(item, true, self.options.toolbarTips, self.options.shortcuts, 'button', self); } From b11cd8edb099596277d854695fad98c45933481e Mon Sep 17 00:00:00 2001 From: firm1 Date: Tue, 28 Jan 2020 21:35:28 +0100 Subject: [PATCH 5/6] don't use down icon --- src/css/easymde.css | 21 ++++++++------------- src/js/easymde.js | 3 --- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/css/easymde.css b/src/css/easymde.css index 98b205d..20a60fc 100644 --- a/src/css/easymde.css +++ b/src/css/easymde.css @@ -319,7 +319,13 @@ .editor-toolbar .easymde-dropdown { position: relative; - width: 45px; + background: linear-gradient(to bottom right, #fff 0%, #fff 84%, #333 50%, #333 100%); + border-radius: 0px; + border: 1px solid #fff; +} + +.editor-toolbar .easymde-dropdown:hover { + background: linear-gradient(to bottom right, #fff 0%, #fff 84%, #333 50%, #333 100%); } .easymde-dropdown-content { @@ -333,17 +339,6 @@ } .easymde-dropdown:active .easymde-dropdown-content, -.easymde-dropdown:focus .easymde-dropdown-content{ +.easymde-dropdown:focus .easymde-dropdown-content { display: block; } - -.down { - transform: rotate(45deg); - -webkit-transform: rotate(45deg); - border: solid #777; - border-width: 0 3px 3px 0; - display: inline-block; - padding: 2px; - margin-left: 8px; - margin-bottom: 3px; -} diff --git a/src/js/easymde.js b/src/js/easymde.js index e4d4ccf..c93786e 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -122,9 +122,6 @@ function createToolbarDropdown(options, enableTooltips, shortcuts, parent) { var child = createToolbarButton(options.children[childrenIndex], true, enableTooltips, shortcuts, 'button', parent); content.appendChild(child); } - var dropIcon = document.createElement('i'); - dropIcon.className = 'down'; - el.appendChild(dropIcon); el.appendChild(content); return el; } From b85bdde0edeeeb0a7b9165ce8cecde7f82b52314 Mon Sep 17 00:00:00 2001 From: Jeroen Akkerman Date: Wed, 29 Jan 2020 15:57:28 +0100 Subject: [PATCH 6/6] Add button shortcuts and typings --- src/css/easymde.css | 4 ++-- src/js/easymde.js | 15 ++++++++++++--- types/easymde-test.ts | 29 ++++++++++++++++++++++++++--- types/easymde.d.ts | 34 +++++++++++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/css/easymde.css b/src/css/easymde.css index 20a60fc..92cf821 100644 --- a/src/css/easymde.css +++ b/src/css/easymde.css @@ -320,7 +320,7 @@ .editor-toolbar .easymde-dropdown { position: relative; background: linear-gradient(to bottom right, #fff 0%, #fff 84%, #333 50%, #333 100%); - border-radius: 0px; + border-radius: 0; border: 1px solid #fff; } @@ -332,7 +332,7 @@ display: none; position: absolute; background-color: #f9f9f9; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); padding: 8px; z-index: 2; top: 30px; diff --git a/src/js/easymde.js b/src/js/easymde.js index 642dcb5..761f604 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -119,8 +119,17 @@ function createToolbarDropdown(options, enableTooltips, shortcuts, parent) { var content = document.createElement('div'); content.className = 'easymde-dropdown-content'; for (var childrenIndex = 0; childrenIndex < options.children.length; childrenIndex++) { - var child = createToolbarButton(options.children[childrenIndex], true, enableTooltips, shortcuts, 'button', parent); - content.appendChild(child); + + var child = options.children[childrenIndex]; + var childElement; + + if (typeof child === 'string' && child in toolbarBuiltInButtons) { + childElement = createToolbarButton(toolbarBuiltInButtons[child], true, enableTooltips, shortcuts, 'button', parent); + } else { + childElement = createToolbarButton(child, true, enableTooltips, shortcuts, 'button', parent); + } + + content.appendChild(childElement); } el.appendChild(content); return el; @@ -1791,7 +1800,7 @@ EasyMDE.prototype.markdown = function (text) { // Convert the markdown to HTML var htmlText = marked(text); - + // Sanitize HTML if (this.options.renderingConfig && typeof this.options.renderingConfig.sanitizerFunction === 'function') { htmlText = this.options.renderingConfig.sanitizerFunction.call(this, htmlText); diff --git a/types/easymde-test.ts b/types/easymde-test.ts index cc08210..63cfb1d 100644 --- a/types/easymde-test.ts +++ b/types/easymde-test.ts @@ -43,18 +43,18 @@ const editor2 = new EasyMDE({ { name: 'bold', action: EasyMDE.toggleBold, - className: 'fa fa-bolt', + className: 'fa fas fa-bolt', title: 'Bold' }, '|', + 'undo', { - // Separator name: 'alert', action: (editor: EasyMDE) => { alert('This is from a custom button action!'); // Custom functions have access to the `editor` instance. }, - className: 'fa fa-star', + className: 'fa fas fa-star', title: 'A Custom Button', noDisable: undefined, noMobile: false @@ -67,6 +67,29 @@ const editor2 = new EasyMDE({ title: 'A Custom Link', noDisable: true, noMobile: true + }, + 'preview', + { + name: 'links', + className: 'fa fas fa-arrow-down', + title: 'A Custom Link', + children: [ + { + name: 'link', + action: 'https://github.com/Ionaru/easy-markdown-editor', + className: 'fa fab fa-github', + title: 'A Custom Link', + noDisable: true, + noMobile: true + }, + 'preview', + { + name: 'bold', + action: EasyMDE.toggleBold, + className: 'fa fas fa-bold', + title: 'Bold' + }, + ] } ] }); diff --git a/types/easymde.d.ts b/types/easymde.d.ts index 9391416..0ef9e53 100644 --- a/types/easymde.d.ts +++ b/types/easymde.d.ts @@ -22,6 +22,29 @@ /// /// +interface ArrayOneOrMore extends Array { + 0: T +} + +type ToolbarButton = + 'strikethrough' + | 'code' + | 'table' + | 'redo' + | 'heading' + | 'undo' + | 'heading-bigger' + | 'heading-smaller' + | 'heading-1' + | 'heading-2' + | 'heading-3' + | 'clean-block' + | 'horizontal-rule' + | 'preview' + | 'side-by-side' + | 'fullscreen' + | 'guide'; + declare namespace EasyMDE { interface AutoSaveOptions { enabled?: boolean; @@ -87,6 +110,15 @@ declare namespace EasyMDE { onUpdate: (element: HTMLElement) => void; } + interface ToolbarDropdownIcon { + name: string; + children: ArrayOneOrMore; + className: string; + title: string; + noDisable?: boolean; + noMobile?: boolean; + } + interface ToolbarIcon { name: string; action: string | ((editor: EasyMDE) => void); @@ -139,7 +171,7 @@ declare namespace EasyMDE { status?: boolean | ReadonlyArray; styleSelectedText?: boolean; tabSize?: number; - toolbar?: boolean | ReadonlyArray<'|' | ToolbarIcon>; + toolbar?: boolean | ReadonlyArray<'|' | ToolbarButton | ToolbarIcon | ToolbarDropdownIcon>; toolbarTips?: boolean; onToggleFullScreen?: (goingIntoFullScreen: boolean) => void; theme?: string;