@plannotator/web-highlighter 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/environment.json +6 -0
- package/.eslintrc.js +250 -0
- package/.prettierrc +9 -0
- package/.travis.yml +17 -0
- package/CHANGELOG.md +220 -0
- package/LICENSE +21 -0
- package/README.md +371 -0
- package/README.zh_CN.md +367 -0
- package/config/base.config.js +25 -0
- package/config/base.example.config.js +38 -0
- package/config/paths.js +22 -0
- package/config/server.config.js +17 -0
- package/config/webpack.config.dev.js +18 -0
- package/config/webpack.config.example.js +20 -0
- package/config/webpack.config.prod.js +28 -0
- package/dist/data/cache.d.ts +13 -0
- package/dist/index.d.ts +58 -0
- package/dist/model/range/dom.d.ts +6 -0
- package/dist/model/range/index.d.ts +20 -0
- package/dist/model/range/selection.d.ts +14 -0
- package/dist/model/source/dom.d.ts +23 -0
- package/dist/model/source/index.d.ts +18 -0
- package/dist/painter/dom.d.ts +22 -0
- package/dist/painter/index.d.ts +19 -0
- package/dist/painter/style.d.ts +1 -0
- package/dist/types/index.d.ts +102 -0
- package/dist/util/camel.d.ts +5 -0
- package/dist/util/const.d.ts +41 -0
- package/dist/util/deferred.d.ts +9 -0
- package/dist/util/dom.d.ts +32 -0
- package/dist/util/event.emitter.d.ts +13 -0
- package/dist/util/hook.d.ts +15 -0
- package/dist/util/interaction.d.ts +6 -0
- package/dist/util/is.mobile.d.ts +5 -0
- package/dist/util/tool.d.ts +4 -0
- package/dist/util/uuid.d.ts +4 -0
- package/dist/web-highlighter.min.js +3 -0
- package/dist/web-highlighter.min.js.map +1 -0
- package/docs/ADVANCE.md +113 -0
- package/docs/ADVANCE.zh_CN.md +111 -0
- package/docs/img/create-flow.jpg +0 -0
- package/docs/img/create-flow.zh_CN.jpg +0 -0
- package/docs/img/logo.png +0 -0
- package/docs/img/remove-flow.jpg +0 -0
- package/docs/img/remove-flow.zh_CN.jpg +0 -0
- package/docs/img/sample.gif +0 -0
- package/example/index.css +2 -0
- package/example/index.js +214 -0
- package/example/local.store.js +72 -0
- package/example/my.css +119 -0
- package/example/tpl.html +59 -0
- package/package.json +103 -0
- package/script/build.js +17 -0
- package/script/convet-md.js +25 -0
- package/script/dev.js +22 -0
- package/src/data/cache.ts +57 -0
- package/src/index.ts +285 -0
- package/src/model/range/dom.ts +94 -0
- package/src/model/range/index.ts +88 -0
- package/src/model/range/selection.ts +55 -0
- package/src/model/source/dom.ts +66 -0
- package/src/model/source/index.ts +54 -0
- package/src/painter/dom.ts +345 -0
- package/src/painter/index.ts +199 -0
- package/src/painter/style.ts +21 -0
- package/src/types/index.ts +118 -0
- package/src/util/camel.ts +6 -0
- package/src/util/const.ts +54 -0
- package/src/util/deferred.ts +37 -0
- package/src/util/dom.ts +155 -0
- package/src/util/event.emitter.ts +45 -0
- package/src/util/hook.ts +52 -0
- package/src/util/interaction.ts +20 -0
- package/src/util/is.mobile.ts +7 -0
- package/src/util/tool.ts +14 -0
- package/src/util/uuid.ts +10 -0
- package/test/api.spec.ts +555 -0
- package/test/event.spec.ts +284 -0
- package/test/fixtures/broken.json +32 -0
- package/test/fixtures/index.html +11 -0
- package/test/fixtures/source.json +47 -0
- package/test/hook.spec.ts +244 -0
- package/test/integrate.spec.ts +48 -0
- package/test/mobile.spec.ts +87 -0
- package/test/option.spec.ts +212 -0
- package/test/util.spec.ts +244 -0
- package/test-newlines.html +226 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["webpack://Highlighter/webpack/universalModuleDefinition","webpack://Highlighter/webpack/bootstrap","webpack://Highlighter/./src/util/const.ts","webpack://Highlighter/./src/types/index.ts","webpack://Highlighter/./src/util/event.emitter.ts","webpack://Highlighter/./src/model/source/index.ts","webpack://Highlighter/./src/util/dom.ts","webpack://Highlighter/./src/model/range/index.ts","webpack://Highlighter/./src/model/range/selection.ts","webpack://Highlighter/./src/util/uuid.ts","webpack://Highlighter/./src/index.ts","webpack://Highlighter/./src/model/source/dom.ts","webpack://Highlighter/./src/util/camel.ts","webpack://Highlighter/./src/model/range/dom.ts","webpack://Highlighter/./src/util/hook.ts","webpack://Highlighter/./src/util/interaction.ts","webpack://Highlighter/./src/util/is.mobile.ts","webpack://Highlighter/./src/data/cache.ts","webpack://Highlighter/./src/painter/index.ts","webpack://Highlighter/./src/painter/dom.ts","webpack://Highlighter/./src/util/tool.ts","webpack://Highlighter/./src/painter/style.ts"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","ID_DIVISION","LOCAL_STORE_KEY","STYLESHEET_ID","DATASET_IDENTIFIER","DATASET_IDENTIFIER_EXTRA","DATASET_SPLIT_TYPE","CAMEL_DATASET_IDENTIFIER","CAMEL_DATASET_IDENTIFIER_EXTRA","CAMEL_DATASET_SPLIT_TYPE","getDefaultOptions","$root","document","documentElement","exceptSelectors","wrapTag","verbose","style","className","getStylesheet","ROOT_IDX","UNKNOWN_IDX","INTERNAL_ERROR_EVENT","eventEmitter","ErrorEventEmitter","SplitType","ERROR","EventType","CreateFrom","SelectedNodeType","UserInputEvent","handlersMap","on","type","handler","this","push","off","splice","indexOf","emit","slice","forEach","data","EventEmitter","startMeta","endMeta","text","id","extra","__isHighlightSource","deSerialize","hooks","queryElementNode","start","end","startInfo","getTextChildByOffset","textOffset","endInfo","Serialize","Restore","isEmpty","res","HighlightSource","isHighlightWrapNode","$node","dataset","findAncestorWrapperInRoot","isInsideRoot","$wrapper","parentNode","getHighlightId","getExtraHighlightId","split","filter","getHighlightsByRoot","$roots","Array","isArray","$wraps","$list","querySelectorAll","apply","getHighlightById","$highlights","reg","RegExp","$n","extraId","test","$nodes","cb","length","removeEventListener","$el","evt","fn","addEventListener","addClass","classList","add","removeClass","remove","removeAllClass","hasClass","contains","frozen","nodeType","RANGE_NODE_INVALID","formatDomNode","fromSelection","idHook","range","getDomRange","startContainer","offset","startOffset","endContainer","endOffset","selection","getSelection","toString","HighlightRange","serialize","getDomMeta","RecordInfo","removeDomRange","removeSelection","isCollapsed","console","debug","getRangeAt","removeAllRanges","getTextFromRange","fragment","cloneContents","temp","createElement","cssText","body","appendChild","innerText","e","createUUID","a","Math","random","replace","options","event","run","PointerEnd","_handleSelection","stop","getDoms","getIdByDom","getExtraIdByDom","dispose","PointerOver","_handleHighlightHover","PointerTap","_handleHighlightClick","removeAll","setOption","painter","fromRange","Render","UUID","hRange","_highlightFromHRange","RANGE_INVALID","fromStore","hs","_highlightFromHSource","err","HIGHLIGHT_SOURCE_RECREATE","error","detail","_getHooks","SelectedNodes","WrapNode","Remove","UpdateNodes","source","highlightRange","DOM_SELECTION_EMPTY","cache","save","CREATE","sources","INPUT","$target","target","_hoverId","HOVER_OUT","HOVER","_handleError","warn","CLICK","doseExist","removeHighlight","REMOVE","ids","removeAllHighlight","renderedSources","highlightSource","STORE","isHighlightSource","Highlighter","$parent","nodeStack","$curNode","curOffset","pop","children","childNodes","textContent","parentIndex","getElementsByTagName","parentTagName","reduce","str","idx","toUpperCase","$originParent","HTMLElement","getOriginParent","index","tagName","countGlobalNodeIndex","preNodeOffset","$text","getTextPreOffset","ops","tap","ret","op","args","Hook","isMobile","navigator","userAgent","touchend","mouseup","touchstart","click","mouseover","regMobile","_data","Map","getAll","map","CACHE_SET_ERROR","set","delete","list","pair","Cache","initDefaultStylesheet","HIGHLIGHT_RANGE_FROZEN","$selectedNodes","getSelectedNodes","wrapHighlight","HIGHLIGHT_SOURCE_NONE_RENDER","SOURCE_TYPE_ERROR","$spans","$toRemove","$idToUpdate","$extraToUpdate","$s","spanId","spanExtraIds","$fr","createDocumentFragment","$c","cloneNode","$prev","previousSibling","$next","nextSibling","replaceChild","normalizeSiblingText","newId","shift","$overlapSpan","querySelector","join","extraIds","isMatchSelector","selector","$startNode","$endNode","Text","$element","isExcepted","$e","some","splitText","passedNode","splitType","both","getNodesIfSameStartEnd","selectedNodes","withinSelectedRange","curNode","node","head","tail","none","classNames","isNodeEmpty","selected","$wrap","formerId","wrapOverlapNode","parentId","parentExtraId","extraInfo","setAttribute","headSplit","tailSplit","$span","classNameList","unique","wrapPartialNode","wrapNewNode","isNext","$sibling","nodeValue","removeChild","arr","el","styleId","$style","getElementById","$cssNode","createTextNode"],"mappings":"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","file":"web-highlighter.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"Highlighter\"] = factory();\n\telse\n\t\troot[\"Highlighter\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 8);\n","/**\n * all constants\n * cSpell:ignore mengshou\n */\n\nimport type HighlightSource from '@src/model/source';\nimport type { ERROR } from '@src/types';\nimport camel from '@src/util/camel';\nimport EventEmitter from '@src/util/event.emitter';\n\nexport const ID_DIVISION = ';';\nexport const LOCAL_STORE_KEY = 'highlight-mengshou';\nexport const STYLESHEET_ID = 'highlight-mengshou-style';\n\nexport const DATASET_IDENTIFIER = 'highlight-id';\nexport const DATASET_IDENTIFIER_EXTRA = 'highlight-id-extra';\nexport const DATASET_SPLIT_TYPE = 'highlight-split-type';\nexport const CAMEL_DATASET_IDENTIFIER = camel(DATASET_IDENTIFIER);\nexport const CAMEL_DATASET_IDENTIFIER_EXTRA = camel(DATASET_IDENTIFIER_EXTRA);\nexport const CAMEL_DATASET_SPLIT_TYPE = camel(DATASET_SPLIT_TYPE);\n\nconst DEFAULT_WRAP_TAG = 'span';\n\nexport const getDefaultOptions = () => ({\n $root: document || document.documentElement,\n exceptSelectors: null,\n wrapTag: DEFAULT_WRAP_TAG,\n verbose: false,\n style: {\n className: 'highlight-mengshou-wrap',\n },\n});\n\nexport const getStylesheet = () => `\n .${getDefaultOptions().style.className} {\n background: #ff9;\n cursor: pointer;\n }\n .${getDefaultOptions().style.className}.active {\n background: #ffb;\n }\n`;\n\nexport const ROOT_IDX = -2;\nexport const UNKNOWN_IDX = -1;\nexport const INTERNAL_ERROR_EVENT = 'error';\n\ninterface EventHandlerMap {\n [key: string]: (...args: any[]) => void;\n error: (data: { type: ERROR; detail?: HighlightSource; error?: any }) => void;\n}\nclass ErrorEventEmitter extends EventEmitter<EventHandlerMap> {}\n\nexport const eventEmitter = new ErrorEventEmitter();\n","import type Hook from '@src/util/hook';\n\nexport type RootElement = Document | HTMLElement;\n\nexport interface HighlighterOptions {\n $root?: RootElement;\n exceptSelectors?: string[];\n wrapTag?: string;\n verbose?: boolean;\n style?: {\n className?: string[] | string;\n };\n}\n\nexport interface PainterOptions {\n $root: RootElement;\n wrapTag: string;\n className: string[] | string;\n exceptSelectors: string[];\n}\n\nexport enum SplitType {\n none = 'none',\n head = 'head',\n tail = 'tail',\n both = 'both',\n}\n\nexport enum ERROR {\n DOM_TYPE_ERROR = '[DOM] Receive wrong node type.',\n DOM_SELECTION_EMPTY = '[DOM] The selection contains no dom node, may be you except them.',\n RANGE_INVALID = \"[RANGE] Got invalid dom range, can't convert to a valid highlight range.\",\n RANGE_NODE_INVALID = \"[RANGE] Start or end node isn't a text node, it may occur an error.\",\n DB_ID_DUPLICATE_ERROR = '[STORE] Unique id conflict.',\n CACHE_SET_ERROR = \"[CACHE] Cache.data can't be set manually, please use .save().\",\n SOURCE_TYPE_ERROR = \"[SOURCE] Object isn't a highlight source instance.\",\n HIGHLIGHT_RANGE_FROZEN = '[HIGHLIGHT_RANGE] A highlight range must be frozen before render.',\n HIGHLIGHT_SOURCE_RECREATE = '[HIGHLIGHT_SOURCE] Recreate highlights from sources error.',\n // eslint-disable-next-line max-len\n HIGHLIGHT_SOURCE_NONE_RENDER = \"[HIGHLIGHT_SOURCE] This highlight source isn't rendered. May be the exception skips it or the dom structure has changed.\",\n}\n\nexport enum EventType {\n CREATE = 'selection:create',\n REMOVE = 'selection:remove',\n MODIFY = 'selection:modify',\n HOVER = 'selection:hover',\n HOVER_OUT = 'selection:hover-out',\n CLICK = 'selection:click',\n}\n\nexport enum CreateFrom {\n STORE = 'from-store',\n INPUT = 'from-input',\n}\n\nexport enum SelectedNodeType {\n text = 'text',\n span = 'span',\n}\n\nexport interface SelectedNode {\n $node: Node | Text;\n type: SelectedNodeType;\n splitType: SplitType;\n}\n\nexport interface DomMeta {\n parentTagName: string;\n parentIndex: number;\n textOffset: number;\n extra?: unknown;\n}\n\nexport interface DomNode {\n $node: Node;\n offset: number;\n}\n\nexport interface HighlightPosition {\n start: {\n top: number;\n left: number;\n };\n end: {\n top: number;\n left: number;\n };\n}\n\nexport interface HookMap {\n Render: {\n UUID: Hook<string>;\n SelectedNodes: Hook<SelectedNode[]>;\n WrapNode: Hook<HTMLElement>;\n };\n Serialize: {\n Restore: Hook<DomNode[]>;\n RecordInfo: Hook<string>;\n };\n Remove: {\n UpdateNodes: Hook;\n };\n}\n\nexport enum UserInputEvent {\n touchend = 'touchend',\n mouseup = 'mouseup',\n touchstart = 'touchstart',\n click = 'click',\n mouseover = 'mouseover',\n}\n\nexport interface IInteraction {\n PointerEnd: UserInputEvent;\n PointerTap: UserInputEvent;\n PointerOver: UserInputEvent;\n}\n","/**\n * tiny event emitter\n * modify from mitt\n */\n\ntype EventHandler = (...data: unknown[]) => void;\n\ntype EventMap = Record<string, EventHandler>;\ntype HandlersMap<T extends EventMap> = {\n [K in keyof T]: T[K][];\n};\n\nclass EventEmitter<U extends EventMap = EventMap> {\n private handlersMap: HandlersMap<U> = Object.create(null);\n\n on<T extends keyof U>(type: T, handler: U[T]) {\n if (!this.handlersMap[type]) {\n this.handlersMap[type] = [];\n }\n\n this.handlersMap[type].push(handler);\n\n return this;\n }\n\n off<T extends keyof U>(type: T, handler: U[T]) {\n if (this.handlersMap[type]) {\n this.handlersMap[type].splice(this.handlersMap[type].indexOf(handler) >>> 0, 1);\n }\n\n return this;\n }\n\n emit<T extends keyof U>(type: T, ...data: Parameters<U[T]>) {\n if (this.handlersMap[type]) {\n this.handlersMap[type].slice().forEach(handler => {\n handler(...data);\n });\n }\n\n return this;\n }\n}\n\nexport default EventEmitter;\n","/**\n * HighlightSource Class (HSource)\n * This Object can be deSerialized to HRange.\n * Also it has the ability for persistence.\n */\n\nimport type { DomMeta, HookMap, DomNode } from '@src/types';\nimport HighlightRange from '@src/model/range/index';\nimport { queryElementNode, getTextChildByOffset } from '@src/model/source/dom';\n\nclass HighlightSource {\n startMeta: DomMeta;\n\n endMeta: DomMeta;\n\n text: string;\n\n id: string;\n\n extra?: unknown;\n\n __isHighlightSource: unknown;\n\n constructor(startMeta: DomMeta, endMeta: DomMeta, text: string, id: string, extra?: unknown) {\n this.startMeta = startMeta;\n this.endMeta = endMeta;\n this.text = text;\n this.id = id;\n this.__isHighlightSource = {};\n\n if (extra) {\n this.extra = extra;\n }\n }\n\n deSerialize($root: Document | HTMLElement, hooks: HookMap): HighlightRange {\n const { start, end } = queryElementNode(this, $root);\n let startInfo = getTextChildByOffset(start, this.startMeta.textOffset);\n let endInfo = getTextChildByOffset(end, this.endMeta.textOffset);\n\n if (!hooks.Serialize.Restore.isEmpty()) {\n const res: DomNode[] = hooks.Serialize.Restore.call(this, startInfo, endInfo) || [];\n\n startInfo = res[0] || startInfo;\n endInfo = res[1] || endInfo;\n }\n\n const range = new HighlightRange(startInfo, endInfo, this.text, this.id, true);\n\n return range;\n }\n}\n\nexport default HighlightSource;\n","import type { RootElement } from '@src/types';\nimport {\n ID_DIVISION,\n DATASET_IDENTIFIER,\n CAMEL_DATASET_IDENTIFIER,\n CAMEL_DATASET_IDENTIFIER_EXTRA,\n} from '@src/util/const';\n\n/**\n * whether a wrapper node\n */\nexport const isHighlightWrapNode = ($node: HTMLElement): boolean =>\n !!$node.dataset && !!$node.dataset[CAMEL_DATASET_IDENTIFIER];\n\n/**\n * ===================================================================================\n * below methods (getHighlightId/getExtraHighlightId)\n * will check whether the node is inside a wrapper iteratively util reach the root node\n * if the node is not inside the root, the id must be empty\n * ====================================================================================\n */\n\nconst findAncestorWrapperInRoot = ($node: HTMLElement, $root: RootElement): HTMLElement => {\n let isInsideRoot = false;\n let $wrapper: HTMLElement = null;\n\n while ($node) {\n if (isHighlightWrapNode($node)) {\n $wrapper = $node;\n }\n\n if ($node === $root) {\n isInsideRoot = true;\n break;\n }\n\n $node = $node.parentNode as HTMLElement;\n }\n\n return isInsideRoot ? $wrapper : null;\n};\n\n/**\n * get highlight id by a node\n */\nexport const getHighlightId = ($node: HTMLElement, $root: RootElement): string => {\n $node = findAncestorWrapperInRoot($node, $root);\n\n if (!$node) {\n return '';\n }\n\n return $node.dataset[CAMEL_DATASET_IDENTIFIER];\n};\n\n/**\n * get extra highlight id by a node\n */\nexport const getExtraHighlightId = ($node: HTMLElement, $root: RootElement): string[] => {\n $node = findAncestorWrapperInRoot($node, $root);\n\n if (!$node) {\n return [];\n }\n\n return $node.dataset[CAMEL_DATASET_IDENTIFIER_EXTRA].split(ID_DIVISION).filter(i => i);\n};\n\n/**\n * get all highlight wrapping nodes nodes from a root node\n */\nexport const getHighlightsByRoot = ($roots: RootElement | RootElement[], wrapTag: string): HTMLElement[] => {\n if (!Array.isArray($roots)) {\n $roots = [$roots];\n }\n\n const $wraps: HTMLElement[] = [];\n\n for (const $r of $roots) {\n const $list = $r.querySelectorAll<HTMLElement>(`${wrapTag}[data-${DATASET_IDENTIFIER}]`);\n\n // eslint-disable-next-line prefer-spread\n $wraps.push.apply($wraps, $list);\n }\n\n return $wraps;\n};\n\n/**\n * get all highlight wrapping nodes by highlight id from a root node\n */\nexport const getHighlightById = ($root: RootElement, id: string, wrapTag: string): HTMLElement[] => {\n const $highlights: HTMLElement[] = [];\n const reg = new RegExp(`(${id}\\\\${ID_DIVISION}|\\\\${ID_DIVISION}?${id}$)`);\n const $list = $root.querySelectorAll<HTMLElement>(`${wrapTag}[data-${DATASET_IDENTIFIER}]`);\n\n for (const $l of $list) {\n const $n = $l;\n const nid = $n.dataset[CAMEL_DATASET_IDENTIFIER];\n\n if (nid === id) {\n $highlights.push($n);\n continue;\n }\n\n const extraId = $n.dataset[CAMEL_DATASET_IDENTIFIER_EXTRA];\n\n if (reg.test(extraId)) {\n $highlights.push($n);\n continue;\n }\n }\n\n return $highlights;\n};\n\nexport const forEach = ($nodes: NodeList, cb: (n: Node, idx: number, s: NodeList) => void): void => {\n for (let i = 0; i < $nodes.length; i++) {\n cb($nodes[i], i, $nodes);\n }\n};\n\nexport const removeEventListener = ($el: RootElement, evt: string, fn: EventListenerOrEventListenerObject) => {\n $el.removeEventListener(evt, fn);\n};\n\n/**\n * maybe be need some polyfill methods later\n * provide unified dom methods for compatibility\n */\nexport const addEventListener = ($el: RootElement, evt: string, fn: EventListenerOrEventListenerObject) => {\n $el.addEventListener(evt, fn);\n\n return () => {\n removeEventListener($el, evt, fn);\n };\n};\n\nexport const addClass = ($el: HTMLElement, className: string[] | string) => {\n if (!Array.isArray(className)) {\n className = [className];\n }\n\n $el.classList.add(...className);\n};\n\nexport const removeClass = ($el: HTMLElement, className: string): void => {\n $el.classList.remove(className);\n};\n\nexport const removeAllClass = ($el: HTMLElement): void => {\n $el.className = '';\n};\n\nexport const hasClass = ($el: HTMLElement, className: string): boolean => $el.classList.contains(className);\n","/**\n * the HighlightRange Class(HRange)\n * It's a special object called HRange in Highlighter,\n * represents for a piece of chosen dom\n */\n\nimport type { DomNode, HookMap } from '@src/types';\nimport type Hook from '@src/util/hook';\nimport HighlightSource from '@src/model/source/index';\nimport { ERROR } from '@src/types';\nimport { getDomRange, removeSelection } from '@src/model/range/selection';\nimport uuid from '@src/util/uuid';\nimport { getDomMeta, formatDomNode } from '@src/model/range/dom';\nimport { eventEmitter, INTERNAL_ERROR_EVENT } from '@src/util/const';\n\nclass HighlightRange {\n static removeDomRange = removeSelection;\n\n start: DomNode;\n\n end: DomNode;\n\n text: string;\n\n id: string;\n\n frozen: boolean;\n\n constructor(start: DomNode, end: DomNode, text: string, id: string, frozen = false) {\n if (start.$node.nodeType !== 3 || end.$node.nodeType !== 3) {\n eventEmitter.emit(INTERNAL_ERROR_EVENT, {\n type: ERROR.RANGE_NODE_INVALID,\n });\n }\n\n this.start = formatDomNode(start);\n this.end = formatDomNode(end);\n this.text = text;\n this.frozen = frozen;\n this.id = id;\n }\n\n static fromSelection(idHook: Hook<string>) {\n const range = getDomRange();\n\n if (!range) {\n return null;\n }\n\n const start: DomNode = {\n $node: range.startContainer,\n offset: range.startOffset,\n };\n const end: DomNode = {\n $node: range.endContainer,\n offset: range.endOffset,\n };\n\n // Use Selection.toString() for proper newline handling between block elements\n // Range.toString() includes HTML source whitespace, Selection.toString() gives clean output\n const selection = window.getSelection();\n const text = selection?.toString() || range.toString();\n let id = idHook.call(start, end, text);\n\n id = typeof id !== 'undefined' && id !== null ? id : uuid();\n\n return new HighlightRange(start, end, text, id);\n }\n\n // serialize the HRange instance\n // so that you can save the returned object (e.g. use JSON.stringify on it and send to backend)\n serialize($root: Document | HTMLElement, hooks: HookMap): HighlightSource {\n const startMeta = getDomMeta(this.start.$node as Text, this.start.offset, $root);\n const endMeta = getDomMeta(this.end.$node as Text, this.end.offset, $root);\n\n let extra;\n\n if (!hooks.Serialize.RecordInfo.isEmpty()) {\n extra = hooks.Serialize.RecordInfo.call(this.start, this.end, $root);\n }\n\n this.frozen = true;\n\n return new HighlightSource(startMeta, endMeta, this.text, this.id, extra);\n }\n}\n\nexport default HighlightRange;\n","/**\n * Something about the Selection/Range API in browsers.\n * If you want to use Highlighter in some old browsers, you may use a polyfill.\n * https://caniuse.com/#search=selection\n */\n\nexport const getDomRange = (): Range => {\n const selection = window.getSelection();\n\n if (selection.isCollapsed) {\n // eslint-disable-next-line no-console\n console.debug('no text selected');\n\n return null;\n }\n\n return selection.getRangeAt(0);\n};\n\nexport const removeSelection = (): void => {\n window.getSelection().removeAllRanges();\n};\n\n/**\n * Get text from a Range with proper newline handling for block elements.\n * Uses innerText on a cloned fragment to get clean output matching Selection.toString().\n * Range.toString() includes HTML source whitespace, this method gives user-expected output.\n * Falls back to range.toString() in environments where innerText isn't available (e.g. jsdom).\n */\nexport const getTextFromRange = (range: Range): string => {\n // Try innerText approach for proper newline handling in real browsers\n try {\n const fragment = range.cloneContents();\n const temp = document.createElement('div');\n\n // Position off-screen but keep visible - innerText returns empty for hidden elements!\n temp.style.cssText = 'position:absolute;left:-9999px;top:-9999px;';\n document.body.appendChild(temp);\n temp.appendChild(fragment);\n\n const text = temp.innerText;\n\n temp.remove();\n\n // innerText may be undefined in jsdom, or empty if something went wrong\n if (text) {\n return text;\n }\n } catch (e: unknown) {\n // Fall through to fallback\n }\n\n // Fallback to range.toString() (loses proper newline handling but works everywhere)\n return range.toString();\n};\n","/**\n * generate UUID\n */\n\n/* eslint-disable @typescript-eslint/restrict-plus-operands */\nexport default function createUUID(a?): string {\n return a\n ? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16)\n : (([1e7] as unknown as string) + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, createUUID);\n}\n","import type { DomNode, DomMeta, HookMap, HighlighterOptions } from '@src/types';\nimport EventEmitter from '@src/util/event.emitter';\nimport HighlightRange from '@src/model/range';\nimport { getTextFromRange } from '@src/model/range/selection';\nimport HighlightSource from '@src/model/source';\nimport uuid from '@src/util/uuid';\nimport Hook from '@src/util/hook';\nimport getInteraction from '@src/util/interaction';\nimport Cache from '@src/data/cache';\nimport Painter from '@src/painter';\nimport { eventEmitter, getDefaultOptions, INTERNAL_ERROR_EVENT } from '@src/util/const';\nimport { ERROR, EventType, CreateFrom } from '@src/types';\nimport {\n addClass,\n removeClass,\n isHighlightWrapNode,\n getHighlightById,\n getExtraHighlightId,\n getHighlightsByRoot,\n getHighlightId,\n addEventListener,\n removeEventListener,\n} from '@src/util/dom';\n\ninterface EventHandlerMap {\n [key: string]: (...args: any[]) => void;\n [EventType.CLICK]: (data: { id: string }, h: Highlighter, e: MouseEvent | TouchEvent) => void;\n [EventType.HOVER]: (data: { id: string }, h: Highlighter, e: MouseEvent | TouchEvent) => void;\n [EventType.HOVER_OUT]: (data: { id: string }, h: Highlighter, e: MouseEvent | TouchEvent) => void;\n [EventType.CREATE]: (data: { sources: HighlightSource[]; type: CreateFrom }, h: Highlighter) => void;\n [EventType.REMOVE]: (data: { ids: string[] }, h: Highlighter) => void;\n}\n\nexport default class Highlighter extends EventEmitter<EventHandlerMap> {\n static event = EventType;\n\n static isHighlightWrapNode = isHighlightWrapNode;\n\n hooks: HookMap;\n\n painter: Painter;\n\n cache: Cache;\n\n private _hoverId: string;\n\n private options: HighlighterOptions;\n\n private readonly event = getInteraction();\n\n constructor(options?: HighlighterOptions) {\n super();\n this.options = getDefaultOptions();\n // initialize hooks\n this.hooks = this._getHooks();\n this.setOption(options);\n // initialize cache\n this.cache = new Cache();\n\n const $root = this.options.$root;\n\n // initialize event listener\n addEventListener($root, this.event.PointerOver, this._handleHighlightHover);\n // initialize event listener\n addEventListener($root, this.event.PointerTap, this._handleHighlightClick);\n eventEmitter.on(INTERNAL_ERROR_EVENT, this._handleError);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n static isHighlightSource = (d: any) => !!d.__isHighlightSource;\n\n run = () => addEventListener(this.options.$root, this.event.PointerEnd, this._handleSelection);\n\n stop = () => {\n removeEventListener(this.options.$root, this.event.PointerEnd, this._handleSelection);\n };\n\n addClass = (className: string, id?: string) => {\n this.getDoms(id).forEach($n => {\n addClass($n, className);\n });\n };\n\n removeClass = (className: string, id?: string) => {\n this.getDoms(id).forEach($n => {\n removeClass($n, className);\n });\n };\n\n getIdByDom = ($node: HTMLElement): string => getHighlightId($node, this.options.$root);\n\n getExtraIdByDom = ($node: HTMLElement): string[] => getExtraHighlightId($node, this.options.$root);\n\n getDoms = (id?: string): HTMLElement[] =>\n id\n ? getHighlightById(this.options.$root, id, this.options.wrapTag)\n : getHighlightsByRoot(this.options.$root, this.options.wrapTag);\n\n dispose = () => {\n const $root = this.options.$root;\n\n removeEventListener($root, this.event.PointerOver, this._handleHighlightHover);\n removeEventListener($root, this.event.PointerEnd, this._handleSelection);\n removeEventListener($root, this.event.PointerTap, this._handleHighlightClick);\n this.removeAll();\n };\n\n setOption = (options?: HighlighterOptions) => {\n this.options = {\n ...this.options,\n ...options,\n };\n this.painter = new Painter(\n {\n $root: this.options.$root,\n wrapTag: this.options.wrapTag,\n className: this.options.style.className,\n exceptSelectors: this.options.exceptSelectors,\n },\n this.hooks,\n );\n };\n\n fromRange = (range: Range): HighlightSource => {\n const start: DomNode = {\n $node: range.startContainer,\n offset: range.startOffset,\n };\n const end: DomNode = {\n $node: range.endContainer,\n offset: range.endOffset,\n };\n\n // Use getTextFromRange for proper newline handling between block elements\n const text = getTextFromRange(range);\n let id = this.hooks.Render.UUID.call(start, end, text);\n\n id = typeof id !== 'undefined' && id !== null ? id : uuid();\n\n const hRange = new HighlightRange(start, end, text, id);\n\n if (!hRange) {\n eventEmitter.emit(INTERNAL_ERROR_EVENT, {\n type: ERROR.RANGE_INVALID,\n });\n\n return null;\n }\n\n return this._highlightFromHRange(hRange);\n };\n\n fromStore = (start: DomMeta, end: DomMeta, text: string, id: string, extra?: unknown): HighlightSource => {\n const hs = new HighlightSource(start, end, text, id, extra);\n\n try {\n this._highlightFromHSource(hs);\n\n return hs;\n } catch (err: unknown) {\n eventEmitter.emit(INTERNAL_ERROR_EVENT, {\n type: ERROR.HIGHLIGHT_SOURCE_RECREATE,\n error: err,\n detail: hs,\n });\n\n return null;\n }\n };\n\n remove(id: string) {\n if (!id) {\n return;\n }\n\n const doseExist = this.painter.removeHighlight(id);\n\n this.cache.remove(id);\n\n // only emit REMOVE event when highlight exist\n if (doseExist) {\n this.emit(EventType.REMOVE, { ids: [id] }, this);\n }\n }\n\n removeAll() {\n this.painter.removeAllHighlight();\n\n const ids = this.cache.removeAll();\n\n this.emit(EventType.REMOVE, { ids }, this);\n }\n\n private readonly _getHooks = (): HookMap => ({\n Render: {\n UUID: new Hook('Render.UUID'),\n SelectedNodes: new Hook('Render.SelectedNodes'),\n WrapNode: new Hook('Render.WrapNode'),\n },\n Serialize: {\n Restore: new Hook('Serialize.Restore'),\n RecordInfo: new Hook('Serialize.RecordInfo'),\n },\n Remove: {\n UpdateNodes: new Hook('Remove.UpdateNodes'),\n },\n });\n\n private readonly _highlightFromHRange = (range: HighlightRange): HighlightSource => {\n const source: HighlightSource = range.serialize(this.options.$root, this.hooks);\n const $wraps = this.painter.highlightRange(range);\n\n if ($wraps.length === 0) {\n eventEmitter.emit(INTERNAL_ERROR_EVENT, {\n type: ERROR.DOM_SELECTION_EMPTY,\n });\n\n return null;\n }\n\n this.cache.save(source);\n this.emit(EventType.CREATE, { sources: [source], type: CreateFrom.INPUT }, this);\n\n return source;\n };\n\n private _highlightFromHSource(sources: HighlightSource | HighlightSource[] = []) {\n const renderedSources: HighlightSource[] = this.painter.highlightSource(sources);\n\n this.emit(EventType.CREATE, { sources: renderedSources, type: CreateFrom.STORE }, this);\n this.cache.save(sources);\n }\n\n private readonly _handleSelection = () => {\n const range = HighlightRange.fromSelection(this.hooks.Render.UUID);\n\n if (range) {\n this._highlightFromHRange(range);\n HighlightRange.removeDomRange();\n }\n };\n\n private readonly _handleHighlightHover = (e: MouseEvent | TouchEvent) => {\n const $target = e.target as HTMLElement;\n\n if (!isHighlightWrapNode($target)) {\n this._hoverId && this.emit(EventType.HOVER_OUT, { id: this._hoverId }, this, e);\n this._hoverId = null;\n\n return;\n }\n\n const id = getHighlightId($target, this.options.$root);\n\n // prevent trigger in the same highlight range\n if (this._hoverId === id) {\n return;\n }\n\n // hover another highlight range, need to trigger previous highlight hover out event\n if (this._hoverId) {\n this.emit(EventType.HOVER_OUT, { id: this._hoverId }, this, e);\n }\n\n this._hoverId = id;\n this.emit(EventType.HOVER, { id: this._hoverId }, this, e);\n };\n\n private readonly _handleError = (type: { type: ERROR; detail?: HighlightSource; error?: any }) => {\n if (this.options.verbose) {\n // eslint-disable-next-line no-console\n console.warn(type);\n }\n };\n\n private readonly _handleHighlightClick = (e: MouseEvent | TouchEvent) => {\n const $target = e.target as HTMLElement;\n\n if (isHighlightWrapNode($target)) {\n const id = getHighlightId($target, this.options.$root);\n\n this.emit(EventType.CLICK, { id }, this, e);\n }\n };\n}\n","import type { DomNode } from '@src//types';\nimport type HighlightSource from '@src/model/source/index';\nimport { ROOT_IDX } from '@src/util/const';\n\n/**\n * Because of supporting highlighting a same area (range overlapping),\n * Highlighter will calculate which text-node and how much offset it actually be,\n * based on the origin website dom node and the text offset.\n *\n * @param {Node} $parent element node in the origin website dom tree\n * @param {number} offset text offset in the origin website dom tree\n * @return {DomNode} DOM a dom info object\n */\nexport const getTextChildByOffset = ($parent: Node, offset: number): DomNode => {\n const nodeStack: Node[] = [$parent];\n\n let $curNode: Node = null;\n let curOffset = 0;\n let startOffset = 0;\n\n while (($curNode = nodeStack.pop())) {\n const children = $curNode.childNodes;\n\n for (let i = children.length - 1; i >= 0; i--) {\n nodeStack.push(children[i]);\n }\n\n if ($curNode.nodeType === 3) {\n startOffset = offset - curOffset;\n curOffset += $curNode.textContent.length;\n\n if (curOffset >= offset) {\n break;\n }\n }\n }\n\n if (!$curNode) {\n $curNode = $parent;\n }\n\n return {\n $node: $curNode,\n offset: startOffset,\n };\n};\n\n/**\n * get start and end parent element from meta info\n *\n * @param {HighlightSource} hs\n * @param {HTMLElement | Document} $root root element, default document\n * @return {Object}\n */\nexport const queryElementNode = (hs: HighlightSource, $root: Document | HTMLElement): { start: Node; end: Node } => {\n const start =\n hs.startMeta.parentIndex === ROOT_IDX\n ? $root\n : $root.getElementsByTagName(hs.startMeta.parentTagName)[hs.startMeta.parentIndex];\n const end =\n hs.endMeta.parentIndex === ROOT_IDX\n ? $root\n : $root.getElementsByTagName(hs.endMeta.parentTagName)[hs.endMeta.parentIndex];\n\n return { start, end };\n};\n","/**\n * convert dash-joined string to camel case\n */\n\nexport default (a: string): string =>\n a.split('-').reduce((str, s, idx) => str + (idx === 0 ? s : s[0].toUpperCase() + s.slice(1)), '');\n","/**\n * some dom operations about HighlightRange\n */\n\nimport type { DomMeta, DomNode } from '@src/types';\nimport { CAMEL_DATASET_IDENTIFIER, ROOT_IDX, UNKNOWN_IDX } from '@src/util/const';\n\nconst countGlobalNodeIndex = ($node: Node, $root: Document | HTMLElement): number => {\n const tagName = ($node as HTMLElement).tagName;\n const $list = $root.getElementsByTagName(tagName);\n\n for (let i = 0; i < $list.length; i++) {\n if ($node === $list[i]) {\n return i;\n }\n }\n\n return UNKNOWN_IDX;\n};\n\n/**\n * text total length in all predecessors (text nodes) in the root node\n * (without offset in current node)\n */\nconst getTextPreOffset = ($root: Node, $text: Node): number => {\n const nodeStack: Node[] = [$root];\n\n let $curNode: Node = null;\n let offset = 0;\n\n while (($curNode = nodeStack.pop())) {\n const children = $curNode.childNodes;\n\n for (let i = children.length - 1; i >= 0; i--) {\n nodeStack.push(children[i]);\n }\n\n if ($curNode.nodeType === 3 && $curNode !== $text) {\n offset += $curNode.textContent.length;\n } else if ($curNode.nodeType === 3) {\n break;\n }\n }\n\n return offset;\n};\n\n/**\n * find the original dom parent node (none highlight dom)\n */\nconst getOriginParent = ($node: HTMLElement | Text): HTMLElement => {\n if ($node instanceof HTMLElement && (!$node.dataset || !$node.dataset[CAMEL_DATASET_IDENTIFIER])) {\n return $node;\n }\n\n let $originParent = $node.parentNode as HTMLElement;\n\n while ($originParent?.dataset[CAMEL_DATASET_IDENTIFIER]) {\n $originParent = $originParent.parentNode as HTMLElement;\n }\n\n return $originParent;\n};\n\nexport const getDomMeta = ($node: HTMLElement | Text, offset: number, $root: Document | HTMLElement): DomMeta => {\n const $originParent = getOriginParent($node);\n const index = $originParent === $root ? ROOT_IDX : countGlobalNodeIndex($originParent, $root);\n const preNodeOffset = getTextPreOffset($originParent, $node);\n const tagName = $originParent.tagName;\n\n return {\n parentTagName: tagName,\n parentIndex: index,\n textOffset: preNodeOffset + offset,\n };\n};\n\nexport const formatDomNode = (n: DomNode): DomNode => {\n if (\n // Text\n n.$node.nodeType === 3 ||\n // CDATASection\n n.$node.nodeType === 4 ||\n // Comment\n n.$node.nodeType === 8\n ) {\n return n;\n }\n\n return {\n $node: n.$node.childNodes[n.offset],\n offset: 0,\n };\n};\n","/**\n * simple hook\n * webpack-plugin-liked api\n */\n\ntype HookCallback<T> = (...args: unknown[]) => T;\n\nclass Hook<T = unknown> {\n name = '';\n\n private readonly ops: HookCallback<T>[] = [];\n\n constructor(name?) {\n this.name = name;\n }\n\n tap(cb: HookCallback<T>) {\n if (this.ops.indexOf(cb) === -1) {\n this.ops.push(cb);\n }\n\n return () => {\n this.remove(cb);\n };\n }\n\n remove(cb: HookCallback<T>) {\n const idx = this.ops.indexOf(cb);\n\n if (idx < 0) {\n return;\n }\n\n this.ops.splice(idx, 1);\n }\n\n isEmpty() {\n return this.ops.length === 0;\n }\n\n call(...args: unknown[]) {\n let ret: T;\n\n this.ops.forEach(op => {\n ret = op(...args);\n });\n\n return ret;\n }\n}\n\nexport default Hook;\n","/**\n * adapter for mobile and desktop events\n */\n\nimport type { IInteraction } from '@src/types';\nimport { UserInputEvent } from '@src/types';\nimport detectMobile from '@src/util/is.mobile';\n\nexport default (): IInteraction => {\n const isMobile = detectMobile(window.navigator.userAgent);\n\n const interaction: IInteraction = {\n PointerEnd: isMobile ? UserInputEvent.touchend : UserInputEvent.mouseup,\n PointerTap: isMobile ? UserInputEvent.touchstart : UserInputEvent.click,\n // hover and click will be the same event in mobile\n PointerOver: isMobile ? UserInputEvent.touchstart : UserInputEvent.mouseover,\n };\n\n return interaction;\n};\n","/**\n * is mobile device?\n */\n\nconst regMobile = /Android|iPhone|BlackBerry|BB10|Opera Mini|Phone|Mobile|Silk|Windows Phone|Mobile(?:.+)Firefox\\b/i;\n\nexport default (userAgent: string) => regMobile.test(userAgent);\n","import EventEmitter from '@src/util/event.emitter';\nimport type HighlightSource from '@src/model/source';\nimport { ERROR } from '@src/types';\n\nclass Cache extends EventEmitter {\n private _data: Map<string, HighlightSource> = new Map();\n\n get data() {\n return this.getAll();\n }\n\n set data(map) {\n throw ERROR.CACHE_SET_ERROR;\n }\n\n save(source: HighlightSource | HighlightSource[]): void {\n if (!Array.isArray(source)) {\n this._data.set(source.id, source);\n\n return;\n }\n\n source.forEach(s => this._data.set(s.id, s));\n }\n\n get(id: string): HighlightSource {\n return this._data.get(id);\n }\n\n remove(id: string): void {\n this._data.delete(id);\n }\n\n getAll(): HighlightSource[] {\n const list: HighlightSource[] = [];\n\n for (const pair of this._data) {\n list.push(pair[1]);\n }\n\n return list;\n }\n\n removeAll(): string[] {\n const ids: string[] = [];\n\n for (const pair of this._data) {\n ids.push(pair[0]);\n }\n\n this._data = new Map();\n\n return ids;\n }\n}\n\nexport default Cache;\n","/**\n * Painter object is designed for some painting work about higlighting,\n * including rendering, cleaning...\n * No need to instantiate repeatly. A Highlighter instance will bind a Painter instance.\n */\n\nimport type HighlightRange from '@src/model/range';\nimport type { PainterOptions, HookMap } from '@src/types';\nimport HighlightSource from '@src/model/source';\nimport { wrapHighlight, getSelectedNodes, normalizeSiblingText } from '@src/painter/dom';\nimport { getHighlightsByRoot, forEach, addClass, removeAllClass } from '@src/util/dom';\nimport { ERROR } from '@src/types';\nimport { initDefaultStylesheet } from '@src/painter/style';\nimport {\n ID_DIVISION,\n eventEmitter,\n DATASET_IDENTIFIER,\n INTERNAL_ERROR_EVENT,\n CAMEL_DATASET_IDENTIFIER,\n CAMEL_DATASET_IDENTIFIER_EXTRA,\n} from '@src/util/const';\n\nexport default class Painter {\n options: PainterOptions;\n\n $style: HTMLStyleElement;\n\n styleId: string;\n\n hooks: HookMap;\n\n constructor(options: PainterOptions, hooks: HookMap) {\n this.options = {\n $root: options.$root,\n wrapTag: options.wrapTag,\n exceptSelectors: options.exceptSelectors,\n className: options.className,\n };\n this.hooks = hooks;\n\n initDefaultStylesheet();\n }\n\n /* =========================== render =========================== */\n highlightRange(range: HighlightRange): HTMLElement[] {\n if (!range.frozen) {\n throw ERROR.HIGHLIGHT_RANGE_FROZEN;\n }\n\n const { $root, className, exceptSelectors } = this.options;\n const hooks = this.hooks;\n\n let $selectedNodes = getSelectedNodes($root, range.start, range.end, exceptSelectors);\n\n if (!hooks.Render.SelectedNodes.isEmpty()) {\n $selectedNodes = hooks.Render.SelectedNodes.call(range.id, $selectedNodes) || [];\n }\n\n return $selectedNodes.map(n => {\n let $node = wrapHighlight(n, range, className, this.options.wrapTag);\n\n if (!hooks.Render.WrapNode.isEmpty()) {\n $node = hooks.Render.WrapNode.call(range.id, $node);\n }\n\n return $node;\n });\n }\n\n highlightSource(sources: HighlightSource | HighlightSource[]): HighlightSource[] {\n const list = Array.isArray(sources) ? sources : [sources];\n\n const renderedSources: HighlightSource[] = [];\n\n list.forEach(s => {\n if (!(s instanceof HighlightSource)) {\n eventEmitter.emit(INTERNAL_ERROR_EVENT, {\n type: ERROR.SOURCE_TYPE_ERROR,\n });\n\n return;\n }\n\n const range = s.deSerialize(this.options.$root, this.hooks);\n const $nodes = this.highlightRange(range);\n\n if ($nodes.length > 0) {\n renderedSources.push(s);\n } else {\n eventEmitter.emit(INTERNAL_ERROR_EVENT, {\n type: ERROR.HIGHLIGHT_SOURCE_NONE_RENDER,\n detail: s,\n });\n }\n });\n\n return renderedSources;\n }\n /* ============================================================== */\n\n /* =========================== clean =========================== */\n // id: target id - highlight with this id should be clean\n // if there is no highlight for this id, it will return false, vice versa\n removeHighlight(id: string): boolean {\n // whether extra ids contains the target id\n const reg = new RegExp(`(${id}\\\\${ID_DIVISION}|\\\\${ID_DIVISION}?${id}$)`);\n\n const hooks = this.hooks;\n const wrapTag = this.options.wrapTag;\n const $spans = document.querySelectorAll<HTMLElement>(`${wrapTag}[data-${DATASET_IDENTIFIER}]`);\n\n // nodes to remove\n const $toRemove: HTMLElement[] = [];\n // nodes to update main id\n const $idToUpdate: HTMLElement[] = [];\n // nodes to update extra id\n const $extraToUpdate: HTMLElement[] = [];\n\n for (const $s of $spans) {\n const spanId = $s.dataset[CAMEL_DATASET_IDENTIFIER];\n const spanExtraIds = $s.dataset[CAMEL_DATASET_IDENTIFIER_EXTRA];\n\n // main id is the target id and no extra ids --> to remove\n if (spanId === id && !spanExtraIds) {\n $toRemove.push($s);\n }\n // main id is the target id but there is some extra ids -> update main id & extra id\n else if (spanId === id) {\n $idToUpdate.push($s);\n }\n // main id isn't the target id but extra ids contains it -> just remove it from extra id\n else if (spanId !== id && reg.test(spanExtraIds)) {\n $extraToUpdate.push($s);\n }\n }\n\n $toRemove.forEach($s => {\n const $parent = $s.parentNode;\n const $fr = document.createDocumentFragment();\n\n forEach($s.childNodes, ($c: Node) => $fr.appendChild($c.cloneNode(false)));\n\n const $prev = $s.previousSibling;\n const $next = $s.nextSibling;\n\n $parent.replaceChild($fr, $s);\n // there are bugs in IE11, so use a more reliable function\n normalizeSiblingText($prev, true);\n normalizeSiblingText($next, false);\n hooks.Remove.UpdateNodes.call(id, $s, 'remove');\n });\n\n $idToUpdate.forEach($s => {\n const dataset = $s.dataset;\n const ids = dataset[CAMEL_DATASET_IDENTIFIER_EXTRA].split(ID_DIVISION);\n const newId = ids.shift();\n\n // find overlapped wrapper associated with \"extra id\"\n const $overlapSpan = document.querySelector<HTMLElement>(\n `${wrapTag}[data-${DATASET_IDENTIFIER}=\"${newId}\"]`,\n );\n\n if ($overlapSpan) {\n // empty the current class list\n removeAllClass($s);\n // retain the class list of the overlapped wrapper which associated with \"extra id\"\n addClass($s, [...$overlapSpan.classList]);\n }\n\n dataset[CAMEL_DATASET_IDENTIFIER] = newId;\n dataset[CAMEL_DATASET_IDENTIFIER_EXTRA] = ids.join(ID_DIVISION);\n\n hooks.Remove.UpdateNodes.call(id, $s, 'id-update');\n });\n\n $extraToUpdate.forEach($s => {\n const extraIds = $s.dataset[CAMEL_DATASET_IDENTIFIER_EXTRA];\n\n $s.dataset[CAMEL_DATASET_IDENTIFIER_EXTRA] = extraIds.replace(reg, '');\n hooks.Remove.UpdateNodes.call(id, $s, 'extra-update');\n });\n\n return $toRemove.length + $idToUpdate.length + $extraToUpdate.length !== 0;\n }\n\n removeAllHighlight() {\n const { wrapTag, $root } = this.options;\n const $spans = getHighlightsByRoot($root, wrapTag);\n\n $spans.forEach($s => {\n const $parent = $s.parentNode;\n const $fr = document.createDocumentFragment();\n\n forEach($s.childNodes, ($c: Node) => $fr.appendChild($c.cloneNode(false)));\n $parent.replaceChild($fr, $s);\n });\n }\n /* ============================================================== */\n}\n","import type HighlightRange from '@src/model/range';\nimport type { SelectedNode, DomNode } from '@src/types';\nimport { SplitType, SelectedNodeType } from '@src/types';\nimport { hasClass, addClass as addElementClass, isHighlightWrapNode, removeAllClass } from '@src/util/dom';\nimport {\n ID_DIVISION,\n getDefaultOptions,\n CAMEL_DATASET_IDENTIFIER,\n CAMEL_DATASET_IDENTIFIER_EXTRA,\n DATASET_IDENTIFIER,\n DATASET_SPLIT_TYPE,\n DATASET_IDENTIFIER_EXTRA,\n} from '../util/const';\nimport { unique } from '../util/tool';\n\n/**\n * 支持的选择器类型\n * - class: .title, .main-nav\n * - id: #nav, #js-toggle-btn\n * - tag: div, p, span\n */\nconst isMatchSelector = ($node: HTMLElement, selector: string): boolean => {\n if (!$node) {\n return false;\n }\n\n if (/^\\./.test(selector)) {\n const className = selector.replace(/^\\./, '');\n\n return $node && hasClass($node, className);\n } else if (/^#/.test(selector)) {\n const id = selector.replace(/^#/, '');\n\n return $node && $node.id === id;\n }\n\n const tagName = selector.toUpperCase();\n\n return $node && $node.tagName === tagName;\n};\n\n/**\n * If start node and end node is the same, don't need to tranvers the dom tree.\n */\nconst getNodesIfSameStartEnd = (\n $startNode: Text,\n startOffset: number,\n endOffset: number,\n exceptSelectors?: string[],\n) => {\n let $element = $startNode as Node;\n\n const isExcepted = ($e: HTMLElement) => exceptSelectors?.some(s => isMatchSelector($e, s));\n\n while ($element) {\n if ($element.nodeType === 1 && isExcepted($element as HTMLElement)) {\n return [];\n }\n\n $element = $element.parentNode;\n }\n\n $startNode.splitText(startOffset);\n\n const passedNode = $startNode.nextSibling as Text;\n\n passedNode.splitText(endOffset - startOffset);\n\n return [\n {\n $node: passedNode,\n type: SelectedNodeType.text,\n splitType: SplitType.both,\n },\n ];\n};\n\n/**\n * get all the dom nodes between the start and end node\n */\nexport const getSelectedNodes = (\n $root: Document | HTMLElement,\n start: DomNode,\n end: DomNode,\n exceptSelectors: string[],\n): SelectedNode[] => {\n const $startNode = start.$node;\n const $endNode = end.$node;\n const startOffset = start.offset;\n const endOffset = end.offset;\n\n // split current node when the start-node and end-node is the same\n if ($startNode === $endNode && $startNode instanceof Text) {\n return getNodesIfSameStartEnd($startNode, startOffset, endOffset, exceptSelectors);\n }\n\n const nodeStack: (ChildNode | Document | HTMLElement | Text)[] = [$root];\n const selectedNodes: SelectedNode[] = [];\n\n const isExcepted = ($e: HTMLElement) => exceptSelectors?.some(s => isMatchSelector($e, s));\n\n let withinSelectedRange = false;\n let curNode: Node = null;\n\n while ((curNode = nodeStack.pop())) {\n // do not traverse the excepted node\n if (curNode.nodeType === 1 && isExcepted(curNode as HTMLElement)) {\n continue;\n }\n\n const children = curNode.childNodes;\n\n for (let i = children.length - 1; i >= 0; i--) {\n nodeStack.push(children[i]);\n }\n\n // only collect text nodes\n if (curNode === $startNode) {\n if (curNode.nodeType === 3) {\n (curNode as Text).splitText(startOffset);\n\n const node = curNode.nextSibling as Text;\n\n selectedNodes.push({\n $node: node,\n type: SelectedNodeType.text,\n splitType: SplitType.head,\n });\n }\n\n // meet the start-node (begin to traverse)\n withinSelectedRange = true;\n } else if (curNode === $endNode) {\n if (curNode.nodeType === 3) {\n const node = curNode as Text;\n\n node.splitText(endOffset);\n selectedNodes.push({\n $node: node,\n type: SelectedNodeType.text,\n splitType: SplitType.tail,\n });\n }\n\n // meet the end-node\n break;\n }\n // handle text nodes between the range\n else if (withinSelectedRange && curNode.nodeType === 3) {\n selectedNodes.push({\n $node: curNode as Text,\n type: SelectedNodeType.text,\n splitType: SplitType.none,\n });\n }\n }\n\n return selectedNodes;\n};\n\nconst addClass = ($el: HTMLElement, className?: string[] | string): HTMLElement => {\n let classNames = Array.isArray(className) ? className : [className];\n\n classNames = classNames.length === 0 ? [getDefaultOptions().style.className] : classNames;\n classNames.forEach(c => {\n addElementClass($el, c);\n });\n\n return $el;\n};\n\nconst isNodeEmpty = ($n: Node): boolean => !$n || !$n.textContent;\n\n/**\n * Wrap a common wrapper.\n */\nconst wrapNewNode = (\n selected: SelectedNode,\n range: HighlightRange,\n className: string[] | string,\n wrapTag: string,\n): HTMLElement => {\n const $wrap = document.createElement(wrapTag);\n\n addClass($wrap, className);\n\n $wrap.appendChild(selected.$node.cloneNode(false));\n selected.$node.parentNode.replaceChild($wrap, selected.$node);\n\n $wrap.setAttribute(`data-${DATASET_IDENTIFIER}`, range.id);\n $wrap.setAttribute(`data-${DATASET_SPLIT_TYPE}`, selected.splitType);\n $wrap.setAttribute(`data-${DATASET_IDENTIFIER_EXTRA}`, '');\n\n return $wrap;\n};\n\n/**\n * Split and wrapper each one.\n */\nconst wrapPartialNode = (\n selected: SelectedNode,\n range: HighlightRange,\n className: string[] | string,\n wrapTag: string,\n): HTMLElement => {\n const $wrap: HTMLElement = document.createElement(wrapTag);\n\n const $parent = selected.$node.parentNode as HTMLElement;\n const $prev = selected.$node.previousSibling;\n const $next = selected.$node.nextSibling;\n const $fr = document.createDocumentFragment();\n const parentId = $parent.dataset[CAMEL_DATASET_IDENTIFIER];\n const parentExtraId = $parent.dataset[CAMEL_DATASET_IDENTIFIER_EXTRA];\n const extraInfo = parentExtraId ? parentId + ID_DIVISION + parentExtraId : parentId;\n\n $wrap.setAttribute(`data-${DATASET_IDENTIFIER}`, range.id);\n $wrap.setAttribute(`data-${DATASET_IDENTIFIER_EXTRA}`, extraInfo);\n $wrap.appendChild(selected.$node.cloneNode(false));\n\n let headSplit = false;\n let tailSplit = false;\n let splitType: SplitType;\n\n if ($prev) {\n const $span = $parent.cloneNode(false);\n\n $span.textContent = $prev.textContent;\n $fr.appendChild($span);\n headSplit = true;\n }\n\n const classNameList: string[] = [];\n\n if (Array.isArray(className)) {\n classNameList.push(...className);\n } else {\n classNameList.push(className);\n }\n\n addClass($wrap, unique(classNameList));\n $fr.appendChild($wrap);\n\n if ($next) {\n const $span = $parent.cloneNode(false);\n\n $span.textContent = $next.textContent;\n $fr.appendChild($span);\n tailSplit = true;\n }\n\n if (headSplit && tailSplit) {\n splitType = SplitType.both;\n } else if (headSplit) {\n splitType = SplitType.head;\n } else if (tailSplit) {\n splitType = SplitType.tail;\n } else {\n splitType = SplitType.none;\n }\n\n $wrap.setAttribute(`data-${DATASET_SPLIT_TYPE}`, splitType);\n $parent.parentNode.replaceChild($fr, $parent);\n\n return $wrap;\n};\n\n/**\n * Just update id info (no wrapper updated).\n */\nconst wrapOverlapNode = (selected: SelectedNode, range: HighlightRange, className: string[] | string): HTMLElement => {\n const $parent = selected.$node.parentNode as HTMLElement;\n const $wrap: HTMLElement = $parent;\n\n removeAllClass($wrap);\n addClass($wrap, className);\n\n const dataset = $parent.dataset;\n const formerId = dataset[CAMEL_DATASET_IDENTIFIER];\n\n dataset[CAMEL_DATASET_IDENTIFIER] = range.id;\n dataset[CAMEL_DATASET_IDENTIFIER_EXTRA] = dataset[CAMEL_DATASET_IDENTIFIER_EXTRA]\n ? formerId + ID_DIVISION + dataset[CAMEL_DATASET_IDENTIFIER_EXTRA]\n : formerId;\n\n return $wrap;\n};\n\n/**\n * wrap a dom node with highlight wrapper\n *\n * Because of supporting the highlight-overlapping,\n * Highlighter can't just wrap all nodes in a simple way.\n * There are three types:\n * - wrapping a whole new node (without any wrapper)\n * - wrapping part of the node\n * - wrapping the whole wrapped node\n */\nexport const wrapHighlight = (\n selected: SelectedNode,\n range: HighlightRange,\n className: string[] | string,\n wrapTag: string,\n): HTMLElement => {\n const $parent = selected.$node.parentNode as HTMLElement;\n const $prev = selected.$node.previousSibling;\n const $next = selected.$node.nextSibling;\n\n let $wrap: HTMLElement;\n\n // text node, not in a highlight wrapper -> should be wrapped in a highlight wrapper\n if (!isHighlightWrapNode($parent)) {\n $wrap = wrapNewNode(selected, range, className, wrapTag);\n }\n // text node, in a highlight wrap -> should split the existing highlight wrapper\n else if (isHighlightWrapNode($parent) && (!isNodeEmpty($prev) || !isNodeEmpty($next))) {\n $wrap = wrapPartialNode(selected, range, className, wrapTag);\n }\n // completely overlap (with a highlight wrap) -> only add extra id info\n else {\n $wrap = wrapOverlapNode(selected, range, className);\n }\n\n return $wrap;\n};\n\n/**\n * merge the adjacent text nodes\n * .normalize() API has some bugs in IE11\n */\nexport const normalizeSiblingText = ($s: Node, isNext = true) => {\n if (!$s || $s.nodeType !== 3) {\n return;\n }\n\n const $sibling = isNext ? $s.nextSibling : $s.previousSibling;\n\n if ($sibling.nodeType !== 3) {\n return;\n }\n\n const text = $sibling.nodeValue;\n\n $s.nodeValue = isNext ? $s.nodeValue + text : text + $s.nodeValue;\n $sibling.parentNode.removeChild($sibling);\n};\n","/**\n * support IE 10\n */\nexport const unique = <T>(arr: T[]): T[] => {\n const res: T[] = [];\n\n for (const el of arr) {\n if (res.indexOf(el) === -1) {\n res.push(el);\n }\n }\n\n return res;\n};\n","/**\n * inject styles\n */\nimport { STYLESHEET_ID, getStylesheet } from '@src/util/const';\n\nexport const initDefaultStylesheet = () => {\n const styleId = STYLESHEET_ID;\n\n let $style: HTMLStyleElement = document.getElementById(styleId) as HTMLStyleElement;\n\n if (!$style) {\n const $cssNode = document.createTextNode(getStylesheet());\n\n $style = document.createElement('style');\n $style.id = styleId;\n $style.appendChild($cssNode);\n document.head.appendChild($style);\n }\n\n return $style;\n};\n"],"sourceRoot":""}
|
package/docs/ADVANCE.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Internal workflows and hooks
|
|
2
|
+
|
|
3
|
+
English | [简体中文](./ADVANCE.zh_CN.md)
|
|
4
|
+
|
|
5
|
+
This part shows
|
|
6
|
+
|
|
7
|
+
- how web-highlighter creates a new highlighted area and how it removes thems
|
|
8
|
+
- when each hook is called and its usage
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
### Creating highlighted areas
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
### Removing highlighted areas
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
## Hooks - Use sample
|
|
21
|
+
|
|
22
|
+
```JavaScript
|
|
23
|
+
// UUID hook
|
|
24
|
+
const highlighter = new Highlighter();
|
|
25
|
+
highlighter.hooks.Render.UUID.tap(function (start, end, text) {
|
|
26
|
+
// do something to generate your own id
|
|
27
|
+
return id;
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Hooks - List
|
|
32
|
+
|
|
33
|
+
### `Render.UUID`
|
|
34
|
+
|
|
35
|
+
Hook into the process of generating a unique id.
|
|
36
|
+
|
|
37
|
+
**arguments:**
|
|
38
|
+
|
|
39
|
+
- start: DOM info of the start node
|
|
40
|
+
- end: DOM info of the end node
|
|
41
|
+
- text: text content in the highlighted area
|
|
42
|
+
|
|
43
|
+
**return value needed:**
|
|
44
|
+
|
|
45
|
+
- A new unique id.
|
|
46
|
+
|
|
47
|
+
### `Render.SelectedNodes`
|
|
48
|
+
|
|
49
|
+
Process all the text nodes in the highlighted area and return a new list by using this hook.
|
|
50
|
+
|
|
51
|
+
**arguments:**
|
|
52
|
+
|
|
53
|
+
- id: id of the highlighted area
|
|
54
|
+
- selectedNodes: all the text nodes in the highlighted area
|
|
55
|
+
|
|
56
|
+
**return value needed:**
|
|
57
|
+
|
|
58
|
+
- the text nodes need to be wrapped
|
|
59
|
+
|
|
60
|
+
### `Render.WrapNode`
|
|
61
|
+
|
|
62
|
+
Process the wrapping elements.
|
|
63
|
+
|
|
64
|
+
**arguments:**
|
|
65
|
+
|
|
66
|
+
- id: id of the highlighted area
|
|
67
|
+
- node: the wrapping elements
|
|
68
|
+
|
|
69
|
+
**return value needed:**
|
|
70
|
+
|
|
71
|
+
- the wrapping elements
|
|
72
|
+
|
|
73
|
+
### `Serialize.Restore`
|
|
74
|
+
|
|
75
|
+
Customize your own restoring method. When you tap this hook, the `HighlightSource` instance will use the function you pass to calculate the start and end nodes' info.
|
|
76
|
+
|
|
77
|
+
**arguments:**
|
|
78
|
+
|
|
79
|
+
- hs: the current `HighlightSource` instance
|
|
80
|
+
- start: a [DomNode type](https://github.com/alienzhou/web-highlighter/blob/master/src/types/index.ts#L75-L78) object which record the start info
|
|
81
|
+
- end: a [DomNode type](https://github.com/alienzhou/web-highlighter/blob/master/src/types/index.ts#L75-L78) object which record the end info
|
|
82
|
+
|
|
83
|
+
**return value needed:**
|
|
84
|
+
|
|
85
|
+
- an array: the first element is the start info and the second is the end
|
|
86
|
+
|
|
87
|
+
### `Serialize.RecordInfo`
|
|
88
|
+
|
|
89
|
+
Add or modify some extra info when serialize the `HighlightRange` object.
|
|
90
|
+
|
|
91
|
+
**arguments:**
|
|
92
|
+
|
|
93
|
+
- start: meta info of the start node
|
|
94
|
+
- end: meta info of the end node
|
|
95
|
+
- root: the root element
|
|
96
|
+
|
|
97
|
+
**return value needed:**
|
|
98
|
+
|
|
99
|
+
- extra info: it will be added to the `extra` field in the `HighlightSource` object
|
|
100
|
+
|
|
101
|
+
### `Remove.UpdateNodes`
|
|
102
|
+
|
|
103
|
+
Process the affected wrapping elements when remove highlighted areas.
|
|
104
|
+
|
|
105
|
+
**arguments:**
|
|
106
|
+
|
|
107
|
+
- id: id of the highlighted area
|
|
108
|
+
- nodes: the affected wrapping elements
|
|
109
|
+
- type: affected type or state, one of `remove`, `id-update` and `extra-update`
|
|
110
|
+
|
|
111
|
+
**return value needed:**
|
|
112
|
+
|
|
113
|
+
- `void`
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# 内部工作流程与钩子
|
|
2
|
+
|
|
3
|
+
[English](./ADVANCE.md) | 简体中文
|
|
4
|
+
|
|
5
|
+
这一部分将会介绍
|
|
6
|
+
|
|
7
|
+
- web-highlighter 是如何创建与清除高亮选区的
|
|
8
|
+
- 各个钩子的触发时机及其用途
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## 工作流程
|
|
12
|
+
|
|
13
|
+
### 高亮选区创建流程
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
### 高亮选区清除流程
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
## 钩子的使用
|
|
22
|
+
|
|
23
|
+
```JavaScript
|
|
24
|
+
const highlighter = new Highlighter();
|
|
25
|
+
highlighter.hooks.Render.UUID.tap(function (start, end, text) {
|
|
26
|
+
// 生成 id
|
|
27
|
+
return id;
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 钩子列表
|
|
32
|
+
|
|
33
|
+
### `Render.UUID`
|
|
34
|
+
|
|
35
|
+
自定义UUID(选区id)的生成。
|
|
36
|
+
|
|
37
|
+
**参数:**
|
|
38
|
+
|
|
39
|
+
- start: 起始节点的信息
|
|
40
|
+
- end: 终止节点的信息
|
|
41
|
+
- text: 文本内容
|
|
42
|
+
|
|
43
|
+
**所需的返回值:**
|
|
44
|
+
|
|
45
|
+
- 生成的选区 id
|
|
46
|
+
|
|
47
|
+
### `Render.SelectedNodes`
|
|
48
|
+
|
|
49
|
+
操作高亮选区所包含的所有文本节点
|
|
50
|
+
|
|
51
|
+
**参数:**
|
|
52
|
+
|
|
53
|
+
- id: 高亮 id
|
|
54
|
+
- selectedNodes: 当前高亮被选择的所有文本节点
|
|
55
|
+
|
|
56
|
+
**所需的返回值:**
|
|
57
|
+
|
|
58
|
+
- 需要被高亮元素包裹的所有文本节点
|
|
59
|
+
|
|
60
|
+
### `Render.WrapNode`
|
|
61
|
+
|
|
62
|
+
操作高亮包裹后的元素
|
|
63
|
+
|
|
64
|
+
**参数:**
|
|
65
|
+
|
|
66
|
+
- id: 高亮 id
|
|
67
|
+
- node: 高亮包裹的节点
|
|
68
|
+
|
|
69
|
+
**所需的返回值:**
|
|
70
|
+
|
|
71
|
+
- 高亮包裹的节点
|
|
72
|
+
|
|
73
|
+
### `Serialize.Restore`
|
|
74
|
+
|
|
75
|
+
自定义你的还原(反序列化)方法。当你使用这个钩子时,`HighlightSource` 实例会调用你注册的方法来计算高亮选区的首尾节点信息。
|
|
76
|
+
|
|
77
|
+
**参数:**
|
|
78
|
+
|
|
79
|
+
- hs: 当前的 `HighlightSource` 实例
|
|
80
|
+
|
|
81
|
+
**所需的返回值:**
|
|
82
|
+
|
|
83
|
+
- 一个数组对象: 数组的第一个元素是选区开始的节点信息,第二个元素是结束的节点信息
|
|
84
|
+
|
|
85
|
+
### `Serialize.RecordInfo`
|
|
86
|
+
|
|
87
|
+
为选区序列化时的持久化数据生成额外信息
|
|
88
|
+
|
|
89
|
+
**参数:**
|
|
90
|
+
|
|
91
|
+
- start: 起始节点的元数据
|
|
92
|
+
- end: 终止节点的元数据
|
|
93
|
+
- root: 选区根元素
|
|
94
|
+
|
|
95
|
+
**所需的返回值:**
|
|
96
|
+
|
|
97
|
+
- 持久化信息中的额外数据,会被添加到 `HighlightSource` 的 `extra` 字段里
|
|
98
|
+
|
|
99
|
+
### `Remove.UpdateNodes`
|
|
100
|
+
|
|
101
|
+
删除选区时,对受影响的节点进行自定义操作
|
|
102
|
+
|
|
103
|
+
**参数:**
|
|
104
|
+
|
|
105
|
+
- id: 高亮id
|
|
106
|
+
- node: 收到影响的节点
|
|
107
|
+
- type: 更新的类型,包括三种:`remove`、`id-update` 和 `extra-update`
|
|
108
|
+
|
|
109
|
+
**所需的返回值:**
|
|
110
|
+
|
|
111
|
+
- 无需返回值
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/* Picnic CSS v6.5.0 http://picnicss.com/ */
|
|
2
|
+
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:0;padding:0}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{box-sizing:inherit}html,body{font-family:Arial, Helvetica, sans-serif;box-sizing:border-box;height:100%}body{color:#111;font-size:1.1em;line-height:1.5;background:#fff}main{display:block}h1,h2,h3,h4,h5,h6{margin:0;padding:.6em 0}li{margin:0 0 .3em}a{color:#0074d9;text-decoration:none;box-shadow:none;transition:all 0.3s}code{padding:.3em .6em;font-size:.8em;background:#f5f5f5}pre{text-align:left;padding:.3em .6em;background:#f5f5f5;border-radius:.2em}pre code{padding:0}blockquote{padding:0 0 0 1em;margin:0 0 0 .1em;box-shadow:inset 5px 0 rgba(17,17,17,0.3)}label{cursor:pointer}[class^="icon-"]:before,[class*=" icon-"]:before{margin:0 .6em 0 0}i[class^="icon-"]:before,i[class*=" icon-"]:before{margin:0}.label,[data-tooltip]:after,button,.button,[type=submit],.dropimage{display:inline-block;text-align:center;margin:0;padding:.3em .9em;vertical-align:middle;background:#0074d9;color:#fff;border:0;border-radius:.2em;width:auto;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.success.label,.success[data-tooltip]:after,button.success,.success.button,.success[type=submit],.success.dropimage{background:#2ecc40}.warning.label,.warning[data-tooltip]:after,button.warning,.warning.button,.warning[type=submit],.warning.dropimage{background:#ff851b}.error.label,.error[data-tooltip]:after,button.error,.error.button,.error[type=submit],.error.dropimage{background:#ff4136}.pseudo.label,.pseudo[data-tooltip]:after,button.pseudo,.pseudo.button,.pseudo[type=submit],.pseudo.dropimage{background:transparent;color:#111}.label,[data-tooltip]:after{font-size:.6em;padding:.4em .6em;margin-left:1em;line-height:1}button,.button,[type=submit],.dropimage{margin:.3em 0;cursor:pointer;transition:all 0.3s;border-radius:.2em;height:auto;box-shadow:0 0 transparent inset}button:hover,.button:hover,[type=submit]:hover,.dropimage:hover,button:focus,.button:focus,[type=submit]:focus,.dropimage:focus{box-shadow:inset 0 0 0 99em rgba(255,255,255,0.2);border:0}button.pseudo:hover,.pseudo.button:hover,.pseudo[type=submit]:hover,.pseudo.dropimage:hover,button.pseudo:focus,.pseudo.button:focus,.pseudo[type=submit]:focus,.pseudo.dropimage:focus{box-shadow:inset 0 0 0 99em rgba(17,17,17,0.1)}button.active,.active.button,.active[type=submit],.active.dropimage,button:active,.button:active,[type=submit]:active,.dropimage:active,button.pseudo:active,.pseudo.button:active,.pseudo[type=submit]:active,.pseudo.dropimage:active{box-shadow:inset 0 0 0 99em rgba(17,17,17,0.2)}button[disabled],[disabled].button,[disabled][type=submit],[disabled].dropimage{cursor:default;box-shadow:none;background:#bbb}:checked+.toggle,:checked+.toggle:hover{box-shadow:inset 0 0 0 99em rgba(17,17,17,0.2)}[type]+.toggle{padding:.3em .9em;margin-right:0}[type]+.toggle:after,[type]+.toggle:before{display:none}input,textarea,.select select{line-height:1.5;margin:0;height:2.1em;padding:.3em .6em;border:1px solid #ccc;background-color:#fff;border-radius:.2em;transition:all 0.3s;width:100%}input:focus,textarea:focus,.select select:focus{border:1px solid #0074d9;outline:0}textarea{height:auto}[type=file],[type=color]{cursor:pointer}[type=file]{height:auto}select{background:#fff url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyIiBoZWlnaHQ9IjMiPjxwYXRoIGQ9Im0gMCwxIDEsMiAxLC0yIHoiLz48L3N2Zz4=) no-repeat scroll 95% center/10px 15px;background-position:calc(100% - 15px) center;border:1px solid #ccc;border-radius:.2em;cursor:pointer;width:100%;height:2.1em;box-sizing:border-box;padding:.3em .45em;transition:all .3s;-moz-appearance:none;-webkit-appearance:none;appearance:none}select::-ms-expand{display:none}select:focus,select:active{border:1px solid #0074d9;transition:outline 0s}select:-moz-focusring{color:transparent;text-shadow:0 0 0 #111}select option{font-size:inherit;padding:.3em .45em}[type=radio],[type=checkbox]{opacity:0;width:0;position:absolute;display:inline-block}[type=radio]+.checkable:hover:before,[type=checkbox]+.checkable:hover:before,[type=radio]:focus+.checkable:before,[type=checkbox]:focus+.checkable:before{border:1px solid #0074d9}[type=radio]+.checkable,[type=checkbox]+.checkable{position:relative;cursor:pointer;padding-left:1.5em;margin-right:.6em}[type=radio]+.checkable:before,[type=checkbox]+.checkable:before,[type=radio]+.checkable:after,[type=checkbox]+.checkable:after{content:'';position:absolute;display:inline-block;left:0;top:50%;transform:translateY(-50%);font-size:1em;line-height:1em;color:transparent;font-family:sans;text-align:center;box-sizing:border-box;width:1em;height:1em;border-radius:50%;transition:all 0.3s}[type=radio]+.checkable:before,[type=checkbox]+.checkable:before{border:1px solid #aaa}[type=radio]:checked+.checkable:after,[type=checkbox]:checked+.checkable:after{background:#555;transform:scale(0.5) translateY(-100%)}[type=checkbox]+.checkable:before{border-radius:.2em}[type=checkbox]+.checkable:after{content:"✔";background:none;transform:scale(2) translateY(-25%);visibility:hidden;opacity:0}[type=checkbox]:checked+.checkable:after{color:#111;background:none;transform:translateY(-50%);transition:all 0.3s;visibility:visible;opacity:1}table{text-align:left}td,th{padding:.3em 2.4em .3em .6em}th{text-align:left;font-weight:900;color:#fff;background-color:#0074d9}.success th{background-color:#2ecc40}.warning th{background-color:#ff851b}.error th{background-color:#ff4136}.dull th{background-color:#aaa}tr:nth-child(even){background:rgba(0,0,0,0.05)}.flex{display:-ms-flexbox;display:flex;margin-left:-0.6em;width:calc(100% + .6em);flex-wrap:wrap;transition:all .3s ease}.flex>*{box-sizing:border-box;flex:1 1 auto;padding-left:.6em;padding-bottom:.6em}.flex[class*="one"]>*,.flex[class*="two"]>*,.flex[class*="three"]>*,.flex[class*="four"]>*,.flex[class*="five"]>*,.flex[class*="six"]>*,.flex[class*="seven"]>*,.flex[class*="eight"]>*,.flex[class*="nine"]>*,.flex[class*="ten"]>*,.flex[class*="eleven"]>*,.flex[class*="twelve"]>*{flex-grow:0}.flex.grow>*{flex-grow:1}.center{justify-content:center}.one>*{width:100%}.two>*{width:50%}.three>*{width:33.33333%}.four>*{width:25%}.five>*{width:20%}.six>*{width:16.66666%}.seven>*{width:14.28571%}.eight>*{width:12.5%}.nine>*{width:11.11111%}.ten>*{width:10%}.eleven>*{width:9.09091%}.twelve>*{width:8.33333%}@media all and (min-width: 500px){.one-500>*{width:100%}.two-500>*{width:50%}.three-500>*{width:33.33333%}.four-500>*{width:25%}.five-500>*{width:20%}.six-500>*{width:16.66666%}.seven-500>*{width:14.28571%}.eight-500>*{width:12.5%}.nine-500>*{width:11.11111%}.ten-500>*{width:10%}.eleven-500>*{width:9.09091%}.twelve-500>*{width:8.33333%}}@media all and (min-width: 600px){.one-600>*{width:100%}.two-600>*{width:50%}.three-600>*{width:33.33333%}.four-600>*{width:25%}.five-600>*{width:20%}.six-600>*{width:16.66666%}.seven-600>*{width:14.28571%}.eight-600>*{width:12.5%}.nine-600>*{width:11.11111%}.ten-600>*{width:10%}.eleven-600>*{width:9.09091%}.twelve-600>*{width:8.33333%}}@media all and (min-width: 700px){.one-700>*{width:100%}.two-700>*{width:50%}.three-700>*{width:33.33333%}.four-700>*{width:25%}.five-700>*{width:20%}.six-700>*{width:16.66666%}.seven-700>*{width:14.28571%}.eight-700>*{width:12.5%}.nine-700>*{width:11.11111%}.ten-700>*{width:10%}.eleven-700>*{width:9.09091%}.twelve-700>*{width:8.33333%}}@media all and (min-width: 800px){.one-800>*{width:100%}.two-800>*{width:50%}.three-800>*{width:33.33333%}.four-800>*{width:25%}.five-800>*{width:20%}.six-800>*{width:16.66666%}.seven-800>*{width:14.28571%}.eight-800>*{width:12.5%}.nine-800>*{width:11.11111%}.ten-800>*{width:10%}.eleven-800>*{width:9.09091%}.twelve-800>*{width:8.33333%}}@media all and (min-width: 900px){.one-900>*{width:100%}.two-900>*{width:50%}.three-900>*{width:33.33333%}.four-900>*{width:25%}.five-900>*{width:20%}.six-900>*{width:16.66666%}.seven-900>*{width:14.28571%}.eight-900>*{width:12.5%}.nine-900>*{width:11.11111%}.ten-900>*{width:10%}.eleven-900>*{width:9.09091%}.twelve-900>*{width:8.33333%}}@media all and (min-width: 1000px){.one-1000>*{width:100%}.two-1000>*{width:50%}.three-1000>*{width:33.33333%}.four-1000>*{width:25%}.five-1000>*{width:20%}.six-1000>*{width:16.66666%}.seven-1000>*{width:14.28571%}.eight-1000>*{width:12.5%}.nine-1000>*{width:11.11111%}.ten-1000>*{width:10%}.eleven-1000>*{width:9.09091%}.twelve-1000>*{width:8.33333%}}@media all and (min-width: 1100px){.one-1100>*{width:100%}.two-1100>*{width:50%}.three-1100>*{width:33.33333%}.four-1100>*{width:25%}.five-1100>*{width:20%}.six-1100>*{width:16.66666%}.seven-1100>*{width:14.28571%}.eight-1100>*{width:12.5%}.nine-1100>*{width:11.11111%}.ten-1100>*{width:10%}.eleven-1100>*{width:9.09091%}.twelve-1100>*{width:8.33333%}}@media all and (min-width: 1200px){.one-1200>*{width:100%}.two-1200>*{width:50%}.three-1200>*{width:33.33333%}.four-1200>*{width:25%}.five-1200>*{width:20%}.six-1200>*{width:16.66666%}.seven-1200>*{width:14.28571%}.eight-1200>*{width:12.5%}.nine-1200>*{width:11.11111%}.ten-1200>*{width:10%}.eleven-1200>*{width:9.09091%}.twelve-1200>*{width:8.33333%}}@media all and (min-width: 1300px){.one-1300>*{width:100%}.two-1300>*{width:50%}.three-1300>*{width:33.33333%}.four-1300>*{width:25%}.five-1300>*{width:20%}.six-1300>*{width:16.66666%}.seven-1300>*{width:14.28571%}.eight-1300>*{width:12.5%}.nine-1300>*{width:11.11111%}.ten-1300>*{width:10%}.eleven-1300>*{width:9.09091%}.twelve-1300>*{width:8.33333%}}@media all and (min-width: 1400px){.one-1400>*{width:100%}.two-1400>*{width:50%}.three-1400>*{width:33.33333%}.four-1400>*{width:25%}.five-1400>*{width:20%}.six-1400>*{width:16.66666%}.seven-1400>*{width:14.28571%}.eight-1400>*{width:12.5%}.nine-1400>*{width:11.11111%}.ten-1400>*{width:10%}.eleven-1400>*{width:9.09091%}.twelve-1400>*{width:8.33333%}}@media all and (min-width: 1500px){.one-1500>*{width:100%}.two-1500>*{width:50%}.three-1500>*{width:33.33333%}.four-1500>*{width:25%}.five-1500>*{width:20%}.six-1500>*{width:16.66666%}.seven-1500>*{width:14.28571%}.eight-1500>*{width:12.5%}.nine-1500>*{width:11.11111%}.ten-1500>*{width:10%}.eleven-1500>*{width:9.09091%}.twelve-1500>*{width:8.33333%}}@media all and (min-width: 1600px){.one-1600>*{width:100%}.two-1600>*{width:50%}.three-1600>*{width:33.33333%}.four-1600>*{width:25%}.five-1600>*{width:20%}.six-1600>*{width:16.66666%}.seven-1600>*{width:14.28571%}.eight-1600>*{width:12.5%}.nine-1600>*{width:11.11111%}.ten-1600>*{width:10%}.eleven-1600>*{width:9.09091%}.twelve-1600>*{width:8.33333%}}@media all and (min-width: 1700px){.one-1700>*{width:100%}.two-1700>*{width:50%}.three-1700>*{width:33.33333%}.four-1700>*{width:25%}.five-1700>*{width:20%}.six-1700>*{width:16.66666%}.seven-1700>*{width:14.28571%}.eight-1700>*{width:12.5%}.nine-1700>*{width:11.11111%}.ten-1700>*{width:10%}.eleven-1700>*{width:9.09091%}.twelve-1700>*{width:8.33333%}}@media all and (min-width: 1800px){.one-1800>*{width:100%}.two-1800>*{width:50%}.three-1800>*{width:33.33333%}.four-1800>*{width:25%}.five-1800>*{width:20%}.six-1800>*{width:16.66666%}.seven-1800>*{width:14.28571%}.eight-1800>*{width:12.5%}.nine-1800>*{width:11.11111%}.ten-1800>*{width:10%}.eleven-1800>*{width:9.09091%}.twelve-1800>*{width:8.33333%}}@media all and (min-width: 1900px){.one-1900>*{width:100%}.two-1900>*{width:50%}.three-1900>*{width:33.33333%}.four-1900>*{width:25%}.five-1900>*{width:20%}.six-1900>*{width:16.66666%}.seven-1900>*{width:14.28571%}.eight-1900>*{width:12.5%}.nine-1900>*{width:11.11111%}.ten-1900>*{width:10%}.eleven-1900>*{width:9.09091%}.twelve-1900>*{width:8.33333%}}@media all and (min-width: 2000px){.one-2000>*{width:100%}.two-2000>*{width:50%}.three-2000>*{width:33.33333%}.four-2000>*{width:25%}.five-2000>*{width:20%}.six-2000>*{width:16.66666%}.seven-2000>*{width:14.28571%}.eight-2000>*{width:12.5%}.nine-2000>*{width:11.11111%}.ten-2000>*{width:10%}.eleven-2000>*{width:9.09091%}.twelve-2000>*{width:8.33333%}}.full{width:100%}.half{width:50%}.third{width:33.33333%}.two-third{width:66.66666%}.fourth{width:25%}.three-fourth{width:75%}.fifth{width:20%}.two-fifth{width:40%}.three-fifth{width:60%}.four-fifth{width:80%}.sixth{width:16.66666%}.none{display:none}@media all and (min-width: 500px){.full-500{width:100%;display:block}.half-500{width:50%;display:block}.third-500{width:33.33333%;display:block}.two-third-500{width:66.66666%;display:block}.fourth-500{width:25%;display:block}.three-fourth-500{width:75%;display:block}.fifth-500{width:20%;display:block}.two-fifth-500{width:40%;display:block}.three-fifth-500{width:60%;display:block}.four-fifth-500{width:80%;display:block}.sixth-500{width:16.66666%;display:block}}@media all and (min-width: 600px){.full-600{width:100%;display:block}.half-600{width:50%;display:block}.third-600{width:33.33333%;display:block}.two-third-600{width:66.66666%;display:block}.fourth-600{width:25%;display:block}.three-fourth-600{width:75%;display:block}.fifth-600{width:20%;display:block}.two-fifth-600{width:40%;display:block}.three-fifth-600{width:60%;display:block}.four-fifth-600{width:80%;display:block}.sixth-600{width:16.66666%;display:block}}@media all and (min-width: 700px){.full-700{width:100%;display:block}.half-700{width:50%;display:block}.third-700{width:33.33333%;display:block}.two-third-700{width:66.66666%;display:block}.fourth-700{width:25%;display:block}.three-fourth-700{width:75%;display:block}.fifth-700{width:20%;display:block}.two-fifth-700{width:40%;display:block}.three-fifth-700{width:60%;display:block}.four-fifth-700{width:80%;display:block}.sixth-700{width:16.66666%;display:block}}@media all and (min-width: 800px){.full-800{width:100%;display:block}.half-800{width:50%;display:block}.third-800{width:33.33333%;display:block}.two-third-800{width:66.66666%;display:block}.fourth-800{width:25%;display:block}.three-fourth-800{width:75%;display:block}.fifth-800{width:20%;display:block}.two-fifth-800{width:40%;display:block}.three-fifth-800{width:60%;display:block}.four-fifth-800{width:80%;display:block}.sixth-800{width:16.66666%;display:block}}@media all and (min-width: 900px){.full-900{width:100%;display:block}.half-900{width:50%;display:block}.third-900{width:33.33333%;display:block}.two-third-900{width:66.66666%;display:block}.fourth-900{width:25%;display:block}.three-fourth-900{width:75%;display:block}.fifth-900{width:20%;display:block}.two-fifth-900{width:40%;display:block}.three-fifth-900{width:60%;display:block}.four-fifth-900{width:80%;display:block}.sixth-900{width:16.66666%;display:block}}@media all and (min-width: 1000px){.full-1000{width:100%;display:block}.half-1000{width:50%;display:block}.third-1000{width:33.33333%;display:block}.two-third-1000{width:66.66666%;display:block}.fourth-1000{width:25%;display:block}.three-fourth-1000{width:75%;display:block}.fifth-1000{width:20%;display:block}.two-fifth-1000{width:40%;display:block}.three-fifth-1000{width:60%;display:block}.four-fifth-1000{width:80%;display:block}.sixth-1000{width:16.66666%;display:block}}@media all and (min-width: 1100px){.full-1100{width:100%;display:block}.half-1100{width:50%;display:block}.third-1100{width:33.33333%;display:block}.two-third-1100{width:66.66666%;display:block}.fourth-1100{width:25%;display:block}.three-fourth-1100{width:75%;display:block}.fifth-1100{width:20%;display:block}.two-fifth-1100{width:40%;display:block}.three-fifth-1100{width:60%;display:block}.four-fifth-1100{width:80%;display:block}.sixth-1100{width:16.66666%;display:block}}@media all and (min-width: 1200px){.full-1200{width:100%;display:block}.half-1200{width:50%;display:block}.third-1200{width:33.33333%;display:block}.two-third-1200{width:66.66666%;display:block}.fourth-1200{width:25%;display:block}.three-fourth-1200{width:75%;display:block}.fifth-1200{width:20%;display:block}.two-fifth-1200{width:40%;display:block}.three-fifth-1200{width:60%;display:block}.four-fifth-1200{width:80%;display:block}.sixth-1200{width:16.66666%;display:block}}@media all and (min-width: 1300px){.full-1300{width:100%;display:block}.half-1300{width:50%;display:block}.third-1300{width:33.33333%;display:block}.two-third-1300{width:66.66666%;display:block}.fourth-1300{width:25%;display:block}.three-fourth-1300{width:75%;display:block}.fifth-1300{width:20%;display:block}.two-fifth-1300{width:40%;display:block}.three-fifth-1300{width:60%;display:block}.four-fifth-1300{width:80%;display:block}.sixth-1300{width:16.66666%;display:block}}@media all and (min-width: 1400px){.full-1400{width:100%;display:block}.half-1400{width:50%;display:block}.third-1400{width:33.33333%;display:block}.two-third-1400{width:66.66666%;display:block}.fourth-1400{width:25%;display:block}.three-fourth-1400{width:75%;display:block}.fifth-1400{width:20%;display:block}.two-fifth-1400{width:40%;display:block}.three-fifth-1400{width:60%;display:block}.four-fifth-1400{width:80%;display:block}.sixth-1400{width:16.66666%;display:block}}@media all and (min-width: 1500px){.full-1500{width:100%;display:block}.half-1500{width:50%;display:block}.third-1500{width:33.33333%;display:block}.two-third-1500{width:66.66666%;display:block}.fourth-1500{width:25%;display:block}.three-fourth-1500{width:75%;display:block}.fifth-1500{width:20%;display:block}.two-fifth-1500{width:40%;display:block}.three-fifth-1500{width:60%;display:block}.four-fifth-1500{width:80%;display:block}.sixth-1500{width:16.66666%;display:block}}@media all and (min-width: 1600px){.full-1600{width:100%;display:block}.half-1600{width:50%;display:block}.third-1600{width:33.33333%;display:block}.two-third-1600{width:66.66666%;display:block}.fourth-1600{width:25%;display:block}.three-fourth-1600{width:75%;display:block}.fifth-1600{width:20%;display:block}.two-fifth-1600{width:40%;display:block}.three-fifth-1600{width:60%;display:block}.four-fifth-1600{width:80%;display:block}.sixth-1600{width:16.66666%;display:block}}@media all and (min-width: 1700px){.full-1700{width:100%;display:block}.half-1700{width:50%;display:block}.third-1700{width:33.33333%;display:block}.two-third-1700{width:66.66666%;display:block}.fourth-1700{width:25%;display:block}.three-fourth-1700{width:75%;display:block}.fifth-1700{width:20%;display:block}.two-fifth-1700{width:40%;display:block}.three-fifth-1700{width:60%;display:block}.four-fifth-1700{width:80%;display:block}.sixth-1700{width:16.66666%;display:block}}@media all and (min-width: 1800px){.full-1800{width:100%;display:block}.half-1800{width:50%;display:block}.third-1800{width:33.33333%;display:block}.two-third-1800{width:66.66666%;display:block}.fourth-1800{width:25%;display:block}.three-fourth-1800{width:75%;display:block}.fifth-1800{width:20%;display:block}.two-fifth-1800{width:40%;display:block}.three-fifth-1800{width:60%;display:block}.four-fifth-1800{width:80%;display:block}.sixth-1800{width:16.66666%;display:block}}@media all and (min-width: 1900px){.full-1900{width:100%;display:block}.half-1900{width:50%;display:block}.third-1900{width:33.33333%;display:block}.two-third-1900{width:66.66666%;display:block}.fourth-1900{width:25%;display:block}.three-fourth-1900{width:75%;display:block}.fifth-1900{width:20%;display:block}.two-fifth-1900{width:40%;display:block}.three-fifth-1900{width:60%;display:block}.four-fifth-1900{width:80%;display:block}.sixth-1900{width:16.66666%;display:block}}@media all and (min-width: 2000px){.full-2000{width:100%;display:block}.half-2000{width:50%;display:block}.third-2000{width:33.33333%;display:block}.two-third-2000{width:66.66666%;display:block}.fourth-2000{width:25%;display:block}.three-fourth-2000{width:75%;display:block}.fifth-2000{width:20%;display:block}.two-fifth-2000{width:40%;display:block}.three-fifth-2000{width:60%;display:block}.four-fifth-2000{width:80%;display:block}.sixth-2000{width:16.66666%;display:block}}@media all and (min-width: 500px){.none-500{display:none}}@media all and (min-width: 600px){.none-600{display:none}}@media all and (min-width: 700px){.none-700{display:none}}@media all and (min-width: 800px){.none-800{display:none}}@media all and (min-width: 900px){.none-900{display:none}}@media all and (min-width: 1000px){.none-1000{display:none}}@media all and (min-width: 1100px){.none-1100{display:none}}@media all and (min-width: 1200px){.none-1200{display:none}}@media all and (min-width: 1300px){.none-1300{display:none}}@media all and (min-width: 1400px){.none-1400{display:none}}@media all and (min-width: 1500px){.none-1500{display:none}}@media all and (min-width: 1600px){.none-1600{display:none}}@media all and (min-width: 1700px){.none-1700{display:none}}@media all and (min-width: 1800px){.none-1800{display:none}}@media all and (min-width: 1900px){.none-1900{display:none}}@media all and (min-width: 2000px){.none-2000{display:none}}.off-none{margin-left:0}.off-half{margin-left:50%}.off-third{margin-left:33.33333%}.off-two-third{margin-left:66.66666%}.off-fourth{margin-left:25%}.off-three-fourth{margin-left:75%}.off-fifth{margin-left:20%}.off-two-fifth{margin-left:40%}.off-three-fifth{margin-left:60%}.off-four-fifth{margin-left:80%}.off-sixth{margin-left:16.66666%}@media all and (min-width: 500px){.off-none-500{margin-left:0}.off-half-500{margin-left:50%}.off-third-500{margin-left:33.33333%}.off-two-third-500{margin-left:66.66666%}.off-fourth-500{margin-left:25%}.off-three-fourth-500{margin-left:75%}.off-fifth-500{margin-left:20%}.off-two-fifth-500{margin-left:40%}.off-three-fifth-500{margin-left:60%}.off-four-fifth-500{margin-left:80%}.off-sixth-500{margin-left:16.66666%}}@media all and (min-width: 600px){.off-none-600{margin-left:0}.off-half-600{margin-left:50%}.off-third-600{margin-left:33.33333%}.off-two-third-600{margin-left:66.66666%}.off-fourth-600{margin-left:25%}.off-three-fourth-600{margin-left:75%}.off-fifth-600{margin-left:20%}.off-two-fifth-600{margin-left:40%}.off-three-fifth-600{margin-left:60%}.off-four-fifth-600{margin-left:80%}.off-sixth-600{margin-left:16.66666%}}@media all and (min-width: 700px){.off-none-700{margin-left:0}.off-half-700{margin-left:50%}.off-third-700{margin-left:33.33333%}.off-two-third-700{margin-left:66.66666%}.off-fourth-700{margin-left:25%}.off-three-fourth-700{margin-left:75%}.off-fifth-700{margin-left:20%}.off-two-fifth-700{margin-left:40%}.off-three-fifth-700{margin-left:60%}.off-four-fifth-700{margin-left:80%}.off-sixth-700{margin-left:16.66666%}}@media all and (min-width: 800px){.off-none-800{margin-left:0}.off-half-800{margin-left:50%}.off-third-800{margin-left:33.33333%}.off-two-third-800{margin-left:66.66666%}.off-fourth-800{margin-left:25%}.off-three-fourth-800{margin-left:75%}.off-fifth-800{margin-left:20%}.off-two-fifth-800{margin-left:40%}.off-three-fifth-800{margin-left:60%}.off-four-fifth-800{margin-left:80%}.off-sixth-800{margin-left:16.66666%}}@media all and (min-width: 900px){.off-none-900{margin-left:0}.off-half-900{margin-left:50%}.off-third-900{margin-left:33.33333%}.off-two-third-900{margin-left:66.66666%}.off-fourth-900{margin-left:25%}.off-three-fourth-900{margin-left:75%}.off-fifth-900{margin-left:20%}.off-two-fifth-900{margin-left:40%}.off-three-fifth-900{margin-left:60%}.off-four-fifth-900{margin-left:80%}.off-sixth-900{margin-left:16.66666%}}@media all and (min-width: 1000px){.off-none-1000{margin-left:0}.off-half-1000{margin-left:50%}.off-third-1000{margin-left:33.33333%}.off-two-third-1000{margin-left:66.66666%}.off-fourth-1000{margin-left:25%}.off-three-fourth-1000{margin-left:75%}.off-fifth-1000{margin-left:20%}.off-two-fifth-1000{margin-left:40%}.off-three-fifth-1000{margin-left:60%}.off-four-fifth-1000{margin-left:80%}.off-sixth-1000{margin-left:16.66666%}}@media all and (min-width: 1100px){.off-none-1100{margin-left:0}.off-half-1100{margin-left:50%}.off-third-1100{margin-left:33.33333%}.off-two-third-1100{margin-left:66.66666%}.off-fourth-1100{margin-left:25%}.off-three-fourth-1100{margin-left:75%}.off-fifth-1100{margin-left:20%}.off-two-fifth-1100{margin-left:40%}.off-three-fifth-1100{margin-left:60%}.off-four-fifth-1100{margin-left:80%}.off-sixth-1100{margin-left:16.66666%}}@media all and (min-width: 1200px){.off-none-1200{margin-left:0}.off-half-1200{margin-left:50%}.off-third-1200{margin-left:33.33333%}.off-two-third-1200{margin-left:66.66666%}.off-fourth-1200{margin-left:25%}.off-three-fourth-1200{margin-left:75%}.off-fifth-1200{margin-left:20%}.off-two-fifth-1200{margin-left:40%}.off-three-fifth-1200{margin-left:60%}.off-four-fifth-1200{margin-left:80%}.off-sixth-1200{margin-left:16.66666%}}@media all and (min-width: 1300px){.off-none-1300{margin-left:0}.off-half-1300{margin-left:50%}.off-third-1300{margin-left:33.33333%}.off-two-third-1300{margin-left:66.66666%}.off-fourth-1300{margin-left:25%}.off-three-fourth-1300{margin-left:75%}.off-fifth-1300{margin-left:20%}.off-two-fifth-1300{margin-left:40%}.off-three-fifth-1300{margin-left:60%}.off-four-fifth-1300{margin-left:80%}.off-sixth-1300{margin-left:16.66666%}}@media all and (min-width: 1400px){.off-none-1400{margin-left:0}.off-half-1400{margin-left:50%}.off-third-1400{margin-left:33.33333%}.off-two-third-1400{margin-left:66.66666%}.off-fourth-1400{margin-left:25%}.off-three-fourth-1400{margin-left:75%}.off-fifth-1400{margin-left:20%}.off-two-fifth-1400{margin-left:40%}.off-three-fifth-1400{margin-left:60%}.off-four-fifth-1400{margin-left:80%}.off-sixth-1400{margin-left:16.66666%}}@media all and (min-width: 1500px){.off-none-1500{margin-left:0}.off-half-1500{margin-left:50%}.off-third-1500{margin-left:33.33333%}.off-two-third-1500{margin-left:66.66666%}.off-fourth-1500{margin-left:25%}.off-three-fourth-1500{margin-left:75%}.off-fifth-1500{margin-left:20%}.off-two-fifth-1500{margin-left:40%}.off-three-fifth-1500{margin-left:60%}.off-four-fifth-1500{margin-left:80%}.off-sixth-1500{margin-left:16.66666%}}@media all and (min-width: 1600px){.off-none-1600{margin-left:0}.off-half-1600{margin-left:50%}.off-third-1600{margin-left:33.33333%}.off-two-third-1600{margin-left:66.66666%}.off-fourth-1600{margin-left:25%}.off-three-fourth-1600{margin-left:75%}.off-fifth-1600{margin-left:20%}.off-two-fifth-1600{margin-left:40%}.off-three-fifth-1600{margin-left:60%}.off-four-fifth-1600{margin-left:80%}.off-sixth-1600{margin-left:16.66666%}}@media all and (min-width: 1700px){.off-none-1700{margin-left:0}.off-half-1700{margin-left:50%}.off-third-1700{margin-left:33.33333%}.off-two-third-1700{margin-left:66.66666%}.off-fourth-1700{margin-left:25%}.off-three-fourth-1700{margin-left:75%}.off-fifth-1700{margin-left:20%}.off-two-fifth-1700{margin-left:40%}.off-three-fifth-1700{margin-left:60%}.off-four-fifth-1700{margin-left:80%}.off-sixth-1700{margin-left:16.66666%}}@media all and (min-width: 1800px){.off-none-1800{margin-left:0}.off-half-1800{margin-left:50%}.off-third-1800{margin-left:33.33333%}.off-two-third-1800{margin-left:66.66666%}.off-fourth-1800{margin-left:25%}.off-three-fourth-1800{margin-left:75%}.off-fifth-1800{margin-left:20%}.off-two-fifth-1800{margin-left:40%}.off-three-fifth-1800{margin-left:60%}.off-four-fifth-1800{margin-left:80%}.off-sixth-1800{margin-left:16.66666%}}@media all and (min-width: 1900px){.off-none-1900{margin-left:0}.off-half-1900{margin-left:50%}.off-third-1900{margin-left:33.33333%}.off-two-third-1900{margin-left:66.66666%}.off-fourth-1900{margin-left:25%}.off-three-fourth-1900{margin-left:75%}.off-fifth-1900{margin-left:20%}.off-two-fifth-1900{margin-left:40%}.off-three-fifth-1900{margin-left:60%}.off-four-fifth-1900{margin-left:80%}.off-sixth-1900{margin-left:16.66666%}}@media all and (min-width: 2000px){.off-none-2000{margin-left:0}.off-half-2000{margin-left:50%}.off-third-2000{margin-left:33.33333%}.off-two-third-2000{margin-left:66.66666%}.off-fourth-2000{margin-left:25%}.off-three-fourth-2000{margin-left:75%}.off-fifth-2000{margin-left:20%}.off-two-fifth-2000{margin-left:40%}.off-three-fifth-2000{margin-left:60%}.off-four-fifth-2000{margin-left:80%}.off-sixth-2000{margin-left:16.66666%}}nav{position:fixed;top:0;left:0;right:0;height:3em;padding:0 .6em;background:#fff;box-shadow:0 0 0.2em rgba(17,17,17,0.2);z-index:10000;transition:all .3s;transform-style:preserve-3d}nav .brand,nav .menu,nav .burger{float:right;position:relative;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}nav .brand{font-weight:700;float:left;padding:0 .6em;max-width:50%;white-space:nowrap;color:#111}nav .brand *{vertical-align:middle}nav .logo{height:2em;margin-right:.3em}nav .select::after{height:calc(100% - 1px);padding:0;line-height:2.4em}nav .menu>*{margin-right:.6em}nav .burger{display:none}@media all and (max-width: 60em){nav .burger{display:inline-block;cursor:pointer;bottom:-1000em;margin:0}nav .burger ~ .menu,nav .show:checked ~ .burger{position:fixed;min-height:100%;top:0;right:0;bottom:-1000em;margin:0;background:#fff;transition:all .5s ease;transform:none}nav .burger ~ .menu{z-index:11}nav .show:checked ~ .burger{color:transparent;width:100%;border-radius:0;background:rgba(0,0,0,0.2);transition:all .5s ease}nav .show ~ .menu{width:70%;max-width:300px;transform-origin:center right;transition:all .25s ease;transform:scaleX(0)}nav .show ~ .menu>*{transform:translateX(100%);transition:all 0s ease .5s}nav .show:checked ~ .menu>*:nth-child(1){transition:all .5s cubic-bezier(0.645, 0.045, 0.355, 1) 0s}nav .show:checked ~ .menu>*:nth-child(2){transition:all .5s cubic-bezier(0.645, 0.045, 0.355, 1) .1s}nav .show:checked ~ .menu>*:nth-child(3){transition:all .5s cubic-bezier(0.645, 0.045, 0.355, 1) .2s}nav .show:checked ~ .menu>*:nth-child(4){transition:all .5s cubic-bezier(0.645, 0.045, 0.355, 1) .3s}nav .show:checked ~ .menu>*:nth-child(5){transition:all .5s cubic-bezier(0.645, 0.045, 0.355, 1) .4s}nav .show:checked ~ .menu>*:nth-child(6){transition:all .5s cubic-bezier(0.645, 0.045, 0.355, 1) .5s}nav .show:checked ~ .menu{transform:scaleX(1)}nav .show:checked ~ .menu>*{transform:translateX(0);transition:all .5s ease-in-out .6s}nav .burger ~ .menu>*{display:block;margin:.3em;text-align:left;max-width:calc(100% - .6em)}nav .burger ~ .menu>a{padding:.3em .9em}}.stack,.stack .toggle{margin-top:0;margin-bottom:0;display:block;width:100%;text-align:left;border-radius:0}.stack:first-child,.stack:first-child .toggle{border-top-left-radius:.2em;border-top-right-radius:.2em}.stack:last-child,.stack:last-child .toggle{border-bottom-left-radius:.2em;border-bottom-right-radius:.2em}input.stack,textarea.stack,select.stack{transition:border-bottom 0 ease 0;border-bottom-width:0}input.stack:last-child,textarea.stack:last-child,select.stack:last-child{border-bottom-width:1px}input.stack:focus+input,input.stack:focus+textarea,input.stack:focus+select,textarea.stack:focus+input,textarea.stack:focus+textarea,textarea.stack:focus+select,select.stack:focus+input,select.stack:focus+textarea,select.stack:focus+select{border-top-color:#0074d9}.card,.modal .overlay ~ *{position:relative;box-shadow:0;border-radius:.2em;border:1px solid #ccc;overflow:hidden;text-align:left;background:#fff;margin-bottom:.6em;padding:0;transition:all .3s ease}.hidden.card,.modal .overlay ~ .hidden,:checked+.card,.modal .overlay ~ :checked+*,.modal .overlay:checked+*{font-size:0;padding:0;margin:0;border:0}.card>*,.modal .overlay ~ *>*{max-width:100%;display:block}.card>*:last-child,.modal .overlay ~ *>*:last-child{margin-bottom:0}.card header,.modal .overlay ~ * header,.card section,.modal .overlay ~ * section,.card>p,.modal .overlay ~ *>p{padding:.6em .8em}.card section,.modal .overlay ~ * section{padding:.6em .8em 0}.card hr,.modal .overlay ~ * hr{border:none;height:1px;background-color:#eee}.card header,.modal .overlay ~ * header{font-weight:bold;position:relative;border-bottom:1px solid #eee}.card header h1,.modal .overlay ~ * header h1,.card header h2,.modal .overlay ~ * header h2,.card header h3,.modal .overlay ~ * header h3,.card header h4,.modal .overlay ~ * header h4,.card header h5,.modal .overlay ~ * header h5,.card header h6,.modal .overlay ~ * header h6{padding:0;margin:0 2em 0 0;line-height:1;display:inline-block;vertical-align:text-bottom}.card header:last-child,.modal .overlay ~ * header:last-child{border-bottom:0}.card footer,.modal .overlay ~ * footer{padding:.8em}.card p,.modal .overlay ~ * p{margin:.3em 0}.card p:first-child,.modal .overlay ~ * p:first-child{margin-top:0}.card p:last-child,.modal .overlay ~ * p:last-child{margin-bottom:0}.card>p,.modal .overlay ~ *>p{margin:0;padding-right:2.5em}.card .close,.modal .overlay ~ * .close{position:absolute;top:.4em;right:.3em;font-size:1.2em;padding:0 .5em;cursor:pointer;width:auto}.card .close:hover,.modal .overlay ~ * .close:hover{color:#ff4136}.card h1+.close,.modal .overlay ~ * h1+.close{margin:.2em}.card h2+.close,.modal .overlay ~ * h2+.close{margin:.1em}.card .dangerous,.modal .overlay ~ * .dangerous{background:#ff4136;float:right}.modal{text-align:center}.modal>input{display:none}.modal>input ~ *{opacity:0;max-height:0;overflow:hidden}.modal .overlay{top:0;left:0;bottom:0;right:0;position:fixed;margin:0;border-radius:0;background:rgba(17,17,17,0.6);transition:all 0.3s;z-index:100000}.modal .overlay:before,.modal .overlay:after{display:none}.modal .overlay ~ *{border:0;position:fixed;top:50%;left:50%;transform:translateX(-50%) translateY(-50%) scale(0.2, 0.2);z-index:1000000;transition:all 0.3s}.modal>input:checked ~ *{display:block;opacity:1;max-height:10000px;transition:all 0.3s}.modal>input:checked ~ .overlay ~ *{max-height:90%;overflow:auto;-webkit-transform:translateX(-50%) translateY(-50%) scale(1, 1);transform:translateX(-50%) translateY(-50%) scale(1, 1)}@media (max-width: 60em){.modal .overlay ~ *{min-width:90%}}.dropimage{position:relative;display:block;padding:0;padding-bottom:56.25%;overflow:hidden;cursor:pointer;border:0;margin:.3em 0;border-radius:.2em;background-color:#ddd;background-size:cover;background-position:center center;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NDAiIGhlaWdodD0iNjQwIiB2ZXJzaW9uPSIxLjEiPjxnIHN0eWxlPSJmaWxsOiMzMzMiPjxwYXRoIGQ9Ik0gMTg3IDIzMCBDIDE3NSAyMzAgMTY1IDI0MCAxNjUgMjUyIEwgMTY1IDMwMCBMIDE2NSA0MDggQyAxNjUgNDIwIDE3NSA0MzAgMTg3IDQzMCBMIDQ2MyA0MzAgQyA0NzUgNDMwIDQ4NSA0MjAgNDg1IDQwOCBMIDQ4NSAzMDAgTCA0ODUgMjUyIEMgNDg1IDI0MCA0NzUgMjMwIDQ2MyAyMzAgTCAxODcgMjMwIHogTSAzNjAgMjU2IEEgNzAgNzIgMCAwIDEgNDMwIDMyOCBBIDcwIDcyIDAgMCAxIDM2MCA0MDAgQSA3MCA3MiAwIDAgMSAyOTAgMzI4IEEgNzAgNzIgMCAwIDEgMzYwIDI1NiB6Ii8+PGNpcmNsZSBjeD0iMzYwIiBjeT0iMzMwIiByPSI0MSIvPjxwYXRoIGQ9Im0yMDUgMjI1IDUtMTAgMjAgMCA1IDEwLTMwIDAiLz48cGF0aCBkPSJNMjg1IDIwMEwyNzAgMjI1IDM3NiAyMjUgMzYxIDIwMCAyODUgMjAwek0zMTAgMjA1TDMzNyAyMDUgMzM3IDIxOCAzMTAgMjE4IDMxMCAyMDV6Ii8+PHBhdGggZD0ibTQwNSAyMjUgNS0xMCAyMCAwIDUgMTAtMzAgMCIvPjwvZz48L3N2Zz4=)}.dropimage input{left:0;width:100%;height:100%;border:0;margin:0;padding:0;opacity:0;cursor:pointer;position:absolute}.tabs{position:relative;overflow:hidden}.tabs>label img{float:left;margin-left:.6em}.tabs>.row{width:calc(100% + 2 * .6em);display:table;table-layout:fixed;position:relative;padding-left:0;transition:all .3s;border-spacing:0;margin:0}.tabs>.row:before,.tabs>.row:after{display:none}.tabs>.row>*,.tabs>.row img{display:table-cell;vertical-align:top;margin:0;width:100%}.tabs>input{display:none}.tabs>input+*{width:100%}.tabs>input+label{width:auto}.two.tabs>.row{width:200%;left:-100%}.two.tabs>input:nth-of-type(1):checked ~ .row{margin-left:100%}.two.tabs>label img{width:48%;margin:4% 0 4% 4%}.three.tabs>.row{width:300%;left:-200%}.three.tabs>input:nth-of-type(1):checked ~ .row{margin-left:200%}.three.tabs>input:nth-of-type(2):checked ~ .row{margin-left:100%}.three.tabs>label img{width:30%;margin:5% 0 5% 5%}.four.tabs>.row{width:400%;left:-300%}.four.tabs>input:nth-of-type(1):checked ~ .row{margin-left:300%}.four.tabs>input:nth-of-type(2):checked ~ .row{margin-left:200%}.four.tabs>input:nth-of-type(3):checked ~ .row{margin-left:100%}.four.tabs>label img{width:22%;margin:4% 0 4% 4%}.tabs>label:first-of-type img{margin-left:0}[data-tooltip]{position:relative}[data-tooltip]:after,[data-tooltip]:before{position:absolute;z-index:10;opacity:0;border-width:0;height:0;padding:0;overflow:hidden;transition:opacity .6s ease, height 0s ease .6s;top:calc(100% - 6px);left:0;margin-top:12px}[data-tooltip]:after{margin-left:0;font-size:.8em;background:#111;content:attr(data-tooltip);white-space:nowrap}[data-tooltip]:before{content:'';width:0;height:0;border-width:0;border-style:solid;border-color:transparent transparent #111;margin-top:0;left:10px}[data-tooltip]:hover:after,[data-tooltip]:focus:after,[data-tooltip]:hover:before,[data-tooltip]:focus:before{opacity:1;border-width:6px;height:auto}[data-tooltip]:hover:after,[data-tooltip]:focus:after{padding:.45em .9em}.tooltip-top:after,.tooltip-top:before{top:auto;bottom:calc(100% - 6px);left:0;margin-bottom:12px}.tooltip-top:before{border-color:#111 transparent transparent;margin-bottom:0;left:10px}.tooltip-right:after,.tooltip-right:before{left:100%;margin-left:6px;margin-top:0;top:0}.tooltip-right:before{border-color:transparent #111 transparent transparent;margin-left:-6px;left:100%;top:7px}.tooltip-left:after,.tooltip-left:before{right:100%;margin-right:6px;left:auto;margin-top:0;top:0}.tooltip-left:before{border-color:transparent transparent transparent #111;margin-right:-6px;right:100%;top:7px}
|