diff --git a/libs/CHANGELOG.md b/libs/CHANGELOG.md index ccae79a19..79516fbe5 100644 --- a/libs/CHANGELOG.md +++ b/libs/CHANGELOG.md @@ -4,8 +4,20 @@ All notable changes to this project will be documented in this file. ## [Unreleased] -## [0.0.15] +## [0.0.16] +### Added +- Support api of `logseq.UI.queryElementRect: (selector: string) => Promise` +- Support api of `logseq.UI.queryElementById: (id: string) => Promise` +- Support api of `logseq.UI.checkSlotValid: (slot: UISlotIdentity['slot']) => Promise` +- Support api of `logseq.UI.resolveThemeCssPropsVals: (props: string | Array) => Promise` +- Support api of `logseq.Assets.builtInOpen(path: string): Promise` +### Fixed +- fix Plugin can't register command shortcut with editing mode [#10392](https://github.com/logseq/logseq/issues/10392) +- fix [Plugin API] [Keymap] Command without keybinding can't be present in Keymap [#10466](https://github.com/logseq/logseq/issues/10466) +- fix [Possible DATA LOSS] [Plugin API] [Keymap] Any plugin could break the global config.edn [#10465](https://github.com/logseq/logseq/issues/10465) + +## [0.0.15] ### Added - Support a plug-in flag for the plugin slash commands item - Support api of `logseq.App.setCurrentGraphConfigs: (configs: {}) => Promise` diff --git a/libs/package.json b/libs/package.json index eb322c612..d07348a61 100644 --- a/libs/package.json +++ b/libs/package.json @@ -1,6 +1,6 @@ { "name": "@logseq/libs", - "version": "0.0.15", + "version": "0.0.16", "description": "Logseq SDK libraries", "main": "dist/lsplugin.user.js", "typings": "index.d.ts", diff --git a/libs/src/LSPlugin.core.ts b/libs/src/LSPlugin.core.ts index ee5ebb8be..9bf7ae3db 100644 --- a/libs/src/LSPlugin.core.ts +++ b/libs/src/LSPlugin.core.ts @@ -54,6 +54,7 @@ const DIR_PLUGINS = 'plugins' declare global { interface Window { LSPluginCore: LSPluginCore + DOMPurify: typeof DOMPurify } } @@ -308,23 +309,25 @@ function initProviderHandlers(pluginLocal: PluginLocal) { // provider:ui pluginLocal.on(_('ui'), (ui: UIOptions) => { pluginLocal._onHostMounted(() => { - pluginLocal._dispose( - setupInjectedUI.call( - pluginLocal, - ui, - Object.assign( - { - 'data-ref': pluginLocal.id, - }, - ui.attrs || {} - ), - ({ el, float }) => { - if (!float) return - const identity = el.dataset.identity - pluginLocal.layoutCore.move_container_to_top(identity) - } - ) + const ret = setupInjectedUI.call( + pluginLocal, + ui, + Object.assign( + { + 'data-ref': pluginLocal.id, + }, + ui.attrs || {} + ), + ({ el, float }) => { + if (!float) return + const identity = el.dataset.identity + pluginLocal.layoutCore.move_container_to_top(identity) + } ) + + if (typeof ret === 'function') { + pluginLocal._dispose(ret) + } }) }) } @@ -346,8 +349,6 @@ function initApiProxyHandlers(pluginLocal: PluginLocal) { } } - const { _sync } = payload - if (pluginLocal.shadow) { if (payload.actor) { payload.actor.resolve(ret) @@ -355,6 +356,8 @@ function initApiProxyHandlers(pluginLocal: PluginLocal) { return } + const { _sync } = payload + if (_sync != null) { const reply = (result: any) => { pluginLocal.caller?.callUserModel(LSPMSG_SYNC, { @@ -430,7 +433,7 @@ class PluginLocal extends EventEmitter< async _setupUserSettings(reload?: boolean) { const { _options } = this - const logger = (this._logger = new PluginLogger('Loader')) + const logger = (this._logger = new PluginLogger(`Loader:${this.debugTag}`)) if (_options.settings && !reload) { return @@ -532,7 +535,7 @@ class PluginLocal extends EventEmitter< const localRoot = (this._localRoot = safetyPathNormalize(url)) const logseq: Partial = pkg.logseq || {} - // Pick legal attrs + // Pick legal attrs ;[ 'name', 'author', @@ -642,10 +645,10 @@ class PluginLocal extends EventEmitter< logseq plugin entry ${ - IS_DEV - ? `` - : `` - } + IS_DEV + ? `` + : `` + } @@ -866,7 +869,7 @@ class PluginLocal extends EventEmitter< this._dispose(cleanInjectedScripts.bind(this)) } catch (e) { - this.logger?.error('[Load Plugin]', e, true) + this.logger.error('load', e, true) this.dispose().catch(null) this._status = PluginLocalLoadStatus.ERROR @@ -924,7 +927,7 @@ class PluginLocal extends EventEmitter< ) this.emit('beforeunload', eventBeforeUnload) } catch (e) { - this.logger.error('[beforeunload]', e) + this.logger.error('beforeunload', e) } await this.dispose() @@ -932,7 +935,7 @@ class PluginLocal extends EventEmitter< this.emit('unloaded') } catch (e) { - this.logger.error('[unload Error]', e) + this.logger.error('unload', e) } finally { this._status = PluginLocalLoadStatus.UNLOADED } @@ -1038,7 +1041,7 @@ class PluginLocal extends EventEmitter< get debugTag() { const name = this._options?.name - return `#${this._id} ${name ?? ''}` + return `#${this._id} - ${name ?? ''}` } get localRoot(): string { @@ -1103,8 +1106,7 @@ class LSPluginCore | 'beforereload' | 'reloaded' > - implements ILSPluginThemeManager -{ + implements ILSPluginThemeManager { private _isRegistering = false private _readyIndicator?: DeferredActor private readonly _hostMountedActor: DeferredActor = deferred() @@ -1566,12 +1568,12 @@ class LSPluginCore await this.saveUserPreferences( theme.mode ? { - themes: { - ...this._userPreferences.themes, - mode: theme.mode, - [theme.mode]: theme, - }, - } + themes: { + ...this._userPreferences.themes, + mode: theme.mode, + [theme.mode]: theme, + }, + } : { theme: theme } ) } diff --git a/libs/src/LSPlugin.ts b/libs/src/LSPlugin.ts index d528d1a72..e17bd8e00 100644 --- a/libs/src/LSPlugin.ts +++ b/libs/src/LSPlugin.ts @@ -192,7 +192,7 @@ export interface BlockEntity { level?: number meta?: { timestamps: any; properties: any; startPos: number; endPos: number } title?: Array - marker?: string + marker?: string } /** @@ -235,9 +235,10 @@ export type BlockCursorPosition = { rect: DOMRect } +export type Keybinding = string | Array export type SimpleCommandKeybinding = { mode?: 'global' | 'non-editing' | 'editing' - binding: string + binding: Keybinding mac?: string // special for Mac OS } @@ -469,25 +470,6 @@ export interface IAppProxy { removeTemplate: (name: string) => Promise insertTemplate: (target: BlockUUID, name: string) => Promise - // ui - queryElementById: (id: string) => Promise - - /** - * @added 0.0.5 - * @param selector - */ - queryElementRect: (selector: string) => Promise - - /** - * @deprecated Use `logseq.UI.showMsg` instead - * @param content - * @param status - */ - showMsg: ( - content: string, - status?: 'success' | 'warning' | 'error' | string - ) => void - setZoomFactor: (factor: number) => void setFullScreen: (flag: boolean | 'toggle') => void setLeftSidebarVisible: (flag: boolean | 'toggle') => void @@ -891,20 +873,16 @@ export type UIMsgOptions = { export type UIMsgKey = UIMsgOptions['key'] export interface IUIProxy { - /** - * @added 0.0.2 - * - * @param content - * @param status - * @param opts - */ showMsg: ( content: string, status?: 'success' | 'warning' | 'error' | string, opts?: Partial ) => Promise - closeMsg: (key: UIMsgKey) => void + queryElementRect: (selector: string) => Promise + queryElementById: (id: string) => Promise + checkSlotValid: (slot: UISlotIdentity['slot']) => Promise + resolveThemeCssPropsVals: (props: string | Array) => Promise | null> } /** @@ -938,6 +916,13 @@ export interface IAssetsProxy { * @param path */ makeUrl(path: string): Promise + + /** + * try to open asset type file in Logseq app + * @added 0.0.16 + * @param path + */ + builtInOpen(path: string): Promise } export interface ILSPluginThemeManager { diff --git a/libs/src/LSPlugin.user.ts b/libs/src/LSPlugin.user.ts index 8e2bf196d..99922371a 100644 --- a/libs/src/LSPlugin.user.ts +++ b/libs/src/LSPlugin.user.ts @@ -4,7 +4,7 @@ import { mergeSettingsWithSchema, PluginLogger, safeSnakeCase, - safetyPathJoin, + safetyPathJoin, normalizeKeyStr, } from './helpers' import { LSPluginCaller } from './LSPlugin.caller' import * as callableAPIs from './callable.apis' @@ -77,12 +77,21 @@ function registerSimpleCommand ( }, action: SimpleCommandCallback ) { + const { key, label, desc, palette, keybinding, extras } = opts + if (typeof action !== 'function') { + this.logger.error(`${key || label}: command action should be function.`) return false } - const { key, label, desc, palette, keybinding, extras } = opts - const eventKey = `SimpleCommandHook${key}${++registeredCmdUid}` + const normalizedKey = normalizeKeyStr(key) + + if (!normalizedKey) { + this.logger.error(`${label}: command key is required.`) + return false + } + + const eventKey = `SimpleCommandHook${normalizedKey}${++registeredCmdUid}` this.Editor['on' + eventKey](action) @@ -92,7 +101,7 @@ function registerSimpleCommand ( this.baseInfo.id, // [cmd, action] [ - { key, label, type, desc, keybinding, extras }, + { key: normalizedKey, label, type, desc, keybinding, extras }, ['editor/hook', eventKey], ], palette, @@ -171,7 +180,7 @@ const app: Partial = { const { binding } = keybinding const group = '$shortcut$' - const key = group + safeSnakeCase(binding) + const key = opts.key || (group + safeSnakeCase(binding?.toString())) return registerSimpleCommand.call( this, diff --git a/libs/src/helpers.ts b/libs/src/helpers.ts index 7117b17ec..63397c1bf 100644 --- a/libs/src/helpers.ts +++ b/libs/src/helpers.ts @@ -2,7 +2,7 @@ import { SettingSchemaDesc, StyleString, UIOptions } from './LSPlugin' import { PluginLocal } from './LSPlugin.core' import * as nodePath from 'path' import DOMPurify from 'dompurify' -import merge from 'deepmerge'; +import merge from 'deepmerge' import { snakeCase } from 'snake-case' import * as callables from './callable.apis' import EventEmitter from 'eventemitter3' @@ -211,12 +211,23 @@ export function deferred(timeout?: number, tag?: string) { export function invokeHostExportedApi(method: string, ...args: Array) { method = method?.startsWith('_call') ? method : method?.replace(/^[_$]+/, '') - const method1 = safeSnakeCase(method) + let method1 = safeSnakeCase(method) + + // @ts-ignore + const nsSDK = window.logseq?.sdk + const supportedNS = nsSDK && Object.keys(nsSDK) + let nsTarget = {} + const ns0 = method1?.split('_')?.[0] + + if (ns0 && supportedNS.includes(ns0)) { + method1 = method1.replace(new RegExp(`^${ns0}_`), '') + nsTarget = nsSDK?.[ns0] + } const logseqHostExportedApi = Object.assign( // @ts-ignore - window.logseq?.api || {}, - callables + {}, window.logseq?.api, + nsTarget, callables ) const fn = @@ -266,9 +277,9 @@ export function setupInjectedStyle( el.textContent = style attrs && - Object.entries(attrs).forEach(([k, v]) => { - el.setAttribute(k, v) - }) + Object.entries(attrs).forEach(([k, v]) => { + el.setAttribute(k, v) + }) document.head.append(el) @@ -313,7 +324,7 @@ export function setupInjectedUI( console.error( `${this.debugTag} can not resolve selector target ${selector}` ) - return + return false } if (ui.template) { @@ -344,22 +355,22 @@ export function setupInjectedUI( // update attributes attrs && - Object.entries(attrs).forEach(([k, v]) => { - el.setAttribute(k, v) - }) + Object.entries(attrs).forEach(([k, v]) => { + el.setAttribute(k, v) + }) let positionDirty = el.dataset.dx != null ui.style && - Object.entries(ui.style).forEach(([k, v]) => { - if ( - positionDirty && - ['left', 'top', 'bottom', 'right', 'width', 'height'].includes(k) - ) { - return - } + Object.entries(ui.style).forEach(([k, v]) => { + if ( + positionDirty && + ['left', 'top', 'bottom', 'right', 'width', 'height'].includes(k) + ) { + return + } - el.style[k] = v - }) + el.style[k] = v + }) return } @@ -379,14 +390,14 @@ export function setupInjectedUI( content.innerHTML = ui.template attrs && - Object.entries(attrs).forEach(([k, v]) => { - el.setAttribute(k, v) - }) + Object.entries(attrs).forEach(([k, v]) => { + el.setAttribute(k, v) + }) ui.style && - Object.entries(ui.style).forEach(([k, v]) => { - el.style[k] = v - }) + Object.entries(ui.style).forEach(([k, v]) => { + el.style[k] = v + }) let teardownUI: () => void let disposeFloat: () => void @@ -399,11 +410,11 @@ export function setupInjectedUI( el.classList.add('lsp-ui-float-container', 'visible') disposeFloat = (pl._setupResizableContainer(el, key), - pl._setupDraggableContainer(el, { - key, - close: () => teardownUI(), - title: attrs?.title, - })) + pl._setupDraggableContainer(el, { + key, + close: () => teardownUI(), + title: attrs?.title, + })) } if (!!slot && ui.reset) { @@ -542,3 +553,8 @@ export function mergeSettingsWithSchema( // shadow copy return Object.assign(defaults, settings) } + +export function normalizeKeyStr(s: string) { + if (typeof s !== 'string') return + return s.trim().replace(/\s/g, '_').toLowerCase() +} diff --git a/resources/js/lsplugin.core.js b/resources/js/lsplugin.core.js index 7c455b12c..c252a986f 100644 --- a/resources/js/lsplugin.core.js +++ b/resources/js/lsplugin.core.js @@ -1,2 +1,2 @@ /*! For license information please see lsplugin.core.js.LICENSE.txt */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.LSPlugin=t():e.LSPlugin=t()}(self,(()=>(()=>{var e={227:(e,t,n)=>{var r=n(155);t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let r=0,o=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(r++,"%c"===e&&(o=r))})),t.splice(o,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(447)(t);const{formatters:o}=e.exports;o.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},447:(e,t,n)=>{e.exports=function(e){function t(e){let n,o,i,s=null;function a(...e){if(!a.enabled)return;const r=a,o=Number(new Date),i=o-(n||o);r.diff=i,r.prev=n,r.curr=o,n=o,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let s=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,o)=>{if("%%"===n)return"%";s++;const i=t.formatters[o];if("function"==typeof i){const t=e[s];n=i.call(r,t),e.splice(s,1),s--}return n})),t.formatArgs.call(r,e),(r.log||t.log).apply(r,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=r,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==s?s:(o!==t.namespaces&&(o=t.namespaces,i=t.enabled(e)),i),set:e=>{s=e}}),"function"==typeof t.init&&t.init(a),a}function r(e,n){const r=t(this.namespace+(void 0===n?":":n)+e);return r.log=this.log,r}function o(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(o),...t.skips.map(o).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),o=r.length;for(n=0;n{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?n-1:0),o=1;o/gm),W=d(/^data-[\-\w.\u00B7-\uFFFF]/),G=d(/^aria-[\-\w]+$/),J=d(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),V=d(/^(?:\w+script|data):/i),Z=d(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),K=d(/^html$/i),Y=function(){return"undefined"==typeof window?null:window},Q=function(t,n){if("object"!==e(t)||"function"!=typeof t.createPolicy)return null;var r=null,o="data-tt-policy-suffix";n.currentScript&&n.currentScript.hasAttribute(o)&&(r=n.currentScript.getAttribute(o));var i="dompurify"+(r?"#"+r:"");try{return t.createPolicy(i,{createHTML:function(e){return e}})}catch(e){return console.warn("TrustedTypes policy "+i+" could not be created."),null}};return function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Y(),r=function(e){return t(e)};if(r.version="2.3.8",r.removed=[],!n||!n.document||9!==n.document.nodeType)return r.isSupported=!1,r;var i=n.document,s=n.document,a=n.DocumentFragment,c=n.HTMLTemplateElement,l=n.Node,u=n.Element,d=n.NodeFilter,f=n.NamedNodeMap,p=void 0===f?n.NamedNodeMap||n.MozNamedAttrMap:f,g=n.HTMLFormElement,m=n.DOMParser,y=n.trustedTypes,k=u.prototype,X=I(k,"cloneNode"),ee=I(k,"nextSibling"),te=I(k,"childNodes"),ne=I(k,"parentNode");if("function"==typeof c){var re=s.createElement("template");re.content&&re.content.ownerDocument&&(s=re.content.ownerDocument)}var oe=Q(y,i),ie=oe?oe.createHTML(""):"",se=s,ae=se.implementation,ce=se.createNodeIterator,le=se.createDocumentFragment,ue=se.getElementsByTagName,he=i.importNode,de={};try{de=T(s).documentMode?s.documentMode:{}}catch(e){}var fe={};r.isSupported="function"==typeof ne&&ae&&void 0!==ae.createHTMLDocument&&9!==de;var pe,ge,me=q,ye=B,_e=W,be=G,ve=V,we=Z,xe=J,Ce=null,Se=j({},[].concat(o(L),o(M),o(P),o(R),o(D))),Oe=null,Ee=j({},[].concat(o(U),o($),o(z),o(H))),Ae=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),ke=null,je=null,Te=!0,Ie=!0,Le=!1,Me=!1,Pe=!1,Ne=!1,Re=!1,Fe=!1,De=!1,Ue=!1,$e=!0,ze=!0,He=!1,qe={},Be=null,We=j({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),Ge=null,Je=j({},["audio","video","img","source","image","track"]),Ve=null,Ze=j({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ke="http://www.w3.org/1998/Math/MathML",Ye="http://www.w3.org/2000/svg",Qe="http://www.w3.org/1999/xhtml",Xe=Qe,et=!1,tt=["application/xhtml+xml","text/html"],nt="text/html",rt=null,ot=s.createElement("form"),it=function(e){return e instanceof RegExp||e instanceof Function},st=function(t){rt&&rt===t||(t&&"object"===e(t)||(t={}),t=T(t),Ce="ALLOWED_TAGS"in t?j({},t.ALLOWED_TAGS):Se,Oe="ALLOWED_ATTR"in t?j({},t.ALLOWED_ATTR):Ee,Ve="ADD_URI_SAFE_ATTR"in t?j(T(Ze),t.ADD_URI_SAFE_ATTR):Ze,Ge="ADD_DATA_URI_TAGS"in t?j(T(Je),t.ADD_DATA_URI_TAGS):Je,Be="FORBID_CONTENTS"in t?j({},t.FORBID_CONTENTS):We,ke="FORBID_TAGS"in t?j({},t.FORBID_TAGS):{},je="FORBID_ATTR"in t?j({},t.FORBID_ATTR):{},qe="USE_PROFILES"in t&&t.USE_PROFILES,Te=!1!==t.ALLOW_ARIA_ATTR,Ie=!1!==t.ALLOW_DATA_ATTR,Le=t.ALLOW_UNKNOWN_PROTOCOLS||!1,Me=t.SAFE_FOR_TEMPLATES||!1,Pe=t.WHOLE_DOCUMENT||!1,Fe=t.RETURN_DOM||!1,De=t.RETURN_DOM_FRAGMENT||!1,Ue=t.RETURN_TRUSTED_TYPE||!1,Re=t.FORCE_BODY||!1,$e=!1!==t.SANITIZE_DOM,ze=!1!==t.KEEP_CONTENT,He=t.IN_PLACE||!1,xe=t.ALLOWED_URI_REGEXP||xe,Xe=t.NAMESPACE||Qe,t.CUSTOM_ELEMENT_HANDLING&&it(t.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Ae.tagNameCheck=t.CUSTOM_ELEMENT_HANDLING.tagNameCheck),t.CUSTOM_ELEMENT_HANDLING&&it(t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Ae.attributeNameCheck=t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),t.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Ae.allowCustomizedBuiltInElements=t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),pe=pe=-1===tt.indexOf(t.PARSER_MEDIA_TYPE)?nt:t.PARSER_MEDIA_TYPE,ge="application/xhtml+xml"===pe?function(e){return e}:w,Me&&(Ie=!1),De&&(Fe=!0),qe&&(Ce=j({},o(D)),Oe=[],!0===qe.html&&(j(Ce,L),j(Oe,U)),!0===qe.svg&&(j(Ce,M),j(Oe,$),j(Oe,H)),!0===qe.svgFilters&&(j(Ce,P),j(Oe,$),j(Oe,H)),!0===qe.mathMl&&(j(Ce,R),j(Oe,z),j(Oe,H))),t.ADD_TAGS&&(Ce===Se&&(Ce=T(Ce)),j(Ce,t.ADD_TAGS)),t.ADD_ATTR&&(Oe===Ee&&(Oe=T(Oe)),j(Oe,t.ADD_ATTR)),t.ADD_URI_SAFE_ATTR&&j(Ve,t.ADD_URI_SAFE_ATTR),t.FORBID_CONTENTS&&(Be===We&&(Be=T(Be)),j(Be,t.FORBID_CONTENTS)),ze&&(Ce["#text"]=!0),Pe&&j(Ce,["html","head","body"]),Ce.table&&(j(Ce,["tbody"]),delete ke.tbody),h&&h(t),rt=t)},at=j({},["mi","mo","mn","ms","mtext"]),ct=j({},["foreignobject","desc","title","annotation-xml"]),lt=j({},["title","style","font","a","script"]),ut=j({},M);j(ut,P),j(ut,N);var ht=j({},R);j(ht,F);var dt=function(e){var t=ne(e);t&&t.tagName||(t={namespaceURI:Qe,tagName:"template"});var n=w(e.tagName),r=w(t.tagName);return e.namespaceURI===Ye?t.namespaceURI===Qe?"svg"===n:t.namespaceURI===Ke?"svg"===n&&("annotation-xml"===r||at[r]):Boolean(ut[n]):e.namespaceURI===Ke?t.namespaceURI===Qe?"math"===n:t.namespaceURI===Ye?"math"===n&&ct[r]:Boolean(ht[n]):e.namespaceURI===Qe&&!(t.namespaceURI===Ye&&!ct[r])&&!(t.namespaceURI===Ke&&!at[r])&&!ht[n]&&(lt[n]||!ut[n])},ft=function(e){v(r.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){try{e.outerHTML=ie}catch(t){e.remove()}}},pt=function(e,t){try{v(r.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){v(r.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Oe[e])if(Fe||De)try{ft(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},gt=function(e){var t,n;if(Re)e=""+e;else{var r=x(e,/^[\r\n\t ]+/);n=r&&r[0]}"application/xhtml+xml"===pe&&(e=''+e+"");var o=oe?oe.createHTML(e):e;if(Xe===Qe)try{t=(new m).parseFromString(o,pe)}catch(e){}if(!t||!t.documentElement){t=ae.createDocument(Xe,"template",null);try{t.documentElement.innerHTML=et?"":o}catch(e){}}var i=t.body||t.documentElement;return e&&n&&i.insertBefore(s.createTextNode(n),i.childNodes[0]||null),Xe===Qe?ue.call(t,Pe?"html":"body")[0]:Pe?t.documentElement:i},mt=function(e){return ce.call(e.ownerDocument||e,e,d.SHOW_ELEMENT|d.SHOW_COMMENT|d.SHOW_TEXT,null,!1)},yt=function(e){return e instanceof g&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof p)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore)},_t=function(t){return"object"===e(l)?t instanceof l:t&&"object"===e(t)&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName},bt=function(e,t,n){fe[e]&&_(fe[e],(function(e){e.call(r,t,n,rt)}))},vt=function(e){var t;if(bt("beforeSanitizeElements",e,null),yt(e))return ft(e),!0;if(E(/[\u0080-\uFFFF]/,e.nodeName))return ft(e),!0;var n=ge(e.nodeName);if(bt("uponSanitizeElement",e,{tagName:n,allowedTags:Ce}),e.hasChildNodes()&&!_t(e.firstElementChild)&&(!_t(e.content)||!_t(e.content.firstElementChild))&&E(/<[/\w]/g,e.innerHTML)&&E(/<[/\w]/g,e.textContent))return ft(e),!0;if("select"===n&&E(/