/*! * HyperMD, copyright (c) by laobubu * Distributed under an MIT license: http://laobubu.net/HyperMD/LICENSE * * Break the Wall between writing and preview, in a Markdown Editor. * * HyperMD makes Markdown editor on web WYSIWYG, based on CodeMirror * * Homepage: http://laobubu.net/HyperMD/ * Issues: https://github.com/laobubu/HyperMD/issues */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('codemirror'), require('codemirror/addon/fold/foldcode'), require('codemirror/addon/fold/foldgutter'), require('codemirror/addon/fold/markdown-fold'), require('codemirror/addon/edit/closebrackets'), require('codemirror/lib/codemirror.css'), require('codemirror/addon/fold/foldgutter.css'), require('./theme/hypermd-light.css')) : typeof define === 'function' && define.amd ? define(['exports', 'codemirror', 'codemirror/addon/fold/foldcode', 'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/markdown-fold', 'codemirror/addon/edit/closebrackets', 'codemirror/lib/codemirror.css', 'codemirror/addon/fold/foldgutter.css', './theme/hypermd-light.css'], factory) : (factory((global.HyperMD = {}),global.CodeMirror)); }(this, (function (exports,CodeMirror) { 'use strict'; /** * Provides some common PolyFill * * @internal Part of HyperMD core. * * You shall NOT import this file; please import "core" instead */ if (typeof Object['assign'] != 'function') { // Must be writable: true, enumerable: false, configurable: true Object.defineProperty(Object, "assign", { value: function assign(target, varArgs) { var arguments$1 = arguments; if (target == null) { // TypeError if undefined or null throw new TypeError('Cannot convert undefined or null to object'); } var to = Object(target); for (var index = 1; index < arguments.length; index++) { var nextSource = arguments$1[index]; if (nextSource != null) { // Skip over if undefined or null for (var nextKey in nextSource) { // Avoid bugs when hasOwnProperty is shadowed if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { to[nextKey] = nextSource[nextKey]; } } } } return to; }, writable: true, configurable: true }); } /** * Provides some universal utils * * @internal Part of HyperMD core. * * You shall NOT import this file; please import "core" instead */ /** Simple FlipFlop */ var FlipFlop = function(on_cb, off_cb, state, subkey) { if ( state === void 0 ) state = false; if ( subkey === void 0 ) subkey = "enabled"; this.on_cb = on_cb; this.off_cb = off_cb; this.state = state; this.subkey = subkey; }; /** set a callback when state is changed and is **NOT** `null`, `false` etc. */ FlipFlop.prototype.ON = function (callback) { this.on_cb = callback; return this; }; /** set a callback when state is set to `null`, `false` etc. */ FlipFlop.prototype.OFF = function (callback) { this.off_cb = callback; return this; }; /** * Update FlipFlop status, and trig callback function if needed * * @param {T|object} state new status value. can be a object * @param {boolean} [toBool] convert retrived value to boolean. default: false */ FlipFlop.prototype.set = function (state, toBool) { var newVal = (typeof state === 'object' && state) ? state[this.subkey] : state; if (toBool) { newVal = !!newVal; } if (newVal === this.state) { return; } if (this.state = newVal) { this.on_cb && this.on_cb(newVal); } else { this.off_cb && this.off_cb(newVal); } }; FlipFlop.prototype.setBool = function (state) { return this.set(state, true); }; /** * Bind to a object's property with `Object.defineProperty` * so that you may set state with `obj.enable = true` */ FlipFlop.prototype.bind = function (obj, key, toBool) { var this$1 = this; Object.defineProperty(obj, key, { get: function () { return this$1.state; }, set: function (v) { return this$1.set(v, toBool); }, configurable: true, enumerable: true, }); return this; }; /** async run a function, and retry up to N times until it returns true */ function tryToRun(fn, times, onFailed) { times = ~~times || 5; var delayTime = 250; function nextCycle() { if (!times--) { if (onFailed) { onFailed(); } return; } try { if (fn()) { return; } } catch (e) { } setTimeout(nextCycle, delayTime); delayTime *= 2; } setTimeout(nextCycle, 0); } /** * make a debounced function * * @param {Function} fn * @param {number} delay in ms */ function debounce(fn, delay) { var deferTask = null; var notClearBefore = 0; var run = function () { fn(); deferTask = 0; }; var ans = function () { var nowTime = +new Date(); if (deferTask) { if (nowTime < notClearBefore) { return; } else { clearTimeout(deferTask); } } deferTask = setTimeout(run, delay); notClearBefore = nowTime + 100; // allow 100ms error }; ans.stop = function () { if (!deferTask) { return; } clearTimeout(deferTask); deferTask = 0; }; return ans; } /** * addClass / removeClass etc. * * using CodeMirror's (although they're legacy API) */ var addClass = CodeMirror.addClass; var rmClass = CodeMirror.rmClass; var contains = CodeMirror.contains; /** * a fallback for new Array(count).fill(data) */ function repeat(item, count) { var ans = new Array(count); if (ans['fill']) { ans['fill'](item); } else { for (var i = 0; i < count; i++) { ans[i] = item; } } return ans; } function repeatStr(item, count) { var ans = ""; while (count-- > 0) { ans += item; } return ans; } /** * Visit element nodes and their children */ function visitElements(seeds, handler) { var queue = [seeds], tmp; while (tmp = queue.shift()) { for (var i = 0; i < tmp.length; i++) { var el = tmp[i]; if (!el || el.nodeType != Node.ELEMENT_NODE) { continue; } handler(el); if (el.children && el.children.length > 0) { queue.push(el.children); } } } } /** * A lazy and simple Element size watcher. NOT WORK with animations */ function watchSize(el, onChange, needPoll) { var ref = el.getBoundingClientRect(); var width = ref.width; var height = ref.height; /** check size and trig onChange */ var check = debounce(function () { var rect = el.getBoundingClientRect(); var newWidth = rect.width; var newHeight = rect.height; if (width != newWidth || height != newHeight) { onChange(newWidth, newHeight, width, height); width = newWidth; height = newHeight; setTimeout(check, 200); // maybe changed again later? } }, 100); var nextTimer = null; function pollOnce() { if (nextTimer) { clearTimeout(nextTimer); } if (!stopped) { nextTimer = setTimeout(pollOnce, 200); } check(); } var stopped = false; function stop() { stopped = true; check.stop(); if (nextTimer) { clearTimeout(nextTimer); nextTimer = null; } for (var i = 0; i < eventBinded.length; i++) { eventBinded[i][0].removeEventListener(eventBinded[i][1], check, false); } } var eventBinded = []; function bindEvents(el) { var tagName = el.tagName; var computedStyle = getComputedStyle(el); var getStyle = function (name) { return (computedStyle.getPropertyValue(name) || ''); }; if (getStyle("resize") != 'none') { needPoll = true; } // size changes if loaded if (/^(?:img|video)$/i.test(tagName)) { el.addEventListener('load', check, false); el.addEventListener('error', check, false); } else if (/^(?:details|summary)$/i.test(tagName)) { el.addEventListener('click', check, false); } } if (!needPoll) { visitElements([el], bindEvents); } // bindEvents will update `needPoll` if (needPoll) { nextTimer = setTimeout(pollOnce, 200); } return { check: check, stop: stop, }; } function makeSymbol(name) { if (typeof Symbol === 'function') { return Symbol(name); } return "_\n" + name + "\n_" + Math.floor(Math.random() * 0xFFFF).toString(16); } /** * Ready-to-use functions that powers up your Markdown editor * * @internal Part of HyperMD core. * * You shall NOT import this file; please import "core" instead */ // if (HyperMD_Mark in editor), the editor was a HyperMD mode at least once var HyperMD_Mark = '__hypermd__'; /** * The default configuration that used by `HyperMD.fromTextArea` * * Addons may update this object freely! */ var suggestedEditorConfig = { lineNumbers: true, lineWrapping: true, theme: "hypermd-light", mode: "text/x-hypermd", tabSize: 4, autoCloseBrackets: true, foldGutter: true, gutters: [ "CodeMirror-linenumbers", "CodeMirror-foldgutter", "HyperMD-goback" // (addon: click) 'back' button for footnotes ], }; /** * Editor Options that disable HyperMD WYSIWYG visual effects. * These option will be applied when user invoke `switchToNormal`. * * Addons about visual effects, shall update this object! */ var normalVisualConfig = { theme: "default", }; /** * Initialize an editor from a