From 5fdda042e1fe5df032661c0995d740e463ac03b7 Mon Sep 17 00:00:00 2001 From: Zzzul Date: Sat, 21 Sep 2024 14:47:33 +0700 Subject: [PATCH] update meta tag and fix typo :sunflower: --- docs/.vitepress/cache/deps/package.json | 3 - .../deps/vitepress___@vueuse_core.js.map | 7 - .../vitepress___mark__js_src_vanilla__js.js | 1665 ----------------- ...itepress___mark__js_src_vanilla__js.js.map | 7 - docs/.vitepress/cache/deps/vue.js.map | 7 - docs/0.2.3/sponsors.md | 4 +- docs/0.2.3/usage.md | 13 + docs/contributions.md | 4 +- docs/features.md | 9 +- docs/get-started.md | 17 + docs/id/0.2.3/features.md | 14 +- docs/id/0.2.3/getting-started.md | 14 +- docs/id/0.2.3/how-to-contribute.md | 16 +- docs/id/0.2.3/index.md | 6 +- docs/id/0.2.3/sponsors.md | 20 +- docs/id/0.2.3/usage.md | 15 +- docs/id/contributions.md | 8 +- docs/id/features.md | 23 +- docs/id/introduction.md | 4 +- docs/id/sponsors.md | 7 +- docs/id/upgrade-guide.md | 271 +-- docs/id/usage.md | 14 + docs/introduction.md | 13 + docs/sponsors.md | 2 +- docs/upgrade-guide.md | 27 +- docs/usage.md | 14 + 26 files changed, 357 insertions(+), 1847 deletions(-) delete mode 100644 docs/.vitepress/cache/deps/package.json delete mode 100644 docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map delete mode 100644 docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js delete mode 100644 docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map delete mode 100644 docs/.vitepress/cache/deps/vue.js.map diff --git a/docs/.vitepress/cache/deps/package.json b/docs/.vitepress/cache/deps/package.json deleted file mode 100644 index 3dbc1ca..0000000 --- a/docs/.vitepress/cache/deps/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map b/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map deleted file mode 100644 index 9865211..0000000 --- a/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": [], - "sourcesContent": [], - "mappings": "", - "names": [] -} diff --git a/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js b/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js deleted file mode 100644 index cdaee94..0000000 --- a/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +++ /dev/null @@ -1,1665 +0,0 @@ -// node_modules/mark.js/src/lib/domiterator.js -var DOMIterator = class _DOMIterator { - /** - * @param {HTMLElement|HTMLElement[]|NodeList|string} ctx - The context DOM - * element, an array of DOM elements, a NodeList or a selector - * @param {boolean} [iframes=true] - A boolean indicating if iframes should - * be handled - * @param {string[]} [exclude=[]] - An array containing exclusion selectors - * for iframes - * @param {number} [iframesTimeout=5000] - A number indicating the ms to - * wait before an iframe should be skipped, in case the load event isn't - * fired. This also applies if the user is offline and the resource of the - * iframe is online (either by the browsers "offline" mode or because - * there's no internet connection) - */ - constructor(ctx, iframes = true, exclude = [], iframesTimeout = 5e3) { - this.ctx = ctx; - this.iframes = iframes; - this.exclude = exclude; - this.iframesTimeout = iframesTimeout; - } - /** - * Checks if the specified DOM element matches the selector - * @param {HTMLElement} element - The DOM element - * @param {string|string[]} selector - The selector or an array with - * selectors - * @return {boolean} - * @access public - */ - static matches(element, selector) { - const selectors = typeof selector === "string" ? [selector] : selector, fn = element.matches || element.matchesSelector || element.msMatchesSelector || element.mozMatchesSelector || element.oMatchesSelector || element.webkitMatchesSelector; - if (fn) { - let match = false; - selectors.every((sel) => { - if (fn.call(element, sel)) { - match = true; - return false; - } - return true; - }); - return match; - } else { - return false; - } - } - /** - * Returns all contexts filtered by duplicates (even nested) - * @return {HTMLElement[]} - An array containing DOM contexts - * @access protected - */ - getContexts() { - let ctx, filteredCtx = []; - if (typeof this.ctx === "undefined" || !this.ctx) { - ctx = []; - } else if (NodeList.prototype.isPrototypeOf(this.ctx)) { - ctx = Array.prototype.slice.call(this.ctx); - } else if (Array.isArray(this.ctx)) { - ctx = this.ctx; - } else if (typeof this.ctx === "string") { - ctx = Array.prototype.slice.call( - document.querySelectorAll(this.ctx) - ); - } else { - ctx = [this.ctx]; - } - ctx.forEach((ctx2) => { - const isDescendant = filteredCtx.filter((contexts) => { - return contexts.contains(ctx2); - }).length > 0; - if (filteredCtx.indexOf(ctx2) === -1 && !isDescendant) { - filteredCtx.push(ctx2); - } - }); - return filteredCtx; - } - /** - * @callback DOMIterator~getIframeContentsSuccessCallback - * @param {HTMLDocument} contents - The contentDocument of the iframe - */ - /** - * Calls the success callback function with the iframe document. If it can't - * be accessed it calls the error callback function - * @param {HTMLElement} ifr - The iframe DOM element - * @param {DOMIterator~getIframeContentsSuccessCallback} successFn - * @param {function} [errorFn] - * @access protected - */ - getIframeContents(ifr, successFn, errorFn = () => { - }) { - let doc; - try { - const ifrWin = ifr.contentWindow; - doc = ifrWin.document; - if (!ifrWin || !doc) { - throw new Error("iframe inaccessible"); - } - } catch (e) { - errorFn(); - } - if (doc) { - successFn(doc); - } - } - /** - * Checks if an iframe is empty (if about:blank is the shown page) - * @param {HTMLElement} ifr - The iframe DOM element - * @return {boolean} - * @access protected - */ - isIframeBlank(ifr) { - const bl = "about:blank", src = ifr.getAttribute("src").trim(), href = ifr.contentWindow.location.href; - return href === bl && src !== bl && src; - } - /** - * Observes the onload event of an iframe and calls the success callback or - * the error callback if the iframe is inaccessible. If the event isn't - * fired within the specified {@link DOMIterator#iframesTimeout}, then it'll - * call the error callback too - * @param {HTMLElement} ifr - The iframe DOM element - * @param {DOMIterator~getIframeContentsSuccessCallback} successFn - * @param {function} errorFn - * @access protected - */ - observeIframeLoad(ifr, successFn, errorFn) { - let called = false, tout = null; - const listener = () => { - if (called) { - return; - } - called = true; - clearTimeout(tout); - try { - if (!this.isIframeBlank(ifr)) { - ifr.removeEventListener("load", listener); - this.getIframeContents(ifr, successFn, errorFn); - } - } catch (e) { - errorFn(); - } - }; - ifr.addEventListener("load", listener); - tout = setTimeout(listener, this.iframesTimeout); - } - /** - * Callback when the iframe is ready - * @callback DOMIterator~onIframeReadySuccessCallback - * @param {HTMLDocument} contents - The contentDocument of the iframe - */ - /** - * Callback if the iframe can't be accessed - * @callback DOMIterator~onIframeReadyErrorCallback - */ - /** - * Calls the callback if the specified iframe is ready for DOM access - * @param {HTMLElement} ifr - The iframe DOM element - * @param {DOMIterator~onIframeReadySuccessCallback} successFn - Success - * callback - * @param {DOMIterator~onIframeReadyErrorCallback} errorFn - Error callback - * @see {@link http://stackoverflow.com/a/36155560/3894981} for - * background information - * @access protected - */ - onIframeReady(ifr, successFn, errorFn) { - try { - if (ifr.contentWindow.document.readyState === "complete") { - if (this.isIframeBlank(ifr)) { - this.observeIframeLoad(ifr, successFn, errorFn); - } else { - this.getIframeContents(ifr, successFn, errorFn); - } - } else { - this.observeIframeLoad(ifr, successFn, errorFn); - } - } catch (e) { - errorFn(); - } - } - /** - * Callback when all iframes are ready for DOM access - * @callback DOMIterator~waitForIframesDoneCallback - */ - /** - * Iterates over all iframes and calls the done callback when all of them - * are ready for DOM access (including nested ones) - * @param {HTMLElement} ctx - The context DOM element - * @param {DOMIterator~waitForIframesDoneCallback} done - Done callback - */ - waitForIframes(ctx, done) { - let eachCalled = 0; - this.forEachIframe(ctx, () => true, (ifr) => { - eachCalled++; - this.waitForIframes(ifr.querySelector("html"), () => { - if (!--eachCalled) { - done(); - } - }); - }, (handled) => { - if (!handled) { - done(); - } - }); - } - /** - * Callback allowing to filter an iframe. Must return true when the element - * should remain, otherwise false - * @callback DOMIterator~forEachIframeFilterCallback - * @param {HTMLElement} iframe - The iframe DOM element - */ - /** - * Callback for each iframe content - * @callback DOMIterator~forEachIframeEachCallback - * @param {HTMLElement} content - The iframe document - */ - /** - * Callback if all iframes inside the context were handled - * @callback DOMIterator~forEachIframeEndCallback - * @param {number} handled - The number of handled iframes (those who - * wheren't filtered) - */ - /** - * Iterates over all iframes inside the specified context and calls the - * callbacks when they're ready. Filters iframes based on the instance - * exclusion selectors - * @param {HTMLElement} ctx - The context DOM element - * @param {DOMIterator~forEachIframeFilterCallback} filter - Filter callback - * @param {DOMIterator~forEachIframeEachCallback} each - Each callback - * @param {DOMIterator~forEachIframeEndCallback} [end] - End callback - * @access protected - */ - forEachIframe(ctx, filter, each, end = () => { - }) { - let ifr = ctx.querySelectorAll("iframe"), open = ifr.length, handled = 0; - ifr = Array.prototype.slice.call(ifr); - const checkEnd = () => { - if (--open <= 0) { - end(handled); - } - }; - if (!open) { - checkEnd(); - } - ifr.forEach((ifr2) => { - if (_DOMIterator.matches(ifr2, this.exclude)) { - checkEnd(); - } else { - this.onIframeReady(ifr2, (con) => { - if (filter(ifr2)) { - handled++; - each(con); - } - checkEnd(); - }, checkEnd); - } - }); - } - /** - * Creates a NodeIterator on the specified context - * @see {@link https://developer.mozilla.org/en/docs/Web/API/NodeIterator} - * @param {HTMLElement} ctx - The context DOM element - * @param {DOMIterator~whatToShow} whatToShow - * @param {DOMIterator~filterCb} filter - * @return {NodeIterator} - * @access protected - */ - createIterator(ctx, whatToShow, filter) { - return document.createNodeIterator(ctx, whatToShow, filter, false); - } - /** - * Creates an instance of DOMIterator in an iframe - * @param {HTMLDocument} contents - Iframe document - * @return {DOMIterator} - * @access protected - */ - createInstanceOnIframe(contents) { - return new _DOMIterator(contents.querySelector("html"), this.iframes); - } - /** - * Checks if an iframe occurs between two nodes, more specifically if an - * iframe occurs before the specified node and after the specified prevNode - * @param {HTMLElement} node - The node that should occur after the iframe - * @param {HTMLElement} prevNode - The node that should occur before the - * iframe - * @param {HTMLElement} ifr - The iframe to check against - * @return {boolean} - * @access protected - */ - compareNodeIframe(node, prevNode, ifr) { - const compCurr = node.compareDocumentPosition(ifr), prev = Node.DOCUMENT_POSITION_PRECEDING; - if (compCurr & prev) { - if (prevNode !== null) { - const compPrev = prevNode.compareDocumentPosition(ifr), after = Node.DOCUMENT_POSITION_FOLLOWING; - if (compPrev & after) { - return true; - } - } else { - return true; - } - } - return false; - } - /** - * @typedef {DOMIterator~getIteratorNodeReturn} - * @type {object.} - * @property {HTMLElement} prevNode - The previous node or null if there is - * no - * @property {HTMLElement} node - The current node - */ - /** - * Returns the previous and current node of the specified iterator - * @param {NodeIterator} itr - The iterator - * @return {DOMIterator~getIteratorNodeReturn} - * @access protected - */ - getIteratorNode(itr) { - const prevNode = itr.previousNode(); - let node; - if (prevNode === null) { - node = itr.nextNode(); - } else { - node = itr.nextNode() && itr.nextNode(); - } - return { - prevNode, - node - }; - } - /** - * An array containing objects. The object key "val" contains an iframe - * DOM element. The object key "handled" contains a boolean indicating if - * the iframe was handled already. - * It wouldn't be enough to save all open or all already handled iframes. - * The information of open iframes is necessary because they may occur after - * all other text nodes (and compareNodeIframe would never be true). The - * information of already handled iframes is necessary as otherwise they may - * be handled multiple times - * @typedef DOMIterator~checkIframeFilterIfr - * @type {object[]} - */ - /** - * Checks if an iframe wasn't handled already and if so, calls - * {@link DOMIterator#compareNodeIframe} to check if it should be handled. - * Information wheter an iframe was or wasn't handled is given within the - * ifr dictionary - * @param {HTMLElement} node - The node that should occur after the iframe - * @param {HTMLElement} prevNode - The node that should occur before the - * iframe - * @param {HTMLElement} currIfr - The iframe to check - * @param {DOMIterator~checkIframeFilterIfr} ifr - The iframe dictionary. - * Will be manipulated (by reference) - * @return {boolean} Returns true when it should be handled, otherwise false - * @access protected - */ - checkIframeFilter(node, prevNode, currIfr, ifr) { - let key = false, handled = false; - ifr.forEach((ifrDict, i) => { - if (ifrDict.val === currIfr) { - key = i; - handled = ifrDict.handled; - } - }); - if (this.compareNodeIframe(node, prevNode, currIfr)) { - if (key === false && !handled) { - ifr.push({ - val: currIfr, - handled: true - }); - } else if (key !== false && !handled) { - ifr[key].handled = true; - } - return true; - } - if (key === false) { - ifr.push({ - val: currIfr, - handled: false - }); - } - return false; - } - /** - * Creates an iterator on all open iframes in the specified array and calls - * the end callback when finished - * @param {DOMIterator~checkIframeFilterIfr} ifr - * @param {DOMIterator~whatToShow} whatToShow - * @param {DOMIterator~forEachNodeCallback} eCb - Each callback - * @param {DOMIterator~filterCb} fCb - * @access protected - */ - handleOpenIframes(ifr, whatToShow, eCb, fCb) { - ifr.forEach((ifrDict) => { - if (!ifrDict.handled) { - this.getIframeContents(ifrDict.val, (con) => { - this.createInstanceOnIframe(con).forEachNode( - whatToShow, - eCb, - fCb - ); - }); - } - }); - } - /** - * Iterates through all nodes in the specified context and handles iframe - * nodes at the correct position - * @param {DOMIterator~whatToShow} whatToShow - * @param {HTMLElement} ctx - The context - * @param {DOMIterator~forEachNodeCallback} eachCb - Each callback - * @param {DOMIterator~filterCb} filterCb - Filter callback - * @param {DOMIterator~forEachNodeEndCallback} doneCb - End callback - * @access protected - */ - iterateThroughNodes(whatToShow, ctx, eachCb, filterCb, doneCb) { - const itr = this.createIterator(ctx, whatToShow, filterCb); - let ifr = [], elements = [], node, prevNode, retrieveNodes = () => { - ({ - prevNode, - node - } = this.getIteratorNode(itr)); - return node; - }; - while (retrieveNodes()) { - if (this.iframes) { - this.forEachIframe(ctx, (currIfr) => { - return this.checkIframeFilter(node, prevNode, currIfr, ifr); - }, (con) => { - this.createInstanceOnIframe(con).forEachNode( - whatToShow, - (ifrNode) => elements.push(ifrNode), - filterCb - ); - }); - } - elements.push(node); - } - elements.forEach((node2) => { - eachCb(node2); - }); - if (this.iframes) { - this.handleOpenIframes(ifr, whatToShow, eachCb, filterCb); - } - doneCb(); - } - /** - * Callback for each node - * @callback DOMIterator~forEachNodeCallback - * @param {HTMLElement} node - The DOM text node element - */ - /** - * Callback if all contexts were handled - * @callback DOMIterator~forEachNodeEndCallback - */ - /** - * Iterates over all contexts and initializes - * {@link DOMIterator#iterateThroughNodes iterateThroughNodes} on them - * @param {DOMIterator~whatToShow} whatToShow - * @param {DOMIterator~forEachNodeCallback} each - Each callback - * @param {DOMIterator~filterCb} filter - Filter callback - * @param {DOMIterator~forEachNodeEndCallback} done - End callback - * @access public - */ - forEachNode(whatToShow, each, filter, done = () => { - }) { - const contexts = this.getContexts(); - let open = contexts.length; - if (!open) { - done(); - } - contexts.forEach((ctx) => { - const ready = () => { - this.iterateThroughNodes(whatToShow, ctx, each, filter, () => { - if (--open <= 0) { - done(); - } - }); - }; - if (this.iframes) { - this.waitForIframes(ctx, ready); - } else { - ready(); - } - }); - } - /** - * Callback to filter nodes. Can return e.g. NodeFilter.FILTER_ACCEPT or - * NodeFilter.FILTER_REJECT - * @see {@link http://tinyurl.com/zdczmm2} - * @callback DOMIterator~filterCb - * @param {HTMLElement} node - The node to filter - */ - /** - * @typedef DOMIterator~whatToShow - * @see {@link http://tinyurl.com/zfqqkx2} - * @type {number} - */ -}; - -// node_modules/mark.js/src/lib/mark.js -var Mark = class { - // eslint-disable-line no-unused-vars - /** - * @param {HTMLElement|HTMLElement[]|NodeList|string} ctx - The context DOM - * element, an array of DOM elements, a NodeList or a selector - */ - constructor(ctx) { - this.ctx = ctx; - this.ie = false; - const ua = window.navigator.userAgent; - if (ua.indexOf("MSIE") > -1 || ua.indexOf("Trident") > -1) { - this.ie = true; - } - } - /** - * Options defined by the user. They will be initialized from one of the - * public methods. See {@link Mark#mark}, {@link Mark#markRegExp}, - * {@link Mark#markRanges} and {@link Mark#unmark} for option properties. - * @type {object} - * @param {object} [val] - An object that will be merged with defaults - * @access protected - */ - set opt(val) { - this._opt = Object.assign({}, { - "element": "", - "className": "", - "exclude": [], - "iframes": false, - "iframesTimeout": 5e3, - "separateWordSearch": true, - "diacritics": true, - "synonyms": {}, - "accuracy": "partially", - "acrossElements": false, - "caseSensitive": false, - "ignoreJoiners": false, - "ignoreGroups": 0, - "ignorePunctuation": [], - "wildcards": "disabled", - "each": () => { - }, - "noMatch": () => { - }, - "filter": () => true, - "done": () => { - }, - "debug": false, - "log": window.console - }, val); - } - get opt() { - return this._opt; - } - /** - * An instance of DOMIterator - * @type {DOMIterator} - * @access protected - */ - get iterator() { - return new DOMIterator( - this.ctx, - this.opt.iframes, - this.opt.exclude, - this.opt.iframesTimeout - ); - } - /** - * Logs a message if log is enabled - * @param {string} msg - The message to log - * @param {string} [level="debug"] - The log level, e.g. warn - * error, debug - * @access protected - */ - log(msg, level = "debug") { - const log = this.opt.log; - if (!this.opt.debug) { - return; - } - if (typeof log === "object" && typeof log[level] === "function") { - log[level](`mark.js: ${msg}`); - } - } - /** - * Escapes a string for usage within a regular expression - * @param {string} str - The string to escape - * @return {string} - * @access protected - */ - escapeStr(str) { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); - } - /** - * Creates a regular expression string to match the specified search - * term including synonyms, diacritics and accuracy if defined - * @param {string} str - The search term to be used - * @return {string} - * @access protected - */ - createRegExp(str) { - if (this.opt.wildcards !== "disabled") { - str = this.setupWildcardsRegExp(str); - } - str = this.escapeStr(str); - if (Object.keys(this.opt.synonyms).length) { - str = this.createSynonymsRegExp(str); - } - if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { - str = this.setupIgnoreJoinersRegExp(str); - } - if (this.opt.diacritics) { - str = this.createDiacriticsRegExp(str); - } - str = this.createMergedBlanksRegExp(str); - if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { - str = this.createJoinersRegExp(str); - } - if (this.opt.wildcards !== "disabled") { - str = this.createWildcardsRegExp(str); - } - str = this.createAccuracyRegExp(str); - return str; - } - /** - * Creates a regular expression string to match the defined synonyms - * @param {string} str - The search term to be used - * @return {string} - * @access protected - */ - createSynonymsRegExp(str) { - const syn = this.opt.synonyms, sens = this.opt.caseSensitive ? "" : "i", joinerPlaceholder = this.opt.ignoreJoiners || this.opt.ignorePunctuation.length ? "\0" : ""; - for (let index in syn) { - if (syn.hasOwnProperty(index)) { - const value = syn[index], k1 = this.opt.wildcards !== "disabled" ? this.setupWildcardsRegExp(index) : this.escapeStr(index), k2 = this.opt.wildcards !== "disabled" ? this.setupWildcardsRegExp(value) : this.escapeStr(value); - if (k1 !== "" && k2 !== "") { - str = str.replace( - new RegExp( - `(${this.escapeStr(k1)}|${this.escapeStr(k2)})`, - `gm${sens}` - ), - joinerPlaceholder + `(${this.processSynomyms(k1)}|${this.processSynomyms(k2)})` + joinerPlaceholder - ); - } - } - } - return str; - } - /** - * Setup synonyms to work with ignoreJoiners and or ignorePunctuation - * @param {string} str - synonym key or value to process - * @return {string} - processed synonym string - */ - processSynomyms(str) { - if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) { - str = this.setupIgnoreJoinersRegExp(str); - } - return str; - } - /** - * Sets up the regular expression string to allow later insertion of - * wildcard regular expression matches - * @param {string} str - The search term to be used - * @return {string} - * @access protected - */ - setupWildcardsRegExp(str) { - str = str.replace(/(?:\\)*\?/g, (val) => { - return val.charAt(0) === "\\" ? "?" : ""; - }); - return str.replace(/(?:\\)*\*/g, (val) => { - return val.charAt(0) === "\\" ? "*" : ""; - }); - } - /** - * Sets up the regular expression string to allow later insertion of - * wildcard regular expression matches - * @param {string} str - The search term to be used - * @return {string} - * @access protected - */ - createWildcardsRegExp(str) { - let spaces = this.opt.wildcards === "withSpaces"; - return str.replace(/\u0001/g, spaces ? "[\\S\\s]?" : "\\S?").replace(/\u0002/g, spaces ? "[\\S\\s]*?" : "\\S*"); - } - /** - * Sets up the regular expression string to allow later insertion of - * designated characters (soft hyphens & zero width characters) - * @param {string} str - The search term to be used - * @return {string} - * @access protected - */ - setupIgnoreJoinersRegExp(str) { - return str.replace(/[^(|)\\]/g, (val, indx, original) => { - let nextChar = original.charAt(indx + 1); - if (/[(|)\\]/.test(nextChar) || nextChar === "") { - return val; - } else { - return val + "\0"; - } - }); - } - /** - * Creates a regular expression string to allow ignoring of designated - * characters (soft hyphens, zero width characters & punctuation) based on - * the specified option values of ignorePunctuation and - * ignoreJoiners - * @param {string} str - The search term to be used - * @return {string} - * @access protected - */ - createJoinersRegExp(str) { - let joiner = []; - const ignorePunctuation = this.opt.ignorePunctuation; - if (Array.isArray(ignorePunctuation) && ignorePunctuation.length) { - joiner.push(this.escapeStr(ignorePunctuation.join(""))); - } - if (this.opt.ignoreJoiners) { - joiner.push("\\u00ad\\u200b\\u200c\\u200d"); - } - return joiner.length ? str.split(/\u0000+/).join(`[${joiner.join("")}]*`) : str; - } - /** - * Creates a regular expression string to match diacritics - * @param {string} str - The search term to be used - * @return {string} - * @access protected - */ - createDiacriticsRegExp(str) { - const sens = this.opt.caseSensitive ? "" : "i", dct = this.opt.caseSensitive ? [ - "aàáảãạăằắẳẵặâầấẩẫậäåāą", - "AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ", - "cçćč", - "CÇĆČ", - "dđď", - "DĐĎ", - "eèéẻẽẹêềếểễệëěēę", - "EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ", - "iìíỉĩịîïī", - "IÌÍỈĨỊÎÏĪ", - "lł", - "LŁ", - "nñňń", - "NÑŇŃ", - "oòóỏõọôồốổỗộơởỡớờợöøō", - "OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ", - "rř", - "RŘ", - "sšśșş", - "SŠŚȘŞ", - "tťțţ", - "TŤȚŢ", - "uùúủũụưừứửữựûüůū", - "UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ", - "yýỳỷỹỵÿ", - "YÝỲỶỸỴŸ", - "zžżź", - "ZŽŻŹ" - ] : [ - "aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ", - "cçćčCÇĆČ", - "dđďDĐĎ", - "eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ", - "iìíỉĩịîïīIÌÍỈĨỊÎÏĪ", - "lłLŁ", - "nñňńNÑŇŃ", - "oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ", - "rřRŘ", - "sšśșşSŠŚȘŞ", - "tťțţTŤȚŢ", - "uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ", - "yýỳỷỹỵÿYÝỲỶỸỴŸ", - "zžżźZŽŻŹ" - ]; - let handled = []; - str.split("").forEach((ch) => { - dct.every((dct2) => { - if (dct2.indexOf(ch) !== -1) { - if (handled.indexOf(dct2) > -1) { - return false; - } - str = str.replace( - new RegExp(`[${dct2}]`, `gm${sens}`), - `[${dct2}]` - ); - handled.push(dct2); - } - return true; - }); - }); - return str; - } - /** - * Creates a regular expression string that merges whitespace characters - * including subsequent ones into a single pattern, one or multiple - * whitespaces - * @param {string} str - The search term to be used - * @return {string} - * @access protected - */ - createMergedBlanksRegExp(str) { - return str.replace(/[\s]+/gmi, "[\\s]+"); - } - /** - * Creates a regular expression string to match the specified string with - * the defined accuracy. As in the regular expression of "exactly" can be - * a group containing a blank at the beginning, all regular expressions will - * be created with two groups. The first group can be ignored (may contain - * the said blank), the second contains the actual match - * @param {string} str - The searm term to be used - * @return {str} - * @access protected - */ - createAccuracyRegExp(str) { - const chars = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿"; - let acc = this.opt.accuracy, val = typeof acc === "string" ? acc : acc.value, ls = typeof acc === "string" ? [] : acc.limiters, lsJoin = ""; - ls.forEach((limiter) => { - lsJoin += `|${this.escapeStr(limiter)}`; - }); - switch (val) { - case "partially": - default: - return `()(${str})`; - case "complementary": - lsJoin = "\\s" + (lsJoin ? lsJoin : this.escapeStr(chars)); - return `()([^${lsJoin}]*${str}[^${lsJoin}]*)`; - case "exactly": - return `(^|\\s${lsJoin})(${str})(?=$|\\s${lsJoin})`; - } - } - /** - * @typedef Mark~separatedKeywords - * @type {object.} - * @property {array.} keywords - The list of keywords - * @property {number} length - The length - */ - /** - * Returns a list of keywords dependent on whether separate word search - * was defined. Also it filters empty keywords - * @param {array} sv - The array of keywords - * @return {Mark~separatedKeywords} - * @access protected - */ - getSeparatedKeywords(sv) { - let stack = []; - sv.forEach((kw) => { - if (!this.opt.separateWordSearch) { - if (kw.trim() && stack.indexOf(kw) === -1) { - stack.push(kw); - } - } else { - kw.split(" ").forEach((kwSplitted) => { - if (kwSplitted.trim() && stack.indexOf(kwSplitted) === -1) { - stack.push(kwSplitted); - } - }); - } - }); - return { - // sort because of https://git.io/v6USg - "keywords": stack.sort((a, b) => { - return b.length - a.length; - }), - "length": stack.length - }; - } - /** - * Check if a value is a number - * @param {number|string} value - the value to check; - * numeric strings allowed - * @return {boolean} - * @access protected - */ - isNumeric(value) { - return Number(parseFloat(value)) == value; - } - /** - * @typedef Mark~rangeObject - * @type {object} - * @property {number} start - The start position within the composite value - * @property {number} length - The length of the string to mark within the - * composite value. - */ - /** - * @typedef Mark~setOfRanges - * @type {object[]} - * @property {Mark~rangeObject} - */ - /** - * Returns a processed list of integer offset indexes that do not overlap - * each other, and remove any string values or additional elements - * @param {Mark~setOfRanges} array - unprocessed raw array - * @return {Mark~setOfRanges} - processed array with any invalid entries - * removed - * @throws Will throw an error if an array of objects is not passed - * @access protected - */ - checkRanges(array) { - if (!Array.isArray(array) || Object.prototype.toString.call(array[0]) !== "[object Object]") { - this.log("markRanges() will only accept an array of objects"); - this.opt.noMatch(array); - return []; - } - const stack = []; - let last = 0; - array.sort((a, b) => { - return a.start - b.start; - }).forEach((item) => { - let { start, end, valid } = this.callNoMatchOnInvalidRanges(item, last); - if (valid) { - item.start = start; - item.length = end - start; - stack.push(item); - last = end; - } - }); - return stack; - } - /** - * @typedef Mark~validObject - * @type {object} - * @property {number} start - The start position within the composite value - * @property {number} end - The calculated end position within the composite - * value. - * @property {boolean} valid - boolean value indicating that the start and - * calculated end range is valid - */ - /** - * Initial validation of ranges for markRanges. Preliminary checks are done - * to ensure the start and length values exist and are not zero or non- - * numeric - * @param {Mark~rangeObject} range - the current range object - * @param {number} last - last index of range - * @return {Mark~validObject} - * @access protected - */ - callNoMatchOnInvalidRanges(range, last) { - let start, end, valid = false; - if (range && typeof range.start !== "undefined") { - start = parseInt(range.start, 10); - end = start + parseInt(range.length, 10); - if (this.isNumeric(range.start) && this.isNumeric(range.length) && end - last > 0 && end - start > 0) { - valid = true; - } else { - this.log( - `Ignoring invalid or overlapping range: ${JSON.stringify(range)}` - ); - this.opt.noMatch(range); - } - } else { - this.log(`Ignoring invalid range: ${JSON.stringify(range)}`); - this.opt.noMatch(range); - } - return { - start, - end, - valid - }; - } - /** - * Check valid range for markRanges. Check ranges with access to the context - * string. Range values are double checked, lengths that extend the mark - * beyond the string length are limitied and ranges containing only - * whitespace are ignored - * @param {Mark~rangeObject} range - the current range object - * @param {number} originalLength - original length of the context string - * @param {string} string - current content string - * @return {Mark~validObject} - * @access protected - */ - checkWhitespaceRanges(range, originalLength, string) { - let end, valid = true, max = string.length, offset = originalLength - max, start = parseInt(range.start, 10) - offset; - start = start > max ? max : start; - end = start + parseInt(range.length, 10); - if (end > max) { - end = max; - this.log(`End range automatically set to the max value of ${max}`); - } - if (start < 0 || end - start < 0 || start > max || end > max) { - valid = false; - this.log(`Invalid range: ${JSON.stringify(range)}`); - this.opt.noMatch(range); - } else if (string.substring(start, end).replace(/\s+/g, "") === "") { - valid = false; - this.log("Skipping whitespace only range: " + JSON.stringify(range)); - this.opt.noMatch(range); - } - return { - start, - end, - valid - }; - } - /** - * @typedef Mark~getTextNodesDict - * @type {object.} - * @property {string} value - The composite value of all text nodes - * @property {object[]} nodes - An array of objects - * @property {number} nodes.start - The start position within the composite - * value - * @property {number} nodes.end - The end position within the composite - * value - * @property {HTMLElement} nodes.node - The DOM text node element - */ - /** - * Callback - * @callback Mark~getTextNodesCallback - * @param {Mark~getTextNodesDict} - */ - /** - * Calls the callback with an object containing all text nodes (including - * iframe text nodes) with start and end positions and the composite value - * of them (string) - * @param {Mark~getTextNodesCallback} cb - Callback - * @access protected - */ - getTextNodes(cb) { - let val = "", nodes = []; - this.iterator.forEachNode(NodeFilter.SHOW_TEXT, (node) => { - nodes.push({ - start: val.length, - end: (val += node.textContent).length, - node - }); - }, (node) => { - if (this.matchesExclude(node.parentNode)) { - return NodeFilter.FILTER_REJECT; - } else { - return NodeFilter.FILTER_ACCEPT; - } - }, () => { - cb({ - value: val, - nodes - }); - }); - } - /** - * Checks if an element matches any of the specified exclude selectors. Also - * it checks for elements in which no marks should be performed (e.g. - * script and style tags) and optionally already marked elements - * @param {HTMLElement} el - The element to check - * @return {boolean} - * @access protected - */ - matchesExclude(el) { - return DOMIterator.matches(el, this.opt.exclude.concat([ - // ignores the elements itself, not their childrens (selector *) - "script", - "style", - "title", - "head", - "html" - ])); - } - /** - * Wraps the instance element and class around matches that fit the start - * and end positions within the node - * @param {HTMLElement} node - The DOM text node - * @param {number} start - The position where to start wrapping - * @param {number} end - The position where to end wrapping - * @return {HTMLElement} Returns the splitted text node that will appear - * after the wrapped text node - * @access protected - */ - wrapRangeInTextNode(node, start, end) { - const hEl = !this.opt.element ? "mark" : this.opt.element, startNode = node.splitText(start), ret = startNode.splitText(end - start); - let repl = document.createElement(hEl); - repl.setAttribute("data-markjs", "true"); - if (this.opt.className) { - repl.setAttribute("class", this.opt.className); - } - repl.textContent = startNode.textContent; - startNode.parentNode.replaceChild(repl, startNode); - return ret; - } - /** - * @typedef Mark~wrapRangeInMappedTextNodeDict - * @type {object.} - * @property {string} value - The composite value of all text nodes - * @property {object[]} nodes - An array of objects - * @property {number} nodes.start - The start position within the composite - * value - * @property {number} nodes.end - The end position within the composite - * value - * @property {HTMLElement} nodes.node - The DOM text node element - */ - /** - * Each callback - * @callback Mark~wrapMatchesEachCallback - * @param {HTMLElement} node - The wrapped DOM element - * @param {number} lastIndex - The last matching position within the - * composite value of text nodes - */ - /** - * Filter callback - * @callback Mark~wrapMatchesFilterCallback - * @param {HTMLElement} node - The matching text node DOM element - */ - /** - * Determines matches by start and end positions using the text node - * dictionary even across text nodes and calls - * {@link Mark#wrapRangeInTextNode} to wrap them - * @param {Mark~wrapRangeInMappedTextNodeDict} dict - The dictionary - * @param {number} start - The start position of the match - * @param {number} end - The end position of the match - * @param {Mark~wrapMatchesFilterCallback} filterCb - Filter callback - * @param {Mark~wrapMatchesEachCallback} eachCb - Each callback - * @access protected - */ - wrapRangeInMappedTextNode(dict, start, end, filterCb, eachCb) { - dict.nodes.every((n, i) => { - const sibl = dict.nodes[i + 1]; - if (typeof sibl === "undefined" || sibl.start > start) { - if (!filterCb(n.node)) { - return false; - } - const s = start - n.start, e = (end > n.end ? n.end : end) - n.start, startStr = dict.value.substr(0, n.start), endStr = dict.value.substr(e + n.start); - n.node = this.wrapRangeInTextNode(n.node, s, e); - dict.value = startStr + endStr; - dict.nodes.forEach((k, j) => { - if (j >= i) { - if (dict.nodes[j].start > 0 && j !== i) { - dict.nodes[j].start -= e; - } - dict.nodes[j].end -= e; - } - }); - end -= e; - eachCb(n.node.previousSibling, n.start); - if (end > n.end) { - start = n.end; - } else { - return false; - } - } - return true; - }); - } - /** - * Filter callback before each wrapping - * @callback Mark~wrapMatchesFilterCallback - * @param {string} match - The matching string - * @param {HTMLElement} node - The text node where the match occurs - */ - /** - * Callback for each wrapped element - * @callback Mark~wrapMatchesEachCallback - * @param {HTMLElement} element - The marked DOM element - */ - /** - * Callback on end - * @callback Mark~wrapMatchesEndCallback - */ - /** - * Wraps the instance element and class around matches within single HTML - * elements in all contexts - * @param {RegExp} regex - The regular expression to be searched for - * @param {number} ignoreGroups - A number indicating the amount of RegExp - * matching groups to ignore - * @param {Mark~wrapMatchesFilterCallback} filterCb - * @param {Mark~wrapMatchesEachCallback} eachCb - * @param {Mark~wrapMatchesEndCallback} endCb - * @access protected - */ - wrapMatches(regex, ignoreGroups, filterCb, eachCb, endCb) { - const matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1; - this.getTextNodes((dict) => { - dict.nodes.forEach((node) => { - node = node.node; - let match; - while ((match = regex.exec(node.textContent)) !== null && match[matchIdx] !== "") { - if (!filterCb(match[matchIdx], node)) { - continue; - } - let pos = match.index; - if (matchIdx !== 0) { - for (let i = 1; i < matchIdx; i++) { - pos += match[i].length; - } - } - node = this.wrapRangeInTextNode( - node, - pos, - pos + match[matchIdx].length - ); - eachCb(node.previousSibling); - regex.lastIndex = 0; - } - }); - endCb(); - }); - } - /** - * Callback for each wrapped element - * @callback Mark~wrapMatchesAcrossElementsEachCallback - * @param {HTMLElement} element - The marked DOM element - */ - /** - * Filter callback before each wrapping - * @callback Mark~wrapMatchesAcrossElementsFilterCallback - * @param {string} match - The matching string - * @param {HTMLElement} node - The text node where the match occurs - */ - /** - * Callback on end - * @callback Mark~wrapMatchesAcrossElementsEndCallback - */ - /** - * Wraps the instance element and class around matches across all HTML - * elements in all contexts - * @param {RegExp} regex - The regular expression to be searched for - * @param {number} ignoreGroups - A number indicating the amount of RegExp - * matching groups to ignore - * @param {Mark~wrapMatchesAcrossElementsFilterCallback} filterCb - * @param {Mark~wrapMatchesAcrossElementsEachCallback} eachCb - * @param {Mark~wrapMatchesAcrossElementsEndCallback} endCb - * @access protected - */ - wrapMatchesAcrossElements(regex, ignoreGroups, filterCb, eachCb, endCb) { - const matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1; - this.getTextNodes((dict) => { - let match; - while ((match = regex.exec(dict.value)) !== null && match[matchIdx] !== "") { - let start = match.index; - if (matchIdx !== 0) { - for (let i = 1; i < matchIdx; i++) { - start += match[i].length; - } - } - const end = start + match[matchIdx].length; - this.wrapRangeInMappedTextNode(dict, start, end, (node) => { - return filterCb(match[matchIdx], node); - }, (node, lastIndex) => { - regex.lastIndex = lastIndex; - eachCb(node); - }); - } - endCb(); - }); - } - /** - * Callback for each wrapped element - * @callback Mark~wrapRangeFromIndexEachCallback - * @param {HTMLElement} element - The marked DOM element - * @param {Mark~rangeObject} range - the current range object; provided - * start and length values will be numeric integers modified from the - * provided original ranges. - */ - /** - * Filter callback before each wrapping - * @callback Mark~wrapRangeFromIndexFilterCallback - * @param {HTMLElement} node - The text node which includes the range - * @param {Mark~rangeObject} range - the current range object - * @param {string} match - string extracted from the matching range - * @param {number} counter - A counter indicating the number of all marks - */ - /** - * Callback on end - * @callback Mark~wrapRangeFromIndexEndCallback - */ - /** - * Wraps the indicated ranges across all HTML elements in all contexts - * @param {Mark~setOfRanges} ranges - * @param {Mark~wrapRangeFromIndexFilterCallback} filterCb - * @param {Mark~wrapRangeFromIndexEachCallback} eachCb - * @param {Mark~wrapRangeFromIndexEndCallback} endCb - * @access protected - */ - wrapRangeFromIndex(ranges, filterCb, eachCb, endCb) { - this.getTextNodes((dict) => { - const originalLength = dict.value.length; - ranges.forEach((range, counter) => { - let { start, end, valid } = this.checkWhitespaceRanges( - range, - originalLength, - dict.value - ); - if (valid) { - this.wrapRangeInMappedTextNode(dict, start, end, (node) => { - return filterCb( - node, - range, - dict.value.substring(start, end), - counter - ); - }, (node) => { - eachCb(node, range); - }); - } - }); - endCb(); - }); - } - /** - * Unwraps the specified DOM node with its content (text nodes or HTML) - * without destroying possibly present events (using innerHTML) and - * normalizes the parent at the end (merge splitted text nodes) - * @param {HTMLElement} node - The DOM node to unwrap - * @access protected - */ - unwrapMatches(node) { - const parent = node.parentNode; - let docFrag = document.createDocumentFragment(); - while (node.firstChild) { - docFrag.appendChild(node.removeChild(node.firstChild)); - } - parent.replaceChild(docFrag, node); - if (!this.ie) { - parent.normalize(); - } else { - this.normalizeTextNode(parent); - } - } - /** - * Normalizes text nodes. It's a workaround for the native normalize method - * that has a bug in IE (see attached link). Should only be used in IE - * browsers as it's slower than the native method. - * @see {@link http://tinyurl.com/z5asa8c} - * @param {HTMLElement} node - The DOM node to normalize - * @access protected - */ - normalizeTextNode(node) { - if (!node) { - return; - } - if (node.nodeType === 3) { - while (node.nextSibling && node.nextSibling.nodeType === 3) { - node.nodeValue += node.nextSibling.nodeValue; - node.parentNode.removeChild(node.nextSibling); - } - } else { - this.normalizeTextNode(node.firstChild); - } - this.normalizeTextNode(node.nextSibling); - } - /** - * Callback when finished - * @callback Mark~commonDoneCallback - * @param {number} totalMatches - The number of marked elements - */ - /** - * @typedef Mark~commonOptions - * @type {object.} - * @property {string} [element="mark"] - HTML element tag name - * @property {string} [className] - An optional class name - * @property {string[]} [exclude] - An array with exclusion selectors. - * Elements matching those selectors will be ignored - * @property {boolean} [iframes=false] - Whether to search inside iframes - * @property {Mark~commonDoneCallback} [done] - * @property {boolean} [debug=false] - Wheter to log messages - * @property {object} [log=window.console] - Where to log messages (only if - * debug is true) - */ - /** - * Callback for each marked element - * @callback Mark~markRegExpEachCallback - * @param {HTMLElement} element - The marked DOM element - */ - /** - * Callback if there were no matches - * @callback Mark~markRegExpNoMatchCallback - * @param {RegExp} regexp - The regular expression - */ - /** - * Callback to filter matches - * @callback Mark~markRegExpFilterCallback - * @param {HTMLElement} textNode - The text node which includes the match - * @param {string} match - The matching string for the RegExp - * @param {number} counter - A counter indicating the number of all marks - */ - /** - * These options also include the common options from - * {@link Mark~commonOptions} - * @typedef Mark~markRegExpOptions - * @type {object.} - * @property {Mark~markRegExpEachCallback} [each] - * @property {Mark~markRegExpNoMatchCallback} [noMatch] - * @property {Mark~markRegExpFilterCallback} [filter] - */ - /** - * Marks a custom regular expression - * @param {RegExp} regexp - The regular expression - * @param {Mark~markRegExpOptions} [opt] - Optional options object - * @access public - */ - markRegExp(regexp, opt) { - this.opt = opt; - this.log(`Searching with expression "${regexp}"`); - let totalMatches = 0, fn = "wrapMatches"; - const eachCb = (element) => { - totalMatches++; - this.opt.each(element); - }; - if (this.opt.acrossElements) { - fn = "wrapMatchesAcrossElements"; - } - this[fn](regexp, this.opt.ignoreGroups, (match, node) => { - return this.opt.filter(node, match, totalMatches); - }, eachCb, () => { - if (totalMatches === 0) { - this.opt.noMatch(regexp); - } - this.opt.done(totalMatches); - }); - } - /** - * Callback for each marked element - * @callback Mark~markEachCallback - * @param {HTMLElement} element - The marked DOM element - */ - /** - * Callback if there were no matches - * @callback Mark~markNoMatchCallback - * @param {RegExp} term - The search term that was not found - */ - /** - * Callback to filter matches - * @callback Mark~markFilterCallback - * @param {HTMLElement} textNode - The text node which includes the match - * @param {string} match - The matching term - * @param {number} totalCounter - A counter indicating the number of all - * marks - * @param {number} termCounter - A counter indicating the number of marks - * for the specific match - */ - /** - * @typedef Mark~markAccuracyObject - * @type {object.} - * @property {string} value - A accuracy string value - * @property {string[]} limiters - A custom array of limiters. For example - * ["-", ","] - */ - /** - * @typedef Mark~markAccuracySetting - * @type {string} - * @property {"partially"|"complementary"|"exactly"|Mark~markAccuracyObject} - * [accuracy="partially"] - Either one of the following string values: - *
    - *
  • partially: When searching for "lor" only "lor" inside - * "lorem" will be marked
  • - *
  • complementary: When searching for "lor" the whole word - * "lorem" will be marked
  • - *
  • exactly: When searching for "lor" only those exact words - * will be marked. In this example nothing inside "lorem". This value - * is equivalent to the previous option wordBoundary
  • - *
- * Or an object containing two properties: - *
    - *
  • value: One of the above named string values
  • - *
  • limiters: A custom array of string limiters for accuracy - * "exactly" or "complementary"
  • - *
- */ - /** - * @typedef Mark~markWildcardsSetting - * @type {string} - * @property {"disabled"|"enabled"|"withSpaces"} - * [wildcards="disabled"] - Set to any of the following string values: - *
    - *
  • disabled: Disable wildcard usage
  • - *
  • enabled: When searching for "lor?m", the "?" will match zero - * or one non-space character (e.g. "lorm", "loram", "lor3m", etc). When - * searching for "lor*m", the "*" will match zero or more non-space - * characters (e.g. "lorm", "loram", "lor123m", etc).
  • - *
  • withSpaces: When searching for "lor?m", the "?" will - * match zero or one space or non-space character (e.g. "lor m", "loram", - * etc). When searching for "lor*m", the "*" will match zero or more space - * or non-space characters (e.g. "lorm", "lore et dolor ipsum", "lor: m", - * etc).
  • - *
- */ - /** - * @typedef Mark~markIgnorePunctuationSetting - * @type {string[]} - * @property {string} The strings in this setting will contain punctuation - * marks that will be ignored: - *
    - *
  • These punctuation marks can be between any characters, e.g. setting - * this option to ["'"] would match "Worlds", "World's" and - * "Wo'rlds"
  • - *
  • One or more apostrophes between the letters would still produce a - * match (e.g. "W'o''r'l'd's").
  • - *
  • A typical setting for this option could be as follows: - *
    ignorePunctuation: ":;.,-–—‒_(){}[]!'\"+=".split(""),
    This - * setting includes common punctuation as well as a minus, en-dash, - * em-dash and figure-dash - * ({@link https://en.wikipedia.org/wiki/Dash#Figure_dash ref}), as well - * as an underscore.
  • - *
- */ - /** - * These options also include the common options from - * {@link Mark~commonOptions} - * @typedef Mark~markOptions - * @type {object.} - * @property {boolean} [separateWordSearch=true] - Whether to search for - * each word separated by a blank instead of the complete term - * @property {boolean} [diacritics=true] - If diacritic characters should be - * matched. ({@link https://en.wikipedia.org/wiki/Diacritic Diacritics}) - * @property {object} [synonyms] - An object with synonyms. The key will be - * a synonym for the value and the value for the key - * @property {Mark~markAccuracySetting} [accuracy] - * @property {Mark~markWildcardsSetting} [wildcards] - * @property {boolean} [acrossElements=false] - Whether to find matches - * across HTML elements. By default, only matches within single HTML - * elements will be found - * @property {boolean} [ignoreJoiners=false] - Whether to ignore word - * joiners inside of key words. These include soft-hyphens, zero-width - * space, zero-width non-joiners and zero-width joiners. - * @property {Mark~markIgnorePunctuationSetting} [ignorePunctuation] - * @property {Mark~markEachCallback} [each] - * @property {Mark~markNoMatchCallback} [noMatch] - * @property {Mark~markFilterCallback} [filter] - */ - /** - * Marks the specified search terms - * @param {string|string[]} [sv] - Search value, either a search string or - * an array containing multiple search strings - * @param {Mark~markOptions} [opt] - Optional options object - * @access public - */ - mark(sv, opt) { - this.opt = opt; - let totalMatches = 0, fn = "wrapMatches"; - const { - keywords: kwArr, - length: kwArrLen - } = this.getSeparatedKeywords(typeof sv === "string" ? [sv] : sv), sens = this.opt.caseSensitive ? "" : "i", handler = (kw) => { - let regex = new RegExp(this.createRegExp(kw), `gm${sens}`), matches = 0; - this.log(`Searching with expression "${regex}"`); - this[fn](regex, 1, (term, node) => { - return this.opt.filter(node, kw, totalMatches, matches); - }, (element) => { - matches++; - totalMatches++; - this.opt.each(element); - }, () => { - if (matches === 0) { - this.opt.noMatch(kw); - } - if (kwArr[kwArrLen - 1] === kw) { - this.opt.done(totalMatches); - } else { - handler(kwArr[kwArr.indexOf(kw) + 1]); - } - }); - }; - if (this.opt.acrossElements) { - fn = "wrapMatchesAcrossElements"; - } - if (kwArrLen === 0) { - this.opt.done(totalMatches); - } else { - handler(kwArr[0]); - } - } - /** - * Callback for each marked element - * @callback Mark~markRangesEachCallback - * @param {HTMLElement} element - The marked DOM element - * @param {array} range - array of range start and end points - */ - /** - * Callback if a processed range is invalid, out-of-bounds, overlaps another - * range, or only matches whitespace - * @callback Mark~markRangesNoMatchCallback - * @param {Mark~rangeObject} range - a range object - */ - /** - * Callback to filter matches - * @callback Mark~markRangesFilterCallback - * @param {HTMLElement} node - The text node which includes the range - * @param {array} range - array of range start and end points - * @param {string} match - string extracted from the matching range - * @param {number} counter - A counter indicating the number of all marks - */ - /** - * These options also include the common options from - * {@link Mark~commonOptions} - * @typedef Mark~markRangesOptions - * @type {object.} - * @property {Mark~markRangesEachCallback} [each] - * @property {Mark~markRangesNoMatchCallback} [noMatch] - * @property {Mark~markRangesFilterCallback} [filter] - */ - /** - * Marks an array of objects containing a start with an end or length of the - * string to mark - * @param {Mark~setOfRanges} rawRanges - The original (preprocessed) - * array of objects - * @param {Mark~markRangesOptions} [opt] - Optional options object - * @access public - */ - markRanges(rawRanges, opt) { - this.opt = opt; - let totalMatches = 0, ranges = this.checkRanges(rawRanges); - if (ranges && ranges.length) { - this.log( - "Starting to mark with the following ranges: " + JSON.stringify(ranges) - ); - this.wrapRangeFromIndex( - ranges, - (node, range, match, counter) => { - return this.opt.filter(node, range, match, counter); - }, - (element, range) => { - totalMatches++; - this.opt.each(element, range); - }, - () => { - this.opt.done(totalMatches); - } - ); - } else { - this.opt.done(totalMatches); - } - } - /** - * Removes all marked elements inside the context with their HTML and - * normalizes the parent at the end - * @param {Mark~commonOptions} [opt] - Optional options object - * @access public - */ - unmark(opt) { - this.opt = opt; - let sel = this.opt.element ? this.opt.element : "*"; - sel += "[data-markjs]"; - if (this.opt.className) { - sel += `.${this.opt.className}`; - } - this.log(`Removal selector "${sel}"`); - this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT, (node) => { - this.unwrapMatches(node); - }, (node) => { - const matchesSel = DOMIterator.matches(node, sel), matchesExclude = this.matchesExclude(node); - if (!matchesSel || matchesExclude) { - return NodeFilter.FILTER_REJECT; - } else { - return NodeFilter.FILTER_ACCEPT; - } - }, this.opt.done); - } -}; - -// node_modules/mark.js/src/vanilla.js -function Mark2(ctx) { - const instance = new Mark(ctx); - this.mark = (sv, opt) => { - instance.mark(sv, opt); - return this; - }; - this.markRegExp = (sv, opt) => { - instance.markRegExp(sv, opt); - return this; - }; - this.markRanges = (sv, opt) => { - instance.markRanges(sv, opt); - return this; - }; - this.unmark = (opt) => { - instance.unmark(opt); - return this; - }; - return this; -} -export { - Mark2 as default -}; -//# sourceMappingURL=vitepress___mark__js_src_vanilla__js.js.map diff --git a/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map b/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map deleted file mode 100644 index 8c14168..0000000 --- a/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../../../../node_modules/mark.js/src/lib/domiterator.js", "../../../../node_modules/mark.js/src/lib/mark.js", "../../../../node_modules/mark.js/src/vanilla.js"], - "sourcesContent": ["/**\n * A NodeIterator with iframes support and a method to check if an element is\n * matching a specified selector\n * @example\n * const iterator = new DOMIterator(\n * document.querySelector(\"#context\"), true\n * );\n * iterator.forEachNode(NodeFilter.SHOW_TEXT, node => {\n * console.log(node);\n * }, node => {\n * if(DOMIterator.matches(node.parentNode, \".ignore\")){\n * return NodeFilter.FILTER_REJECT;\n * } else {\n * return NodeFilter.FILTER_ACCEPT;\n * }\n * }, () => {\n * console.log(\"DONE\");\n * });\n * @todo Outsource into separate repository\n */\nexport default class DOMIterator {\n\n /**\n * @param {HTMLElement|HTMLElement[]|NodeList|string} ctx - The context DOM\n * element, an array of DOM elements, a NodeList or a selector\n * @param {boolean} [iframes=true] - A boolean indicating if iframes should\n * be handled\n * @param {string[]} [exclude=[]] - An array containing exclusion selectors\n * for iframes\n * @param {number} [iframesTimeout=5000] - A number indicating the ms to\n * wait before an iframe should be skipped, in case the load event isn't\n * fired. This also applies if the user is offline and the resource of the\n * iframe is online (either by the browsers \"offline\" mode or because\n * there's no internet connection)\n */\n constructor(ctx, iframes = true, exclude = [], iframesTimeout = 5000) {\n /**\n * The context of the instance. Either a DOM element, an array of DOM\n * elements, a NodeList or a selector\n * @type {HTMLElement|HTMLElement[]|NodeList|string}\n * @access protected\n */\n this.ctx = ctx;\n /**\n * Boolean indicating if iframe support is enabled\n * @type {boolean}\n * @access protected\n */\n this.iframes = iframes;\n /**\n * An array containing exclusion selectors for iframes\n * @type {string[]}\n */\n this.exclude = exclude;\n /**\n * The maximum ms to wait for a load event before skipping an iframe\n * @type {number}\n */\n this.iframesTimeout = iframesTimeout;\n }\n\n /**\n * Checks if the specified DOM element matches the selector\n * @param {HTMLElement} element - The DOM element\n * @param {string|string[]} selector - The selector or an array with\n * selectors\n * @return {boolean}\n * @access public\n */\n static matches(element, selector) {\n const selectors = typeof selector === 'string' ? [selector] : selector,\n fn = (\n element.matches ||\n element.matchesSelector ||\n element.msMatchesSelector ||\n element.mozMatchesSelector ||\n element.oMatchesSelector ||\n element.webkitMatchesSelector\n );\n if (fn) {\n let match = false;\n selectors.every(sel => {\n if (fn.call(element, sel)) {\n match = true;\n return false;\n }\n return true;\n });\n return match;\n } else { // may be false e.g. when el is a textNode\n return false;\n }\n }\n\n /**\n * Returns all contexts filtered by duplicates (even nested)\n * @return {HTMLElement[]} - An array containing DOM contexts\n * @access protected\n */\n getContexts() {\n let ctx,\n filteredCtx = [];\n if (typeof this.ctx === 'undefined' || !this.ctx) { // e.g. null\n ctx = [];\n } else if (NodeList.prototype.isPrototypeOf(this.ctx)) {\n ctx = Array.prototype.slice.call(this.ctx);\n } else if (Array.isArray(this.ctx)) {\n ctx = this.ctx;\n } else if (typeof this.ctx === 'string') {\n ctx = Array.prototype.slice.call(\n document.querySelectorAll(this.ctx)\n );\n } else { // e.g. HTMLElement or element inside iframe\n ctx = [this.ctx];\n }\n // filter duplicate text nodes\n ctx.forEach(ctx => {\n const isDescendant = filteredCtx.filter(contexts => {\n return contexts.contains(ctx);\n }).length > 0;\n if (filteredCtx.indexOf(ctx) === -1 && !isDescendant) {\n filteredCtx.push(ctx);\n }\n });\n return filteredCtx;\n }\n\n /**\n * @callback DOMIterator~getIframeContentsSuccessCallback\n * @param {HTMLDocument} contents - The contentDocument of the iframe\n */\n /**\n * Calls the success callback function with the iframe document. If it can't\n * be accessed it calls the error callback function\n * @param {HTMLElement} ifr - The iframe DOM element\n * @param {DOMIterator~getIframeContentsSuccessCallback} successFn\n * @param {function} [errorFn]\n * @access protected\n */\n getIframeContents(ifr, successFn, errorFn = () => {}) {\n let doc;\n try {\n const ifrWin = ifr.contentWindow;\n doc = ifrWin.document;\n if (!ifrWin || !doc) { // no permission = null. Undefined in Phantom\n throw new Error('iframe inaccessible');\n }\n } catch (e) {\n errorFn();\n }\n if (doc) {\n successFn(doc);\n }\n }\n\n /**\n * Checks if an iframe is empty (if about:blank is the shown page)\n * @param {HTMLElement} ifr - The iframe DOM element\n * @return {boolean}\n * @access protected\n */\n isIframeBlank(ifr) {\n const bl = 'about:blank',\n src = ifr.getAttribute('src').trim(),\n href = ifr.contentWindow.location.href;\n return href === bl && src !== bl && src;\n }\n\n /**\n * Observes the onload event of an iframe and calls the success callback or\n * the error callback if the iframe is inaccessible. If the event isn't\n * fired within the specified {@link DOMIterator#iframesTimeout}, then it'll\n * call the error callback too\n * @param {HTMLElement} ifr - The iframe DOM element\n * @param {DOMIterator~getIframeContentsSuccessCallback} successFn\n * @param {function} errorFn\n * @access protected\n */\n observeIframeLoad(ifr, successFn, errorFn) {\n let called = false,\n tout = null;\n const listener = () => {\n if (called) {\n return;\n }\n called = true;\n clearTimeout(tout);\n try {\n if (!this.isIframeBlank(ifr)) {\n ifr.removeEventListener('load', listener);\n this.getIframeContents(ifr, successFn, errorFn);\n }\n } catch (e) { // isIframeBlank maybe throws throws an error\n errorFn();\n }\n };\n ifr.addEventListener('load', listener);\n tout = setTimeout(listener, this.iframesTimeout);\n }\n\n /**\n * Callback when the iframe is ready\n * @callback DOMIterator~onIframeReadySuccessCallback\n * @param {HTMLDocument} contents - The contentDocument of the iframe\n */\n /**\n * Callback if the iframe can't be accessed\n * @callback DOMIterator~onIframeReadyErrorCallback\n */\n /**\n * Calls the callback if the specified iframe is ready for DOM access\n * @param {HTMLElement} ifr - The iframe DOM element\n * @param {DOMIterator~onIframeReadySuccessCallback} successFn - Success\n * callback\n * @param {DOMIterator~onIframeReadyErrorCallback} errorFn - Error callback\n * @see {@link http://stackoverflow.com/a/36155560/3894981} for\n * background information\n * @access protected\n */\n onIframeReady(ifr, successFn, errorFn) {\n try {\n if (ifr.contentWindow.document.readyState === 'complete') {\n if (this.isIframeBlank(ifr)) {\n this.observeIframeLoad(ifr, successFn, errorFn);\n } else {\n this.getIframeContents(ifr, successFn, errorFn);\n }\n } else {\n this.observeIframeLoad(ifr, successFn, errorFn);\n }\n } catch (e) { // accessing document failed\n errorFn();\n }\n }\n\n /**\n * Callback when all iframes are ready for DOM access\n * @callback DOMIterator~waitForIframesDoneCallback\n */\n /**\n * Iterates over all iframes and calls the done callback when all of them\n * are ready for DOM access (including nested ones)\n * @param {HTMLElement} ctx - The context DOM element\n * @param {DOMIterator~waitForIframesDoneCallback} done - Done callback\n */\n waitForIframes(ctx, done) {\n let eachCalled = 0;\n this.forEachIframe(ctx, () => true, ifr => {\n eachCalled++;\n this.waitForIframes(ifr.querySelector('html'), () => {\n if (!(--eachCalled)) {\n done();\n }\n });\n }, handled => {\n if (!handled) {\n done();\n }\n });\n }\n\n /**\n * Callback allowing to filter an iframe. Must return true when the element\n * should remain, otherwise false\n * @callback DOMIterator~forEachIframeFilterCallback\n * @param {HTMLElement} iframe - The iframe DOM element\n */\n /**\n * Callback for each iframe content\n * @callback DOMIterator~forEachIframeEachCallback\n * @param {HTMLElement} content - The iframe document\n */\n /**\n * Callback if all iframes inside the context were handled\n * @callback DOMIterator~forEachIframeEndCallback\n * @param {number} handled - The number of handled iframes (those who\n * wheren't filtered)\n */\n /**\n * Iterates over all iframes inside the specified context and calls the\n * callbacks when they're ready. Filters iframes based on the instance\n * exclusion selectors\n * @param {HTMLElement} ctx - The context DOM element\n * @param {DOMIterator~forEachIframeFilterCallback} filter - Filter callback\n * @param {DOMIterator~forEachIframeEachCallback} each - Each callback\n * @param {DOMIterator~forEachIframeEndCallback} [end] - End callback\n * @access protected\n */\n forEachIframe(ctx, filter, each, end = () => {}) {\n let ifr = ctx.querySelectorAll('iframe'),\n open = ifr.length,\n handled = 0;\n ifr = Array.prototype.slice.call(ifr);\n const checkEnd = () => {\n if (--open <= 0) {\n end(handled);\n }\n };\n if (!open) {\n checkEnd();\n }\n ifr.forEach(ifr => {\n if (DOMIterator.matches(ifr, this.exclude)) {\n checkEnd();\n } else {\n this.onIframeReady(ifr, con => {\n if (filter(ifr)) {\n handled++;\n each(con);\n }\n checkEnd();\n }, checkEnd);\n }\n });\n }\n\n /**\n * Creates a NodeIterator on the specified context\n * @see {@link https://developer.mozilla.org/en/docs/Web/API/NodeIterator}\n * @param {HTMLElement} ctx - The context DOM element\n * @param {DOMIterator~whatToShow} whatToShow\n * @param {DOMIterator~filterCb} filter\n * @return {NodeIterator}\n * @access protected\n */\n createIterator(ctx, whatToShow, filter) {\n return document.createNodeIterator(ctx, whatToShow, filter, false);\n }\n\n /**\n * Creates an instance of DOMIterator in an iframe\n * @param {HTMLDocument} contents - Iframe document\n * @return {DOMIterator}\n * @access protected\n */\n createInstanceOnIframe(contents) {\n return new DOMIterator(contents.querySelector('html'), this.iframes);\n }\n\n /**\n * Checks if an iframe occurs between two nodes, more specifically if an\n * iframe occurs before the specified node and after the specified prevNode\n * @param {HTMLElement} node - The node that should occur after the iframe\n * @param {HTMLElement} prevNode - The node that should occur before the\n * iframe\n * @param {HTMLElement} ifr - The iframe to check against\n * @return {boolean}\n * @access protected\n */\n compareNodeIframe(node, prevNode, ifr) {\n const compCurr = node.compareDocumentPosition(ifr),\n prev = Node.DOCUMENT_POSITION_PRECEDING;\n if (compCurr & prev) {\n if (prevNode !== null) {\n const compPrev = prevNode.compareDocumentPosition(ifr),\n after = Node.DOCUMENT_POSITION_FOLLOWING;\n if (compPrev & after) {\n return true;\n }\n } else {\n return true;\n }\n }\n return false;\n }\n\n /**\n * @typedef {DOMIterator~getIteratorNodeReturn}\n * @type {object.}\n * @property {HTMLElement} prevNode - The previous node or null if there is\n * no\n * @property {HTMLElement} node - The current node\n */\n /**\n * Returns the previous and current node of the specified iterator\n * @param {NodeIterator} itr - The iterator\n * @return {DOMIterator~getIteratorNodeReturn}\n * @access protected\n */\n getIteratorNode(itr) {\n const prevNode = itr.previousNode();\n let node;\n if (prevNode === null) {\n node = itr.nextNode();\n } else {\n node = itr.nextNode() && itr.nextNode();\n }\n return {\n prevNode,\n node\n };\n }\n\n /**\n * An array containing objects. The object key \"val\" contains an iframe\n * DOM element. The object key \"handled\" contains a boolean indicating if\n * the iframe was handled already.\n * It wouldn't be enough to save all open or all already handled iframes.\n * The information of open iframes is necessary because they may occur after\n * all other text nodes (and compareNodeIframe would never be true). The\n * information of already handled iframes is necessary as otherwise they may\n * be handled multiple times\n * @typedef DOMIterator~checkIframeFilterIfr\n * @type {object[]}\n */\n /**\n * Checks if an iframe wasn't handled already and if so, calls\n * {@link DOMIterator#compareNodeIframe} to check if it should be handled.\n * Information wheter an iframe was or wasn't handled is given within the\n * ifr dictionary\n * @param {HTMLElement} node - The node that should occur after the iframe\n * @param {HTMLElement} prevNode - The node that should occur before the\n * iframe\n * @param {HTMLElement} currIfr - The iframe to check\n * @param {DOMIterator~checkIframeFilterIfr} ifr - The iframe dictionary.\n * Will be manipulated (by reference)\n * @return {boolean} Returns true when it should be handled, otherwise false\n * @access protected\n */\n checkIframeFilter(node, prevNode, currIfr, ifr) {\n let key = false, // false === doesn't exist\n handled = false;\n ifr.forEach((ifrDict, i) => {\n if (ifrDict.val === currIfr) {\n key = i;\n handled = ifrDict.handled;\n }\n });\n if (this.compareNodeIframe(node, prevNode, currIfr)) {\n if (key === false && !handled) {\n ifr.push({\n val: currIfr,\n handled: true\n });\n } else if (key !== false && !handled) {\n ifr[key].handled = true;\n }\n return true;\n }\n if (key === false) {\n ifr.push({\n val: currIfr,\n handled: false\n });\n }\n return false;\n }\n\n /**\n * Creates an iterator on all open iframes in the specified array and calls\n * the end callback when finished\n * @param {DOMIterator~checkIframeFilterIfr} ifr\n * @param {DOMIterator~whatToShow} whatToShow\n * @param {DOMIterator~forEachNodeCallback} eCb - Each callback\n * @param {DOMIterator~filterCb} fCb\n * @access protected\n */\n handleOpenIframes(ifr, whatToShow, eCb, fCb) {\n ifr.forEach(ifrDict => {\n if (!ifrDict.handled) {\n this.getIframeContents(ifrDict.val, con => {\n this.createInstanceOnIframe(con).forEachNode(\n whatToShow, eCb, fCb\n );\n });\n }\n });\n }\n\n /**\n * Iterates through all nodes in the specified context and handles iframe\n * nodes at the correct position\n * @param {DOMIterator~whatToShow} whatToShow\n * @param {HTMLElement} ctx - The context\n * @param {DOMIterator~forEachNodeCallback} eachCb - Each callback\n * @param {DOMIterator~filterCb} filterCb - Filter callback\n * @param {DOMIterator~forEachNodeEndCallback} doneCb - End callback\n * @access protected\n */\n iterateThroughNodes(whatToShow, ctx, eachCb, filterCb, doneCb) {\n const itr = this.createIterator(ctx, whatToShow, filterCb);\n let ifr = [],\n elements = [],\n node, prevNode, retrieveNodes = () => {\n ({\n prevNode,\n node\n } = this.getIteratorNode(itr));\n return node;\n };\n while (retrieveNodes()) {\n if (this.iframes) {\n this.forEachIframe(ctx, currIfr => {\n // note that ifr will be manipulated here\n return this.checkIframeFilter(node, prevNode, currIfr, ifr);\n }, con => {\n this.createInstanceOnIframe(con).forEachNode(\n whatToShow, ifrNode => elements.push(ifrNode), filterCb\n );\n });\n }\n // it's faster to call the each callback in an array loop\n // than in this while loop\n elements.push(node);\n }\n elements.forEach(node => {\n eachCb(node);\n });\n if (this.iframes) {\n this.handleOpenIframes(ifr, whatToShow, eachCb, filterCb);\n }\n doneCb();\n }\n\n /**\n * Callback for each node\n * @callback DOMIterator~forEachNodeCallback\n * @param {HTMLElement} node - The DOM text node element\n */\n /**\n * Callback if all contexts were handled\n * @callback DOMIterator~forEachNodeEndCallback\n */\n /**\n * Iterates over all contexts and initializes\n * {@link DOMIterator#iterateThroughNodes iterateThroughNodes} on them\n * @param {DOMIterator~whatToShow} whatToShow\n * @param {DOMIterator~forEachNodeCallback} each - Each callback\n * @param {DOMIterator~filterCb} filter - Filter callback\n * @param {DOMIterator~forEachNodeEndCallback} done - End callback\n * @access public\n */\n forEachNode(whatToShow, each, filter, done = () => {}) {\n const contexts = this.getContexts();\n let open = contexts.length;\n if (!open) {\n done();\n }\n contexts.forEach(ctx => {\n const ready = () => {\n this.iterateThroughNodes(whatToShow, ctx, each, filter, () => {\n if (--open <= 0) { // call end all contexts were handled\n done();\n }\n });\n };\n // wait for iframes to avoid recursive calls, otherwise this would\n // perhaps reach the recursive function call limit with many nodes\n if (this.iframes) {\n this.waitForIframes(ctx, ready);\n } else {\n ready();\n }\n });\n }\n\n /**\n * Callback to filter nodes. Can return e.g. NodeFilter.FILTER_ACCEPT or\n * NodeFilter.FILTER_REJECT\n * @see {@link http://tinyurl.com/zdczmm2}\n * @callback DOMIterator~filterCb\n * @param {HTMLElement} node - The node to filter\n */\n /**\n * @typedef DOMIterator~whatToShow\n * @see {@link http://tinyurl.com/zfqqkx2}\n * @type {number}\n */\n}\n", "import DOMIterator from './domiterator';\n\n/**\n * Marks search terms in DOM elements\n * @example\n * new Mark(document.querySelector(\".context\")).mark(\"lorem ipsum\");\n * @example\n * new Mark(document.querySelector(\".context\")).markRegExp(/lorem/gmi);\n */\nexport default class Mark { // eslint-disable-line no-unused-vars\n\n /**\n * @param {HTMLElement|HTMLElement[]|NodeList|string} ctx - The context DOM\n * element, an array of DOM elements, a NodeList or a selector\n */\n constructor(ctx) {\n /**\n * The context of the instance. Either a DOM element, an array of DOM\n * elements, a NodeList or a selector\n * @type {HTMLElement|HTMLElement[]|NodeList|string}\n * @access protected\n */\n this.ctx = ctx;\n /**\n * Specifies if the current browser is a IE (necessary for the node\n * normalization bug workaround). See {@link Mark#unwrapMatches}\n * @type {boolean}\n * @access protected\n */\n this.ie = false;\n const ua = window.navigator.userAgent;\n if (ua.indexOf('MSIE') > -1 || ua.indexOf('Trident') > -1) {\n this.ie = true;\n }\n }\n\n /**\n * Options defined by the user. They will be initialized from one of the\n * public methods. See {@link Mark#mark}, {@link Mark#markRegExp},\n * {@link Mark#markRanges} and {@link Mark#unmark} for option properties.\n * @type {object}\n * @param {object} [val] - An object that will be merged with defaults\n * @access protected\n */\n set opt(val) {\n this._opt = Object.assign({}, {\n 'element': '',\n 'className': '',\n 'exclude': [],\n 'iframes': false,\n 'iframesTimeout': 5000,\n 'separateWordSearch': true,\n 'diacritics': true,\n 'synonyms': {},\n 'accuracy': 'partially',\n 'acrossElements': false,\n 'caseSensitive': false,\n 'ignoreJoiners': false,\n 'ignoreGroups': 0,\n 'ignorePunctuation': [],\n 'wildcards': 'disabled',\n 'each': () => {},\n 'noMatch': () => {},\n 'filter': () => true,\n 'done': () => {},\n 'debug': false,\n 'log': window.console\n }, val);\n }\n\n get opt() {\n return this._opt;\n }\n\n /**\n * An instance of DOMIterator\n * @type {DOMIterator}\n * @access protected\n */\n get iterator() {\n // always return new instance in case there were option changes\n return new DOMIterator(\n this.ctx,\n this.opt.iframes,\n this.opt.exclude,\n this.opt.iframesTimeout\n );\n }\n\n /**\n * Logs a message if log is enabled\n * @param {string} msg - The message to log\n * @param {string} [level=\"debug\"] - The log level, e.g. warn\n * error, debug\n * @access protected\n */\n log(msg, level = 'debug') {\n const log = this.opt.log;\n if (!this.opt.debug) {\n return;\n }\n if (typeof log === 'object' && typeof log[level] === 'function') {\n log[level](`mark.js: ${msg}`);\n }\n }\n\n /**\n * Escapes a string for usage within a regular expression\n * @param {string} str - The string to escape\n * @return {string}\n * @access protected\n */\n escapeStr(str) {\n // eslint-disable-next-line no-useless-escape\n return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, '\\\\$&');\n }\n\n /**\n * Creates a regular expression string to match the specified search\n * term including synonyms, diacritics and accuracy if defined\n * @param {string} str - The search term to be used\n * @return {string}\n * @access protected\n */\n createRegExp(str) {\n if (this.opt.wildcards !== 'disabled') {\n str = this.setupWildcardsRegExp(str);\n }\n str = this.escapeStr(str);\n if (Object.keys(this.opt.synonyms).length) {\n str = this.createSynonymsRegExp(str);\n }\n if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {\n str = this.setupIgnoreJoinersRegExp(str);\n }\n if (this.opt.diacritics) {\n str = this.createDiacriticsRegExp(str);\n }\n str = this.createMergedBlanksRegExp(str);\n if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {\n str = this.createJoinersRegExp(str);\n }\n if (this.opt.wildcards !== 'disabled') {\n str = this.createWildcardsRegExp(str);\n }\n str = this.createAccuracyRegExp(str);\n return str;\n }\n\n /**\n * Creates a regular expression string to match the defined synonyms\n * @param {string} str - The search term to be used\n * @return {string}\n * @access protected\n */\n createSynonymsRegExp(str) {\n const syn = this.opt.synonyms,\n sens = this.opt.caseSensitive ? '' : 'i',\n // add replacement character placeholder before and after the\n // synonym group\n joinerPlaceholder = this.opt.ignoreJoiners ||\n this.opt.ignorePunctuation.length ? '\\u0000' : '';\n for (let index in syn) {\n if (syn.hasOwnProperty(index)) {\n const value = syn[index],\n k1 = this.opt.wildcards !== 'disabled' ?\n this.setupWildcardsRegExp(index) :\n this.escapeStr(index),\n k2 = this.opt.wildcards !== 'disabled' ?\n this.setupWildcardsRegExp(value) :\n this.escapeStr(value);\n if (k1 !== '' && k2 !== '') {\n str = str.replace(\n new RegExp(\n `(${this.escapeStr(k1)}|${this.escapeStr(k2)})`,\n `gm${sens}`\n ),\n joinerPlaceholder +\n `(${this.processSynomyms(k1)}|` +\n `${this.processSynomyms(k2)})` +\n joinerPlaceholder\n );\n }\n }\n }\n return str;\n }\n\n /**\n * Setup synonyms to work with ignoreJoiners and or ignorePunctuation\n * @param {string} str - synonym key or value to process\n * @return {string} - processed synonym string\n */\n processSynomyms(str) {\n if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {\n str = this.setupIgnoreJoinersRegExp(str);\n }\n return str;\n }\n\n /**\n * Sets up the regular expression string to allow later insertion of\n * wildcard regular expression matches\n * @param {string} str - The search term to be used\n * @return {string}\n * @access protected\n */\n setupWildcardsRegExp(str) {\n // replace single character wildcard with unicode 0001\n str = str.replace(/(?:\\\\)*\\?/g, val => {\n return val.charAt(0) === '\\\\' ? '?' : '\\u0001';\n });\n // replace multiple character wildcard with unicode 0002\n return str.replace(/(?:\\\\)*\\*/g, val => {\n return val.charAt(0) === '\\\\' ? '*' : '\\u0002';\n });\n }\n\n /**\n * Sets up the regular expression string to allow later insertion of\n * wildcard regular expression matches\n * @param {string} str - The search term to be used\n * @return {string}\n * @access protected\n */\n createWildcardsRegExp(str) {\n // default to \"enable\" (i.e. to not include spaces)\n // \"withSpaces\" uses `[\\\\S\\\\s]` instead of `.` because the latter\n // does not match new line characters\n let spaces = this.opt.wildcards === 'withSpaces';\n return str\n // replace unicode 0001 with a RegExp class to match any single\n // character, or any single non-whitespace character depending\n // on the setting\n .replace(/\\u0001/g, spaces ? '[\\\\S\\\\s]?' : '\\\\S?')\n // replace unicode 0002 with a RegExp class to match zero or\n // more characters, or zero or more non-whitespace characters\n // depending on the setting\n .replace(/\\u0002/g, spaces ? '[\\\\S\\\\s]*?' : '\\\\S*');\n }\n\n /**\n * Sets up the regular expression string to allow later insertion of\n * designated characters (soft hyphens & zero width characters)\n * @param {string} str - The search term to be used\n * @return {string}\n * @access protected\n */\n setupIgnoreJoinersRegExp(str) {\n // adding a \"null\" unicode character as it will not be modified by the\n // other \"create\" regular expression functions\n return str.replace(/[^(|)\\\\]/g, (val, indx, original) => {\n // don't add a null after an opening \"(\", around a \"|\" or before\n // a closing \"(\", or between an escapement (e.g. \\+)\n let nextChar = original.charAt(indx + 1);\n if (/[(|)\\\\]/.test(nextChar) || nextChar === '') {\n return val;\n } else {\n return val + '\\u0000';\n }\n });\n }\n\n /**\n * Creates a regular expression string to allow ignoring of designated\n * characters (soft hyphens, zero width characters & punctuation) based on\n * the specified option values of ignorePunctuation and\n * ignoreJoiners\n * @param {string} str - The search term to be used\n * @return {string}\n * @access protected\n */\n createJoinersRegExp(str) {\n let joiner = [];\n const ignorePunctuation = this.opt.ignorePunctuation;\n if (Array.isArray(ignorePunctuation) && ignorePunctuation.length) {\n joiner.push(this.escapeStr(ignorePunctuation.join('')));\n }\n if (this.opt.ignoreJoiners) {\n // u+00ad = soft hyphen\n // u+200b = zero-width space\n // u+200c = zero-width non-joiner\n // u+200d = zero-width joiner\n joiner.push('\\\\u00ad\\\\u200b\\\\u200c\\\\u200d');\n }\n return joiner.length ?\n str.split(/\\u0000+/).join(`[${joiner.join('')}]*`) :\n str;\n }\n\n /**\n * Creates a regular expression string to match diacritics\n * @param {string} str - The search term to be used\n * @return {string}\n * @access protected\n */\n createDiacriticsRegExp(str) {\n const sens = this.opt.caseSensitive ? '' : 'i',\n dct = this.opt.caseSensitive ? [\n 'aàáảãạăằắẳẵặâầấẩẫậäåāą', 'AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ',\n 'cçćč', 'CÇĆČ', 'dđď', 'DĐĎ',\n 'eèéẻẽẹêềếểễệëěēę', 'EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ',\n 'iìíỉĩịîïī', 'IÌÍỈĨỊÎÏĪ', 'lł', 'LŁ', 'nñňń',\n 'NÑŇŃ', 'oòóỏõọôồốổỗộơởỡớờợöøō', 'OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ',\n 'rř', 'RŘ', 'sšśșş', 'SŠŚȘŞ',\n 'tťțţ', 'TŤȚŢ', 'uùúủũụưừứửữựûüůū', 'UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ',\n 'yýỳỷỹỵÿ', 'YÝỲỶỸỴŸ', 'zžżź', 'ZŽŻŹ'\n ] : [\n 'aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ', 'cçćčCÇĆČ',\n 'dđďDĐĎ', 'eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ',\n 'iìíỉĩịîïīIÌÍỈĨỊÎÏĪ', 'lłLŁ', 'nñňńNÑŇŃ',\n 'oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ', 'rřRŘ',\n 'sšśșşSŠŚȘŞ', 'tťțţTŤȚŢ',\n 'uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ', 'yýỳỷỹỵÿYÝỲỶỸỴŸ', 'zžżźZŽŻŹ'\n ];\n let handled = [];\n str.split('').forEach(ch => {\n dct.every(dct => {\n // Check if the character is inside a diacritics list\n if (dct.indexOf(ch) !== -1) {\n // Check if the related diacritics list was not\n // handled yet\n if (handled.indexOf(dct) > -1) {\n return false;\n }\n // Make sure that the character OR any other\n // character in the diacritics list will be matched\n str = str.replace(\n new RegExp(`[${dct}]`, `gm${sens}`), `[${dct}]`\n );\n handled.push(dct);\n }\n return true;\n });\n });\n return str;\n }\n\n /**\n * Creates a regular expression string that merges whitespace characters\n * including subsequent ones into a single pattern, one or multiple\n * whitespaces\n * @param {string} str - The search term to be used\n * @return {string}\n * @access protected\n */\n createMergedBlanksRegExp(str) {\n return str.replace(/[\\s]+/gmi, '[\\\\s]+');\n }\n\n /**\n * Creates a regular expression string to match the specified string with\n * the defined accuracy. As in the regular expression of \"exactly\" can be\n * a group containing a blank at the beginning, all regular expressions will\n * be created with two groups. The first group can be ignored (may contain\n * the said blank), the second contains the actual match\n * @param {string} str - The searm term to be used\n * @return {str}\n * @access protected\n */\n createAccuracyRegExp(str) {\n const chars = '!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~¡¿';\n let acc = this.opt.accuracy,\n val = typeof acc === 'string' ? acc : acc.value,\n ls = typeof acc === 'string' ? [] : acc.limiters,\n lsJoin = '';\n ls.forEach(limiter => {\n lsJoin += `|${this.escapeStr(limiter)}`;\n });\n switch (val) {\n case 'partially':\n default:\n return `()(${str})`;\n case 'complementary':\n lsJoin = '\\\\s' + (lsJoin ? lsJoin : this.escapeStr(chars));\n return `()([^${lsJoin}]*${str}[^${lsJoin}]*)`;\n case 'exactly':\n return `(^|\\\\s${lsJoin})(${str})(?=$|\\\\s${lsJoin})`;\n }\n }\n\n /**\n * @typedef Mark~separatedKeywords\n * @type {object.}\n * @property {array.} keywords - The list of keywords\n * @property {number} length - The length\n */\n /**\n * Returns a list of keywords dependent on whether separate word search\n * was defined. Also it filters empty keywords\n * @param {array} sv - The array of keywords\n * @return {Mark~separatedKeywords}\n * @access protected\n */\n getSeparatedKeywords(sv) {\n let stack = [];\n sv.forEach(kw => {\n if (!this.opt.separateWordSearch) {\n if (kw.trim() && stack.indexOf(kw) === -1) {\n stack.push(kw);\n }\n } else {\n kw.split(' ').forEach(kwSplitted => {\n if (kwSplitted.trim() && stack.indexOf(kwSplitted) === -1) {\n stack.push(kwSplitted);\n }\n });\n }\n });\n return {\n // sort because of https://git.io/v6USg\n 'keywords': stack.sort((a, b) => {\n return b.length - a.length;\n }),\n 'length': stack.length\n };\n }\n\n /**\n * Check if a value is a number\n * @param {number|string} value - the value to check;\n * numeric strings allowed\n * @return {boolean}\n * @access protected\n */\n isNumeric(value) {\n // http://stackoverflow.com/a/16655847/145346\n // eslint-disable-next-line eqeqeq\n return Number(parseFloat(value)) == value;\n }\n\n /**\n * @typedef Mark~rangeObject\n * @type {object}\n * @property {number} start - The start position within the composite value\n * @property {number} length - The length of the string to mark within the\n * composite value.\n */\n /**\n * @typedef Mark~setOfRanges\n * @type {object[]}\n * @property {Mark~rangeObject}\n */\n /**\n * Returns a processed list of integer offset indexes that do not overlap\n * each other, and remove any string values or additional elements\n * @param {Mark~setOfRanges} array - unprocessed raw array\n * @return {Mark~setOfRanges} - processed array with any invalid entries\n * removed\n * @throws Will throw an error if an array of objects is not passed\n * @access protected\n */\n checkRanges(array) {\n // start and length indexes are included in an array of objects\n // [{start: 0, length: 1}, {start: 4, length: 5}]\n // quick validity check of the first entry only\n if (\n !Array.isArray(array) ||\n Object.prototype.toString.call( array[0] ) !== '[object Object]'\n ) {\n this.log('markRanges() will only accept an array of objects');\n this.opt.noMatch(array);\n return [];\n }\n const stack = [];\n let last = 0;\n array\n // acending sort to ensure there is no overlap in start & end\n // offsets\n .sort((a, b) => {\n return a.start - b.start;\n })\n .forEach(item => {\n let {start, end, valid} = this.callNoMatchOnInvalidRanges(item, last);\n if (valid) {\n // preserve item in case there are extra key:values within\n item.start = start;\n item.length = end - start;\n stack.push(item);\n last = end;\n }\n });\n return stack;\n }\n\n /**\n * @typedef Mark~validObject\n * @type {object}\n * @property {number} start - The start position within the composite value\n * @property {number} end - The calculated end position within the composite\n * value.\n * @property {boolean} valid - boolean value indicating that the start and\n * calculated end range is valid\n */\n /**\n * Initial validation of ranges for markRanges. Preliminary checks are done\n * to ensure the start and length values exist and are not zero or non-\n * numeric\n * @param {Mark~rangeObject} range - the current range object\n * @param {number} last - last index of range\n * @return {Mark~validObject}\n * @access protected\n */\n callNoMatchOnInvalidRanges(range, last) {\n let start, end,\n valid = false;\n if (range && typeof range.start !== 'undefined') {\n start = parseInt(range.start, 10);\n end = start + parseInt(range.length, 10);\n // ignore overlapping values & non-numeric entries\n if (\n this.isNumeric(range.start) &&\n this.isNumeric(range.length) &&\n end - last > 0 &&\n end - start > 0\n ) {\n valid = true;\n } else {\n this.log(\n 'Ignoring invalid or overlapping range: ' +\n `${JSON.stringify(range)}`\n );\n this.opt.noMatch(range);\n }\n } else {\n this.log(`Ignoring invalid range: ${JSON.stringify(range)}`);\n this.opt.noMatch(range);\n }\n return {\n start: start,\n end: end,\n valid: valid\n };\n }\n\n /**\n * Check valid range for markRanges. Check ranges with access to the context\n * string. Range values are double checked, lengths that extend the mark\n * beyond the string length are limitied and ranges containing only\n * whitespace are ignored\n * @param {Mark~rangeObject} range - the current range object\n * @param {number} originalLength - original length of the context string\n * @param {string} string - current content string\n * @return {Mark~validObject}\n * @access protected\n */\n checkWhitespaceRanges(range, originalLength, string) {\n let end,\n valid = true,\n // the max value changes after the DOM is manipulated\n max = string.length,\n // adjust offset to account for wrapped text node\n offset = originalLength - max,\n start = parseInt(range.start, 10) - offset;\n // make sure to stop at max\n start = start > max ? max : start;\n end = start + parseInt(range.length, 10);\n if (end > max) {\n end = max;\n this.log(`End range automatically set to the max value of ${max}`);\n }\n if (start < 0 || end - start < 0 || start > max || end > max) {\n valid = false;\n this.log(`Invalid range: ${JSON.stringify(range)}`);\n this.opt.noMatch(range);\n } else if (string.substring(start, end).replace(/\\s+/g, '') === '') {\n valid = false;\n // whitespace only; even if wrapped it is not visible\n this.log('Skipping whitespace only range: ' +JSON.stringify(range));\n this.opt.noMatch(range);\n }\n return {\n start: start,\n end: end,\n valid: valid\n };\n }\n\n /**\n * @typedef Mark~getTextNodesDict\n * @type {object.}\n * @property {string} value - The composite value of all text nodes\n * @property {object[]} nodes - An array of objects\n * @property {number} nodes.start - The start position within the composite\n * value\n * @property {number} nodes.end - The end position within the composite\n * value\n * @property {HTMLElement} nodes.node - The DOM text node element\n */\n /**\n * Callback\n * @callback Mark~getTextNodesCallback\n * @param {Mark~getTextNodesDict}\n */\n /**\n * Calls the callback with an object containing all text nodes (including\n * iframe text nodes) with start and end positions and the composite value\n * of them (string)\n * @param {Mark~getTextNodesCallback} cb - Callback\n * @access protected\n */\n getTextNodes(cb) {\n let val = '',\n nodes = [];\n this.iterator.forEachNode(NodeFilter.SHOW_TEXT, node => {\n nodes.push({\n start: val.length,\n end: (val += node.textContent).length,\n node\n });\n }, node => {\n if (this.matchesExclude(node.parentNode)) {\n return NodeFilter.FILTER_REJECT;\n } else {\n return NodeFilter.FILTER_ACCEPT;\n }\n }, () => {\n cb({\n value: val,\n nodes: nodes\n });\n });\n }\n\n /**\n * Checks if an element matches any of the specified exclude selectors. Also\n * it checks for elements in which no marks should be performed (e.g.\n * script and style tags) and optionally already marked elements\n * @param {HTMLElement} el - The element to check\n * @return {boolean}\n * @access protected\n */\n matchesExclude(el) {\n return DOMIterator.matches(el, this.opt.exclude.concat([\n // ignores the elements itself, not their childrens (selector *)\n 'script', 'style', 'title', 'head', 'html'\n ]));\n }\n\n /**\n * Wraps the instance element and class around matches that fit the start\n * and end positions within the node\n * @param {HTMLElement} node - The DOM text node\n * @param {number} start - The position where to start wrapping\n * @param {number} end - The position where to end wrapping\n * @return {HTMLElement} Returns the splitted text node that will appear\n * after the wrapped text node\n * @access protected\n */\n wrapRangeInTextNode(node, start, end) {\n const hEl = !this.opt.element ? 'mark' : this.opt.element,\n startNode = node.splitText(start),\n ret = startNode.splitText(end - start);\n let repl = document.createElement(hEl);\n repl.setAttribute('data-markjs', 'true');\n if (this.opt.className) {\n repl.setAttribute('class', this.opt.className);\n }\n repl.textContent = startNode.textContent;\n startNode.parentNode.replaceChild(repl, startNode);\n return ret;\n }\n\n /**\n * @typedef Mark~wrapRangeInMappedTextNodeDict\n * @type {object.}\n * @property {string} value - The composite value of all text nodes\n * @property {object[]} nodes - An array of objects\n * @property {number} nodes.start - The start position within the composite\n * value\n * @property {number} nodes.end - The end position within the composite\n * value\n * @property {HTMLElement} nodes.node - The DOM text node element\n */\n /**\n * Each callback\n * @callback Mark~wrapMatchesEachCallback\n * @param {HTMLElement} node - The wrapped DOM element\n * @param {number} lastIndex - The last matching position within the\n * composite value of text nodes\n */\n /**\n * Filter callback\n * @callback Mark~wrapMatchesFilterCallback\n * @param {HTMLElement} node - The matching text node DOM element\n */\n /**\n * Determines matches by start and end positions using the text node\n * dictionary even across text nodes and calls\n * {@link Mark#wrapRangeInTextNode} to wrap them\n * @param {Mark~wrapRangeInMappedTextNodeDict} dict - The dictionary\n * @param {number} start - The start position of the match\n * @param {number} end - The end position of the match\n * @param {Mark~wrapMatchesFilterCallback} filterCb - Filter callback\n * @param {Mark~wrapMatchesEachCallback} eachCb - Each callback\n * @access protected\n */\n wrapRangeInMappedTextNode(dict, start, end, filterCb, eachCb) {\n // iterate over all text nodes to find the one matching the positions\n dict.nodes.every((n, i) => {\n const sibl = dict.nodes[i + 1];\n if (typeof sibl === 'undefined' || sibl.start > start) {\n if (!filterCb(n.node)) {\n return false;\n }\n // map range from dict.value to text node\n const s = start - n.start,\n e = (end > n.end ? n.end : end) - n.start,\n startStr = dict.value.substr(0, n.start),\n endStr = dict.value.substr(e + n.start);\n n.node = this.wrapRangeInTextNode(n.node, s, e);\n // recalculate positions to also find subsequent matches in the\n // same text node. Necessary as the text node in dict now only\n // contains the splitted part after the wrapped one\n dict.value = startStr + endStr;\n dict.nodes.forEach((k, j) => {\n if (j >= i) {\n if (dict.nodes[j].start > 0 && j !== i) {\n dict.nodes[j].start -= e;\n }\n dict.nodes[j].end -= e;\n }\n });\n end -= e;\n eachCb(n.node.previousSibling, n.start);\n if (end > n.end) {\n start = n.end;\n } else {\n return false;\n }\n }\n return true;\n });\n }\n\n /**\n * Filter callback before each wrapping\n * @callback Mark~wrapMatchesFilterCallback\n * @param {string} match - The matching string\n * @param {HTMLElement} node - The text node where the match occurs\n */\n /**\n * Callback for each wrapped element\n * @callback Mark~wrapMatchesEachCallback\n * @param {HTMLElement} element - The marked DOM element\n */\n /**\n * Callback on end\n * @callback Mark~wrapMatchesEndCallback\n */\n /**\n * Wraps the instance element and class around matches within single HTML\n * elements in all contexts\n * @param {RegExp} regex - The regular expression to be searched for\n * @param {number} ignoreGroups - A number indicating the amount of RegExp\n * matching groups to ignore\n * @param {Mark~wrapMatchesFilterCallback} filterCb\n * @param {Mark~wrapMatchesEachCallback} eachCb\n * @param {Mark~wrapMatchesEndCallback} endCb\n * @access protected\n */\n wrapMatches(regex, ignoreGroups, filterCb, eachCb, endCb) {\n const matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1;\n this.getTextNodes(dict => {\n dict.nodes.forEach(node => {\n node = node.node;\n let match;\n while (\n (match = regex.exec(node.textContent)) !== null &&\n match[matchIdx] !== ''\n ) {\n if (!filterCb(match[matchIdx], node)) {\n continue;\n }\n let pos = match.index;\n if (matchIdx !== 0) {\n for (let i = 1; i < matchIdx; i++) {\n pos += match[i].length;\n }\n }\n node = this.wrapRangeInTextNode(\n node,\n pos,\n pos + match[matchIdx].length\n );\n eachCb(node.previousSibling);\n // reset index of last match as the node changed and the\n // index isn't valid anymore http://tinyurl.com/htsudjd\n regex.lastIndex = 0;\n }\n });\n endCb();\n });\n }\n\n /**\n * Callback for each wrapped element\n * @callback Mark~wrapMatchesAcrossElementsEachCallback\n * @param {HTMLElement} element - The marked DOM element\n */\n /**\n * Filter callback before each wrapping\n * @callback Mark~wrapMatchesAcrossElementsFilterCallback\n * @param {string} match - The matching string\n * @param {HTMLElement} node - The text node where the match occurs\n */\n /**\n * Callback on end\n * @callback Mark~wrapMatchesAcrossElementsEndCallback\n */\n /**\n * Wraps the instance element and class around matches across all HTML\n * elements in all contexts\n * @param {RegExp} regex - The regular expression to be searched for\n * @param {number} ignoreGroups - A number indicating the amount of RegExp\n * matching groups to ignore\n * @param {Mark~wrapMatchesAcrossElementsFilterCallback} filterCb\n * @param {Mark~wrapMatchesAcrossElementsEachCallback} eachCb\n * @param {Mark~wrapMatchesAcrossElementsEndCallback} endCb\n * @access protected\n */\n wrapMatchesAcrossElements(regex, ignoreGroups, filterCb, eachCb, endCb) {\n const matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1;\n this.getTextNodes(dict => {\n let match;\n while (\n (match = regex.exec(dict.value)) !== null &&\n match[matchIdx] !== ''\n ) {\n // calculate range inside dict.value\n let start = match.index;\n if (matchIdx !== 0) {\n for (let i = 1; i < matchIdx; i++) {\n start += match[i].length;\n }\n }\n const end = start + match[matchIdx].length;\n // note that dict will be updated automatically, as it'll change\n // in the wrapping process, due to the fact that text\n // nodes will be splitted\n this.wrapRangeInMappedTextNode(dict, start, end, node => {\n return filterCb(match[matchIdx], node);\n }, (node, lastIndex) => {\n regex.lastIndex = lastIndex;\n eachCb(node);\n });\n }\n endCb();\n });\n }\n\n /**\n * Callback for each wrapped element\n * @callback Mark~wrapRangeFromIndexEachCallback\n * @param {HTMLElement} element - The marked DOM element\n * @param {Mark~rangeObject} range - the current range object; provided\n * start and length values will be numeric integers modified from the\n * provided original ranges.\n */\n /**\n * Filter callback before each wrapping\n * @callback Mark~wrapRangeFromIndexFilterCallback\n * @param {HTMLElement} node - The text node which includes the range\n * @param {Mark~rangeObject} range - the current range object\n * @param {string} match - string extracted from the matching range\n * @param {number} counter - A counter indicating the number of all marks\n */\n /**\n * Callback on end\n * @callback Mark~wrapRangeFromIndexEndCallback\n */\n /**\n * Wraps the indicated ranges across all HTML elements in all contexts\n * @param {Mark~setOfRanges} ranges\n * @param {Mark~wrapRangeFromIndexFilterCallback} filterCb\n * @param {Mark~wrapRangeFromIndexEachCallback} eachCb\n * @param {Mark~wrapRangeFromIndexEndCallback} endCb\n * @access protected\n */\n wrapRangeFromIndex(ranges, filterCb, eachCb, endCb) {\n this.getTextNodes(dict => {\n const originalLength = dict.value.length;\n ranges.forEach((range, counter) => {\n let {start, end, valid} = this.checkWhitespaceRanges(\n range,\n originalLength,\n dict.value\n );\n if (valid) {\n this.wrapRangeInMappedTextNode(dict, start, end, node => {\n return filterCb(\n node,\n range,\n dict.value.substring(start, end),\n counter\n );\n }, node => {\n eachCb(node, range);\n });\n }\n });\n endCb();\n });\n }\n\n /**\n * Unwraps the specified DOM node with its content (text nodes or HTML)\n * without destroying possibly present events (using innerHTML) and\n * normalizes the parent at the end (merge splitted text nodes)\n * @param {HTMLElement} node - The DOM node to unwrap\n * @access protected\n */\n unwrapMatches(node) {\n const parent = node.parentNode;\n let docFrag = document.createDocumentFragment();\n while (node.firstChild) {\n docFrag.appendChild(node.removeChild(node.firstChild));\n }\n parent.replaceChild(docFrag, node);\n if (!this.ie) { // use browser's normalize method\n parent.normalize();\n } else { // custom method (needs more time)\n this.normalizeTextNode(parent);\n }\n }\n\n /**\n * Normalizes text nodes. It's a workaround for the native normalize method\n * that has a bug in IE (see attached link). Should only be used in IE\n * browsers as it's slower than the native method.\n * @see {@link http://tinyurl.com/z5asa8c}\n * @param {HTMLElement} node - The DOM node to normalize\n * @access protected\n */\n normalizeTextNode(node) {\n if (!node) {\n return;\n }\n if (node.nodeType === 3) {\n while (node.nextSibling && node.nextSibling.nodeType === 3) {\n node.nodeValue += node.nextSibling.nodeValue;\n node.parentNode.removeChild(node.nextSibling);\n }\n } else {\n this.normalizeTextNode(node.firstChild);\n }\n this.normalizeTextNode(node.nextSibling);\n }\n\n /**\n * Callback when finished\n * @callback Mark~commonDoneCallback\n * @param {number} totalMatches - The number of marked elements\n */\n /**\n * @typedef Mark~commonOptions\n * @type {object.}\n * @property {string} [element=\"mark\"] - HTML element tag name\n * @property {string} [className] - An optional class name\n * @property {string[]} [exclude] - An array with exclusion selectors.\n * Elements matching those selectors will be ignored\n * @property {boolean} [iframes=false] - Whether to search inside iframes\n * @property {Mark~commonDoneCallback} [done]\n * @property {boolean} [debug=false] - Wheter to log messages\n * @property {object} [log=window.console] - Where to log messages (only if\n * debug is true)\n */\n /**\n * Callback for each marked element\n * @callback Mark~markRegExpEachCallback\n * @param {HTMLElement} element - The marked DOM element\n */\n /**\n * Callback if there were no matches\n * @callback Mark~markRegExpNoMatchCallback\n * @param {RegExp} regexp - The regular expression\n */\n /**\n * Callback to filter matches\n * @callback Mark~markRegExpFilterCallback\n * @param {HTMLElement} textNode - The text node which includes the match\n * @param {string} match - The matching string for the RegExp\n * @param {number} counter - A counter indicating the number of all marks\n */\n /**\n * These options also include the common options from\n * {@link Mark~commonOptions}\n * @typedef Mark~markRegExpOptions\n * @type {object.}\n * @property {Mark~markRegExpEachCallback} [each]\n * @property {Mark~markRegExpNoMatchCallback} [noMatch]\n * @property {Mark~markRegExpFilterCallback} [filter]\n */\n /**\n * Marks a custom regular expression\n * @param {RegExp} regexp - The regular expression\n * @param {Mark~markRegExpOptions} [opt] - Optional options object\n * @access public\n */\n markRegExp(regexp, opt) {\n this.opt = opt;\n this.log(`Searching with expression \"${regexp}\"`);\n let totalMatches = 0,\n fn = 'wrapMatches';\n const eachCb = element => {\n totalMatches++;\n this.opt.each(element);\n };\n if (this.opt.acrossElements) {\n fn = 'wrapMatchesAcrossElements';\n }\n this[fn](regexp, this.opt.ignoreGroups, (match, node) => {\n return this.opt.filter(node, match, totalMatches);\n }, eachCb, () => {\n if (totalMatches === 0) {\n this.opt.noMatch(regexp);\n }\n this.opt.done(totalMatches);\n });\n }\n\n /**\n * Callback for each marked element\n * @callback Mark~markEachCallback\n * @param {HTMLElement} element - The marked DOM element\n */\n /**\n * Callback if there were no matches\n * @callback Mark~markNoMatchCallback\n * @param {RegExp} term - The search term that was not found\n */\n /**\n * Callback to filter matches\n * @callback Mark~markFilterCallback\n * @param {HTMLElement} textNode - The text node which includes the match\n * @param {string} match - The matching term\n * @param {number} totalCounter - A counter indicating the number of all\n * marks\n * @param {number} termCounter - A counter indicating the number of marks\n * for the specific match\n */\n /**\n * @typedef Mark~markAccuracyObject\n * @type {object.}\n * @property {string} value - A accuracy string value\n * @property {string[]} limiters - A custom array of limiters. For example\n * [\"-\", \",\"]\n */\n /**\n * @typedef Mark~markAccuracySetting\n * @type {string}\n * @property {\"partially\"|\"complementary\"|\"exactly\"|Mark~markAccuracyObject}\n * [accuracy=\"partially\"] - Either one of the following string values:\n *
    \n *
  • partially: When searching for \"lor\" only \"lor\" inside\n * \"lorem\" will be marked
  • \n *
  • complementary: When searching for \"lor\" the whole word\n * \"lorem\" will be marked
  • \n *
  • exactly: When searching for \"lor\" only those exact words\n * will be marked. In this example nothing inside \"lorem\". This value\n * is equivalent to the previous option wordBoundary
  • \n *
\n * Or an object containing two properties:\n *
    \n *
  • value: One of the above named string values
  • \n *
  • limiters: A custom array of string limiters for accuracy\n * \"exactly\" or \"complementary\"
  • \n *
\n */\n /**\n * @typedef Mark~markWildcardsSetting\n * @type {string}\n * @property {\"disabled\"|\"enabled\"|\"withSpaces\"}\n * [wildcards=\"disabled\"] - Set to any of the following string values:\n *
    \n *
  • disabled: Disable wildcard usage
  • \n *
  • enabled: When searching for \"lor?m\", the \"?\" will match zero\n * or one non-space character (e.g. \"lorm\", \"loram\", \"lor3m\", etc). When\n * searching for \"lor*m\", the \"*\" will match zero or more non-space\n * characters (e.g. \"lorm\", \"loram\", \"lor123m\", etc).
  • \n *
  • withSpaces: When searching for \"lor?m\", the \"?\" will\n * match zero or one space or non-space character (e.g. \"lor m\", \"loram\",\n * etc). When searching for \"lor*m\", the \"*\" will match zero or more space\n * or non-space characters (e.g. \"lorm\", \"lore et dolor ipsum\", \"lor: m\",\n * etc).
  • \n *
\n */\n /**\n * @typedef Mark~markIgnorePunctuationSetting\n * @type {string[]}\n * @property {string} The strings in this setting will contain punctuation\n * marks that will be ignored:\n *
    \n *
  • These punctuation marks can be between any characters, e.g. setting\n * this option to [\"'\"] would match \"Worlds\", \"World's\" and\n * \"Wo'rlds\"
  • \n *
  • One or more apostrophes between the letters would still produce a\n * match (e.g. \"W'o''r'l'd's\").
  • \n *
  • A typical setting for this option could be as follows:\n *
    ignorePunctuation: \":;.,-–—‒_(){}[]!'\\\"+=\".split(\"\"),
    This\n * setting includes common punctuation as well as a minus, en-dash,\n * em-dash and figure-dash\n * ({@link https://en.wikipedia.org/wiki/Dash#Figure_dash ref}), as well\n * as an underscore.
  • \n *
\n */\n /**\n * These options also include the common options from\n * {@link Mark~commonOptions}\n * @typedef Mark~markOptions\n * @type {object.}\n * @property {boolean} [separateWordSearch=true] - Whether to search for\n * each word separated by a blank instead of the complete term\n * @property {boolean} [diacritics=true] - If diacritic characters should be\n * matched. ({@link https://en.wikipedia.org/wiki/Diacritic Diacritics})\n * @property {object} [synonyms] - An object with synonyms. The key will be\n * a synonym for the value and the value for the key\n * @property {Mark~markAccuracySetting} [accuracy]\n * @property {Mark~markWildcardsSetting} [wildcards]\n * @property {boolean} [acrossElements=false] - Whether to find matches\n * across HTML elements. By default, only matches within single HTML\n * elements will be found\n * @property {boolean} [ignoreJoiners=false] - Whether to ignore word\n * joiners inside of key words. These include soft-hyphens, zero-width\n * space, zero-width non-joiners and zero-width joiners.\n * @property {Mark~markIgnorePunctuationSetting} [ignorePunctuation]\n * @property {Mark~markEachCallback} [each]\n * @property {Mark~markNoMatchCallback} [noMatch]\n * @property {Mark~markFilterCallback} [filter]\n */\n /**\n * Marks the specified search terms\n * @param {string|string[]} [sv] - Search value, either a search string or\n * an array containing multiple search strings\n * @param {Mark~markOptions} [opt] - Optional options object\n * @access public\n */\n mark(sv, opt) {\n this.opt = opt;\n let totalMatches = 0,\n fn = 'wrapMatches';\n\n const {\n keywords: kwArr,\n length: kwArrLen\n } = this.getSeparatedKeywords(typeof sv === 'string' ? [sv] : sv),\n sens = this.opt.caseSensitive ? '' : 'i',\n handler = kw => { // async function calls as iframes are async too\n let regex = new RegExp(this.createRegExp(kw), `gm${sens}`),\n matches = 0;\n this.log(`Searching with expression \"${regex}\"`);\n this[fn](regex, 1, (term, node) => {\n return this.opt.filter(node, kw, totalMatches, matches);\n }, element => {\n matches++;\n totalMatches++;\n this.opt.each(element);\n }, () => {\n if (matches === 0) {\n this.opt.noMatch(kw);\n }\n if (kwArr[kwArrLen - 1] === kw) {\n this.opt.done(totalMatches);\n } else {\n handler(kwArr[kwArr.indexOf(kw) + 1]);\n }\n });\n };\n if (this.opt.acrossElements) {\n fn = 'wrapMatchesAcrossElements';\n }\n if (kwArrLen === 0) {\n this.opt.done(totalMatches);\n } else {\n handler(kwArr[0]);\n }\n }\n\n /**\n * Callback for each marked element\n * @callback Mark~markRangesEachCallback\n * @param {HTMLElement} element - The marked DOM element\n * @param {array} range - array of range start and end points\n */\n /**\n * Callback if a processed range is invalid, out-of-bounds, overlaps another\n * range, or only matches whitespace\n * @callback Mark~markRangesNoMatchCallback\n * @param {Mark~rangeObject} range - a range object\n */\n /**\n * Callback to filter matches\n * @callback Mark~markRangesFilterCallback\n * @param {HTMLElement} node - The text node which includes the range\n * @param {array} range - array of range start and end points\n * @param {string} match - string extracted from the matching range\n * @param {number} counter - A counter indicating the number of all marks\n */\n /**\n * These options also include the common options from\n * {@link Mark~commonOptions}\n * @typedef Mark~markRangesOptions\n * @type {object.}\n * @property {Mark~markRangesEachCallback} [each]\n * @property {Mark~markRangesNoMatchCallback} [noMatch]\n * @property {Mark~markRangesFilterCallback} [filter]\n */\n /**\n * Marks an array of objects containing a start with an end or length of the\n * string to mark\n * @param {Mark~setOfRanges} rawRanges - The original (preprocessed)\n * array of objects\n * @param {Mark~markRangesOptions} [opt] - Optional options object\n * @access public\n */\n markRanges(rawRanges, opt) {\n this.opt = opt;\n let totalMatches = 0,\n ranges = this.checkRanges(rawRanges);\n if (ranges && ranges.length) {\n this.log(\n 'Starting to mark with the following ranges: ' +\n JSON.stringify(ranges)\n );\n this.wrapRangeFromIndex(\n ranges, (node, range, match, counter) => {\n return this.opt.filter(node, range, match, counter);\n }, (element, range) => {\n totalMatches++;\n this.opt.each(element, range);\n }, () => {\n this.opt.done(totalMatches);\n }\n );\n } else {\n this.opt.done(totalMatches);\n }\n }\n\n /**\n * Removes all marked elements inside the context with their HTML and\n * normalizes the parent at the end\n * @param {Mark~commonOptions} [opt] - Optional options object\n * @access public\n */\n unmark(opt) {\n this.opt = opt;\n let sel = this.opt.element ? this.opt.element : '*';\n sel += '[data-markjs]';\n if (this.opt.className) {\n sel += `.${this.opt.className}`;\n }\n this.log(`Removal selector \"${sel}\"`);\n this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT, node => {\n this.unwrapMatches(node);\n }, node => {\n const matchesSel = DOMIterator.matches(node, sel),\n matchesExclude = this.matchesExclude(node);\n if (!matchesSel || matchesExclude) {\n return NodeFilter.FILTER_REJECT;\n } else {\n return NodeFilter.FILTER_ACCEPT;\n }\n }, this.opt.done);\n }\n}\n", "import MarkJS from './lib/mark';\n\nexport default function Mark(ctx) {\n const instance = new MarkJS(ctx);\n this.mark = (sv, opt) => {\n instance.mark(sv, opt);\n return this;\n };\n this.markRegExp = (sv, opt) => {\n instance.markRegExp(sv, opt);\n return this;\n };\n this.markRanges = (sv, opt) => {\n instance.markRanges(sv, opt);\n return this;\n };\n this.unmark = (opt) => {\n instance.unmark(opt);\n return this;\n };\n return this;\n}"], - "mappings": "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", - "names": ["ctx", "ifr", "node", "dct", "Mark"] -} diff --git a/docs/.vitepress/cache/deps/vue.js.map b/docs/.vitepress/cache/deps/vue.js.map deleted file mode 100644 index 9865211..0000000 --- a/docs/.vitepress/cache/deps/vue.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": [], - "sourcesContent": [], - "mappings": "", - "names": [] -} diff --git a/docs/0.2.3/sponsors.md b/docs/0.2.3/sponsors.md index 818e856..727d086 100644 --- a/docs/0.2.3/sponsors.md +++ b/docs/0.2.3/sponsors.md @@ -12,7 +12,7 @@ Generator is an MIT-licensed open-source project and is completely free to use. ### Give it personally to our core team member -- [Mohammad Zulfahmi (Author)](https://zzzul.me) +- [Mohammad Zulfahmi](https://github.com/Zzzul/) (Author) - [GitHub Sponsor](https://github.com/sponsors/Zzzul) - [Buymeacoffe](https://www.buymeacoffee.com/mzulfahmi) - [Ko-fi](https://ko-fi.com/mzulfahmi) @@ -31,7 +31,7 @@ const members = [ { avatar: 'https://www.github.com/Zzzul.png', name: 'Mohammad Zulfahmi', - title: 'Creator', + title: 'Author', links: [ { icon: 'github', link: 'https://github.com/Zzzul' }, ] diff --git a/docs/0.2.3/usage.md b/docs/0.2.3/usage.md index 5d8c2fe..af3e481 100644 --- a/docs/0.2.3/usage.md +++ b/docs/0.2.3/usage.md @@ -1,5 +1,18 @@ --- outline: deep +lastUpdated: true +editLink: true +title: Usage +titleTemplate: How to basic +description: Create your first CRUD's with Generator +head: + - - meta + - name: description + content: Create your first CRUD's with Generator + - - meta + - name: keywords + content: Usage Generator +next: false --- ::: warning diff --git a/docs/contributions.md b/docs/contributions.md index 063cf02..892d79e 100644 --- a/docs/contributions.md +++ b/docs/contributions.md @@ -4,11 +4,11 @@ lastUpdated: true editLink: true title: How to Contribute titleTemplate: Let's contribute -description: How to contribute to this project +description: How to contribute to Generator head: - - meta - name: description - content: How to contribute to this project + content: How to contribute to Generator - - meta - name: keywords content: How to contribute to Generator diff --git a/docs/features.md b/docs/features.md index 314354f..9de84aa 100644 --- a/docs/features.md +++ b/docs/features.md @@ -12,7 +12,7 @@ head: - - meta - name: keywords content: Generator Features - +next: true --- # Available Features @@ -87,7 +87,12 @@ The helper class is placed in `App\Generators\helper.php` Checks whether the menu on the Sidebar matches the accessed uri. ```php -is_active_menu(string|array $menu): boolean; +/** + * @param string|array $route + * @return string ('' || 'active') + */ +is_active_menu(string|array $route): string; ``` + #### `ImageService` This class is used to perform image upload and manipulation functions using [Intervention Image v3.x](https://image.intervention.io/v3), it's placed in `App\Generators\Services` \ No newline at end of file diff --git a/docs/get-started.md b/docs/get-started.md index 5853c2f..cd0fa19 100644 --- a/docs/get-started.md +++ b/docs/get-started.md @@ -1,3 +1,20 @@ +--- +outline: deep +lastUpdated: true +editLink: true +title: Getting Started +titleTemplate: Let's get started +description: Install your Generator for first time +head: + - - meta + - name: description + content: Install your Generator for first time + - - meta + - name: keywords + content: Getting Started Generator +next: true +--- + # Getting Started ### Requirements diff --git a/docs/id/0.2.3/features.md b/docs/id/0.2.3/features.md index f82a686..0aa28f1 100644 --- a/docs/id/0.2.3/features.md +++ b/docs/id/0.2.3/features.md @@ -1,11 +1,21 @@ --- outline: deep -title: Features +lastUpdated: true editLink: true +title: Fitur +titleTemplate: Fitur apa aja sih yang ada? +description: Mengetahui fitur-fitur yang ada pada Generator +head: + - - meta + - name: description + content: Fitur apa aja sih yang ada? + - - meta + - name: keywords + content: Fitur Generator --- ::: warning -kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. +Kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. ::: # Fitur diff --git a/docs/id/0.2.3/getting-started.md b/docs/id/0.2.3/getting-started.md index 6da2b7b..a596d39 100644 --- a/docs/id/0.2.3/getting-started.md +++ b/docs/id/0.2.3/getting-started.md @@ -1,9 +1,21 @@ --- outline: deep +lastUpdated: true +editLink: true +title: Mari Mulai +titleTemplate: Instal Generator untuk pertam kalinya +description: Cara meng-install Generator yang baik dan benar +head: + - - meta + - name: description + content: Meng-instal Generator + - - meta + - name: keywords + content: Install Generator --- ::: warning -kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. +Kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. ::: # Mari Mulai diff --git a/docs/id/0.2.3/how-to-contribute.md b/docs/id/0.2.3/how-to-contribute.md index 592fdf1..de46beb 100644 --- a/docs/id/0.2.3/how-to-contribute.md +++ b/docs/id/0.2.3/how-to-contribute.md @@ -1,10 +1,24 @@ --- outline: deep +lastUpdated: true +editLink: true +title: Cara berkontribusi +titleTemplate: Mari ikut berkontribusi +description: Cara berkontribusi di Generator +head: + - - meta + - name: description + content: Cara berkontribusi di Generator + - - meta + - name: keywords + content: Cara berkontribusi di Generator +next: true --- ::: warning -kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. +Kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. ::: + # Cara Berkontribusi ### kamu dapat berkontribusi pada proyek ini, dengan mengikuti langkah-langkah berikut: diff --git a/docs/id/0.2.3/index.md b/docs/id/0.2.3/index.md index 13b3d91..773b807 100644 --- a/docs/id/0.2.3/index.md +++ b/docs/id/0.2.3/index.md @@ -15,7 +15,7 @@ head: --- ::: warning -kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. +Kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. ::: # Pengenalan @@ -24,11 +24,11 @@ kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolon ![image](https://user-images.githubusercontent.com/62506582/219941448-94c46fca-6a9f-422b-bdd1-29f642c3ccf6.png) -[Generator](https://github.com/Evdigi-INA/generator) adalah pustaka berbasis Laravel yang dapat digunakan untuk membangun kebutuhan dasar aplikasi seperti Baca, Tulis, Ubah, dan Hapus (_CRUD_). Ini adalah _Starter Template_ sederhana yang kami harap dapat membantu kamu dalam mengembangkan _CMS_, _Admin Panel_, atau aplikasi web lainnya yang mempunyai fungsionalitas _CRUD_. +[Generator](https://github.com/Evdigi-INA/generator) adalah pustaka berbasis Laravel yang dapat digunakan untuk membangun kebutuhan dasar aplikasi seperti Baca, Tulis, Ubah, dan Hapus (_CRUD_). Ini adalah _Starter Template_ sederhana yang kami harap dapat membantu kamu dalam mengembangkan _CMS_, _Admin Panel_ atau aplikasi web lainnya yang mempunyai fungsionalitas _CRUD_. ## Alasan -kami memiliki sedikit waktu untuk membuat Master _Main Data_ berulang kali, oleh karena itu pustaka ini mungkin dapat membantu kamu fokus pada fitur utama aplikasi kamu, Alih-alih, kamu bisa menggunakan waktu tersebut untuk tidur, bermain video gim, atau keluar dan menghabiskan waktu di dunia nyata. +kami memiliki sedikit waktu untuk membuat Master _Main Data_ berulang kali, oleh karena itu pustaka ini mungkin dapat membantu kamu fokus pada fitur utama aplikasi kamu, Alih-alih, kamu bisa menggunakan waktu tersebut untuk tidur, bermain video gim atau keluar dan menghabiskan waktu di dunia nyata. ## Siapa kami diff --git a/docs/id/0.2.3/sponsors.md b/docs/id/0.2.3/sponsors.md index 430278d..a653dfd 100644 --- a/docs/id/0.2.3/sponsors.md +++ b/docs/id/0.2.3/sponsors.md @@ -1,9 +1,23 @@ --- outline: deep +lastUpdated: true +editLink: true +title: Sponsor/supporter +titleTemplate: Berikan Dukunganmu +description: Berikkan dukunganmu kepada pada kontributor +head: + - - meta + - name: description + content: Berikkan dukunganmu kepada pada kontributor + - - meta + - name: keywords + content: Berikan Dukungan di Generator +next: false --- + ::: warning -kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. +Kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. ::: # Dukungan @@ -12,7 +26,7 @@ _Generator_ adalah proyek _Open-ource_ berlisensi _MIT_ dan sepenuhnya gratis un ### Berikan dukunganmu kepada tim inti kami -- [Mohammad Zulfahmi (Creator)](https://zzzul.me) +- [Mohammad Zulfahmi (Creator)](https://github.com/Zzzul/) - [GitHub Sponsor](https://github.com/sponsors/Zzzul) - [Buymeacoffe](https://www.buymeacoffee.com/mzulfahmi) - [Ko-fi](https://ko-fi.com/mzulfahmi) @@ -31,7 +45,7 @@ const members = [ { avatar: 'https://www.github.com/Zzzul.png', name: 'Mohammad Zulfahmi', - title: 'Creator', + title: 'Author', links: [ { icon: 'github', link: 'https://github.com/sponsors/Zzzul' }, { icon: 'linkedin', link: 'https://www.linkedin.com/in/mohammad-zulfahmi/' }, diff --git a/docs/id/0.2.3/usage.md b/docs/id/0.2.3/usage.md index e0e0a8e..6c26218 100644 --- a/docs/id/0.2.3/usage.md +++ b/docs/id/0.2.3/usage.md @@ -1,9 +1,22 @@ --- outline: deep +lastUpdated: true +editLink: true +title: Cara Pemakaian +titleTemplate: Cara pakai Generator +description: Cara pemakaian di Generator +head: + - - meta + - name: description + content: Cara pemakaian di Generator + - - meta + - name: keywords + content: Cara Pakai Generator +next: false --- ::: warning -kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. +Kamu sedang menjelajahi dokumentasi untuk versi _Generator_ yang lama nih. Tolong pertimbangkan untuk memperbarui proyek kamu ke versi [Generator 0.3.x](/id/introduction) yaa. ::: # Cara Pemakaian diff --git a/docs/id/contributions.md b/docs/id/contributions.md index dd781db..b146445 100644 --- a/docs/id/contributions.md +++ b/docs/id/contributions.md @@ -4,14 +4,14 @@ lastUpdated: true editLink: true title: Cara berkontribusi titleTemplate: Mari ikut berkontribusi -description: Cara berkontribusi pada proyek ini +description: Cara berkontribusi di Generator head: - - meta - name: description - content: Cara berkontribusi pada proyek ini + content: Cara berkontribusi di Generator - - meta - name: keywords - content: Cara berkontribusi to Generator + content: Cara berkontribusi di Generator next: true --- @@ -175,7 +175,7 @@ kamu dapat berkontribusi pada proyek ini, dengan mengikuti langkah-langkah berik ``` ```bash - git commit -m "describe your changes" + git commit -m "add cool feature" ``` 20. _Push_ perubahan kamu ke repositori diff --git a/docs/id/features.md b/docs/id/features.md index e63c4e9..3697d76 100644 --- a/docs/id/features.md +++ b/docs/id/features.md @@ -1,3 +1,19 @@ +--- +outline: deep +lastUpdated: true +editLink: true +title: Fitur +titleTemplate: Apa aja sih yang ada? +description: Mengetahui fitur-fitur yang ada pada Generator +head: + - - meta + - name: description + content: Fitur apa aja sih yang ada? + - - meta + - name: keywords + content: Fitur Generator +--- + # Fitur yang Tersedia Saat Ini Berikut adalah beberapa fitur yang tersedia saat ini dan dapat kamu coba. @@ -71,8 +87,13 @@ Kelas `helper` ditempatkan di `App\Generators\helper.php` #### Periksa menu aktif pada _Sidebar_ Cek menu pada _Sidebar_ apakah sesuai dengan _url_ yang sedang diakses. + ```php -is_active_menu(string|array $menu): boolean; +/** + * @param string|array $route + * @return string ('' || 'active') + */ +is_active_menu(string|array $route): string; ``` #### `ImageService` diff --git a/docs/id/introduction.md b/docs/id/introduction.md index 70cab5b..5571a7d 100644 --- a/docs/id/introduction.md +++ b/docs/id/introduction.md @@ -22,11 +22,11 @@ Tak Kenal Maka Tak Sayang ![Versi Sederhana](/simple-version.png) [Generator](https://github.com/Evdigi-INA/generator) adalah sebuah pustaka berbasis Laravel yang digunakan untuk membangun kebutuhan dasar aplikasi seperti _Create, Read, Update, dan Delete (CRUD)_. -Ini adalah template awal yang sederhana yang kami harap dapat membantu kamu dalam pengembangan _CMS_, Admin Panel, atau aplikasi web lain yang membutuhkan fungsi _CRUD_. +Ini adalah template awal yang sederhana yang kami harap dapat membantu kamu dalam pengembangan _CMS_, Admin Panel atau aplikasi web lain yang membutuhkan fungsi _CRUD_. ## Alasan Kami sering kali memiliki waktu terbatas untuk membuat master main data berulang kali, oleh karena itu kami harap pustaka ini dapat membantu kamu untuk fokus pada fitur inti aplikasi kamu. -Alih-alih, kamu dapat menggunakan waktu tersebut untuk tidur, berkumpul dengan teman atau keluarga, bermain video game, atau "menyentuh rumput". +Alih-alih, kamu dapat menggunakan waktu tersebut untuk tidur, berkumpul dengan teman atau keluarga, bermain video game atau "menyentuh rumput". ## Siapa Kami Kami adalah sekelompok orang yang terkadang bekerja sebagai _Freelance Developer_ di Bekasi, Indonesia 🇮🇩. Kami ingin membantu pengembang lain mempercepat pembuatan proyek mereka melalui perangkat lunak gratis yang kami buat. diff --git a/docs/id/sponsors.md b/docs/id/sponsors.md index a34bb22..62ad103 100644 --- a/docs/id/sponsors.md +++ b/docs/id/sponsors.md @@ -3,7 +3,7 @@ outline: deep lastUpdated: true editLink: true title: Berikan Dukungan -titleTemplate: Berikan Dukunganmu +titleTemplate: Dukunganmu sangat berarti description: Berikkan dukunganmu kepada pada kontributor head: - - meta @@ -22,7 +22,7 @@ _Generator_ adalah proyek _Open-ource_ berlisensi _MIT_ dan sepenuhnya gratis un ### Berikan dukunganmu kepada tim inti kami -- [Mohammad Zulfahmi (Creator)](https://zzzul.me) +- [Mohammad Zulfahmi](https://github.com/Zzzul/) (Author) - [GitHub Sponsor](https://github.com/sponsors/Zzzul) - [Buymeacoffe](https://www.buymeacoffee.com/mzulfahmi) - [Ko-fi](https://ko-fi.com/mzulfahmi) @@ -43,7 +43,7 @@ const members = [ name: 'Mohammad Zulfahmi', title: 'Author', links: [ - { icon: 'github', link: 'https://github.com/sponsors/Zzzul' }, + { icon: 'github', link: 'https://github.com/Zzzul' }, { icon: 'linkedin', link: 'https://www.linkedin.com/in/mohammad-zulfahmi/' }, ] }, @@ -53,6 +53,7 @@ const members = [ title: 'Core Team Member', links: [ { icon: 'github', link: 'https://github.com/rachyharkov' }, + { icon: 'linkedin', link: 'https://www.linkedin.com/in/rachmad-nur-hayat-731a391b2/' }, ] }, ] diff --git a/docs/id/upgrade-guide.md b/docs/id/upgrade-guide.md index c061871..a2dabcf 100644 --- a/docs/id/upgrade-guide.md +++ b/docs/id/upgrade-guide.md @@ -1,4 +1,22 @@ +--- +outline: deep +lastUpdated: true +editLink: true +title: Pembaruan +titleTemplate: Update untuk pengalaman yang lebih baik +description: Update Generator ke versi terakhir +head: + - - meta + - name: description + content: Update Generator ke versi terakhir + - - meta + - name: keywords + content: Pembaruan Generator +next: true +--- + # Apa aja sih yang baru? + Setiap perubahan itu pasti ada dan wajar, jadi kami harap kamu dapat menerima perubahan ini yaa. ## Perubahan dengan versi terbau @@ -33,28 +51,28 @@ Untuk daftar perubahan terbaru dan lebih lengkap, silakan kunjungi [GitHub Rilis ```json "require": { - "laravel/framework to": "^11.0", // [!code focus] + "laravel/framework": "^11.0", // [!code focus] }, "require-dev": { "nunomaduro/collision": "^8.1", // [!code focus] "evdigiina/generator": "^0.3.0", // [!code focus] - } + } ``` - Opsional, jika kamu menggunakannya +Opsional, jika kamu menggunakannya - ```json - "require": { - "spatie/laravel-permission": "^6.0", // [!code focus] - "laravel/fortify": "^1.21" // [!code focus] - }, - ``` +```json +"require": { + "spatie/laravel-permission": "^6.0", // [!code focus] + "laravel/fortify": "^1.21" // [!code focus] +}, +``` - Lalu jalankan perintah berikut +Lalu jalankan perintah berikut - ```sh - composer update - ``` +```sh +composer update +``` 3. Publikasikan berkas terbaru @@ -131,63 +149,63 @@ Untuk daftar perubahan terbaru dan lebih lengkap, silakan kunjungi [GitHub Rilis @endauth // [!code focus] - ``` + ``` 5. Ubah kode pada `resources/views/layouts/header.blade.php` menjadi seperti dibawah ini - ```blade - - ``` - -6. Buat file `generator.cache` di `vendor/evdigiina/generator` lalu _copy_ kode di bawah ini +6. Buat file `generator.cache` di folder `storage` lalu _copy_ kode di bawah ini ```json { "simple_version_publish_count": 0, "full_version_publish_count": 1 } @@ -199,35 +217,33 @@ Ubah `simple_version_publish_count` atau `full_version_publish_count` menjadi `1 7. Ubah `config/generator.php` dari `image.path` menjadi `image.disk` - ```php - "image" => [ - /** - * Path for store the image. - * - * available options: - * 1. public - * 2. storage - */ - "path" => "storage", // [!code focus] - ] - ``` - - - ```php - "image" => [ - /** - * Image storage location - * - * Available options: - * 1. public - * 2. storage - * 3. S3 - */ - "disk" => "storage", // [!code focus] - // ... another configuration - ] - ``` + ```php + "image" => [ + /** + * Path for store the image. + * + * available options: + * 1. public + * 2. storage + */ + "path" => "storage", // [!code focus] + ] + ``` + ```php + "image" => [ + /** + * Image storage location + * + * Available options: + * 1. public + * 2. storage + * 3. S3 + */ + "disk" => "storage", // [!code focus] + // ... another configuration + ] + ``` Untuk informasi tambahan tentang perubahan ini, [buka di sini](#fitur-terbaru) @@ -251,40 +267,41 @@ Ubah `simple_version_publish_count` atau `full_version_publish_count` menjadi `1 // new Middleware('permission:permission_name delete', only: ['destroy']), ]; } - ``` + ``` - Ubah menjadi Laravel 10 _Middleware_ seperti di bawah ini + Ubah menjadi Laravel 10 _Middleware_ seperti di bawah ini - ```php - public function __construct() - { - $this->middleware('permission:permission_name view')->only('index', 'show'); - $this->middleware('permission:permission_name create')->only('create', 'store'); - $this->middleware('permission:permission_name edit')->only('edit', 'update'); - $this->middleware('permission:permission_name delete')->only('destroy'); - } - ``` + ```php + public function __construct() + { + $this->middleware('permission:permission_name view')->only('index', 'show'); + $this->middleware('permission:permission_name create')->only('create', 'store'); + $this->middleware('permission:permission_name edit')->only('edit', 'update'); + $this->middleware('permission:permission_name delete')->only('destroy'); + } + ``` - Dari + Dari - ```php - use Illuminate\Routing\Controllers\{HasMiddleware, Middleware}; // [!code focus] + ```php + use Illuminate\Routing\Controllers\{HasMiddleware, Middleware}; // [!code focus] - class YourController extends Controller implements HasMiddleware // [!code focus] - { - //... - } - ``` - Menjadi + class YourController extends Controller implements HasMiddleware // [!code focus] + { + //... + } + ``` - ```php - // use Illuminate\Routing\Controllers\{HasMiddleware, Middleware}; // [!code focus] + Menjadi - class YourController extends Controller // [!code focus] - { - //... - } - ``` + ```php + // use Illuminate\Routing\Controllers\{HasMiddleware, Middleware}; // [!code focus] + + class YourController extends Controller // [!code focus] + { + //... + } + ``` Jangan lupa hapus atau berikan komentar pada kode `use Illuminate\Routing\Controllers\{HasMiddleware, Middleware};` @@ -306,7 +323,7 @@ Fitur terbaru yang ditambahkan pada versi _Generator ^0.3.x_: Kelas ini digunakan untuk melakukan unggah gambar dan manipulasi gambar menggunakan [Intervention Image](https://image.intervention.io/v3) -5. Menambahkan opsi baru ke konfigurasi `generator.image.disk`, yang sebelumnya adalah `generator.image.path`, kini kamu dapat menggunakan opsi `public`, `storage`, atau `s3`. Berikut ini contohnya +5. Menambahkan opsi baru ke konfigurasi `generator.image.disk`, yang sebelumnya adalah `generator.image.path`, kini kamu dapat menggunakan opsi `public`, `storage` atau `s3`. Berikut ini contohnya ```php "image" => [ @@ -321,7 +338,7 @@ Fitur terbaru yang ditambahkan pada versi _Generator ^0.3.x_: * change path to disk */ "disk" => "storage", // [!code focus] - + // other configuration codes. ] ``` @@ -343,13 +360,15 @@ return [ */ "image" => [ // [!code focus] /** - * Path for store the image. + * Image storage location * * Available options: * 1. public * 2. storage * 3. S3 - */ + * + * change path to disk + */ "disk" => "storage", // [!code focus] /** @@ -496,4 +515,4 @@ return [ 6. Dokumentasi terbaru :book: - Kami kesulitan ketika membuat dokumentasi untuk banyak versi dan bahasa menggunakan [MkDocs](https://www.mkdocs.org/), oleh karena itu kami memutuskan untuk membuat dokumentasi baru menggunakan [Vitepress](https://vitepress.dev/ ). + Kami kesulitan ketika membuat dokumentasi untuk banyak versi dan bahasa menggunakan [MkDocs](https://www.mkdocs.org/), oleh karena itu kami memutuskan untuk membuat dokumentasi baru menggunakan [Vitepress](https://vitepress.dev/). diff --git a/docs/id/usage.md b/docs/id/usage.md index 3de8b0f..5932d88 100644 --- a/docs/id/usage.md +++ b/docs/id/usage.md @@ -1,7 +1,21 @@ --- outline: deep +lastUpdated: true +editLink: true +title: Cara Pemakaian +titleTemplate: Cara pakai Generator +description: Cara pemakaian di Generator +head: + - - meta + - name: description + content: Cara pemakaian di Generator + - - meta + - name: keywords + content: Cara Pakai Generator +next: true --- + # Cara Pakai yang Semoga Benar ### Buat _CRUD_ untuk pertama kalinya diff --git a/docs/introduction.md b/docs/introduction.md index cc0ff87..1d85f3c 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -1,5 +1,18 @@ --- outline: deep +lastUpdated: true +editLink: true +title: Introduction +titleTemplate: What is Generator? +description: Generator is an open-source Laravel toolkit for building essential administration interfaces with ease. +head: + - - meta + - name: description + content: Generator is an open-source Laravel toolkit for building essential administration interfaces with ease. + - - meta + - name: keywords + content: Introduction Generator +next: true --- # Introduction diff --git a/docs/sponsors.md b/docs/sponsors.md index bb74424..ed4f87c 100644 --- a/docs/sponsors.md +++ b/docs/sponsors.md @@ -21,7 +21,7 @@ Generator is an MIT-licensed open-source project and is completely free to use. ### Give it personally to our core team member -- [Mohammad Zulfahmi (Author)](https://zzzul.me) +- [Mohammad Zulfahmi](https://github.com/Zzzul/) (Author) - [GitHub Sponsor](https://github.com/sponsors/Zzzul) - [Buymeacoffe](https://www.buymeacoffee.com/mzulfahmi) - [Ko-fi](https://ko-fi.com/mzulfahmi) diff --git a/docs/upgrade-guide.md b/docs/upgrade-guide.md index e90d74a..6c90fe6 100644 --- a/docs/upgrade-guide.md +++ b/docs/upgrade-guide.md @@ -1,3 +1,20 @@ +--- +outline: deep +lastUpdated: true +editLink: true +title: Upgrade Guide +titleTemplate: Update for better experience +description: Update Generator to latest version +head: + - - meta + - name: description + content: Update Generator to latest version + - - meta + - name: keywords + content: Upgrade Guide Generator +next: true +--- + # What's New? ## Changes in the Latest Version @@ -30,7 +47,7 @@ For the most recent and complete changelog, please visit [Github Releases](https ```json "require": { - "laravel/framework to": "^11.0", // [!code focus] + "laravel/framework": "^11.0", // [!code focus] }, "require-dev": { "nunomaduro/collision": "^8.1", // [!code focus] @@ -179,7 +196,7 @@ For the most recent and complete changelog, please visit [Github Releases](https ``` -6. Create a file `generator.cache` in `vendor/evdigiina/generator` then copy the code below +6. Create a file `generator.cache` in `storage` folder then copy the code below ```json {"simple_version_publish_count":0,"full_version_publish_count":1} @@ -332,13 +349,15 @@ return [ */ "image" => [ // [!code focus] /** - * Path for store the image. + * Image storage location * * Available options: * 1. public * 2. storage * 3. S3 - */ + * + * change path to disk + */ "disk" => "storage", // [!code focus] /** diff --git a/docs/usage.md b/docs/usage.md index 75874fe..ce7b7a6 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,6 +1,20 @@ --- outline: deep +lastUpdated: true +editLink: true +title: Usage +titleTemplate: How to basic +description: Create your first CRUD's with Generator +head: + - - meta + - name: description + content: Create your first CRUD's with Generator + - - meta + - name: keywords + content: Usage Generator +next: true --- + # Usage ### Create your first CRUD