diff --git a/CHANGELOG.md b/CHANGELOG.md index ba9839a..2ee588f 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]). - `sanitizerFunction` option to allow custom HTML sanitizing in the markdown preview (Thanks to [@adamb70], [#147]). ### Changed - Delay before assuming that submit of the form as failed is `autosave.submit_delay` instead of `autosave.delay` (Thanks to [@Situphen], [#139]). diff --git a/README.md b/README.md index 01a1ef5..44b4fd9 100644 --- a/README.md +++ b/README.md @@ -351,6 +351,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..92cf821 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,12 +116,11 @@ padding: 0; } -.editor-toolbar button { +.editor-toolbar button, .editor-toolbar .easymde-dropdown { background: transparent; display: inline-block; text-align: center; text-decoration: none !important; - width: 30px; height: 30px; margin: 0; padding: 0; @@ -133,6 +129,10 @@ cursor: pointer; } +.editor-toolbar button { + width: 30px; +} + .editor-toolbar button.active, .editor-toolbar button:hover { background: #fcfcfc; @@ -316,3 +316,29 @@ color: #7f8c8d; font-style: italic; } + +.editor-toolbar .easymde-dropdown { + position: relative; + background: linear-gradient(to bottom right, #fff 0%, #fff 84%, #333 50%, #333 100%); + border-radius: 0; + 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 { + display: none; + position: absolute; + background-color: #f9f9f9; + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); + padding: 8px; + z-index: 2; + top: 30px; +} + +.easymde-dropdown:active .easymde-dropdown-content, +.easymde-dropdown:focus .easymde-dropdown-content { + display: block; +} diff --git a/src/js/easymde.js b/src/js/easymde.js index 5e4d8ce..761f604 100644 --- a/src/js/easymde.js +++ b/src/js/easymde.js @@ -110,15 +110,39 @@ function fixShortcut(name) { return name; } +/** + * Create dropdown block + */ +function createToolbarDropdown(options, enableTooltips, shortcuts, 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 = 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; +} /** * Create button element for toolbar. */ -function createToolbarButton(options, enableTooltips, shortcuts) { +function createToolbarButton(options, enableActions, 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 +191,20 @@ function createToolbarButton(options, enableTooltips, shortcuts) { } el.appendChild(icon); + if (options.action && enableActions) { + 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; } @@ -1762,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); @@ -2258,24 +2296,12 @@ 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 { - el = createToolbarButton(item, self.options.toolbarTips, self.options.shortcuts); + el = createToolbarButton(item, true, self.options.toolbarTips, self.options.shortcuts, 'button', self); } - // 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'); - }; - } - } toolbarData[item.name || item] = el; bar.appendChild(el); 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;