/*
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
if you want to view the source visit the plugins github repository
*/
'use strict';
var obsidian = require('obsidian');
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
function wait(delay) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => window.setTimeout(resolve, delay));
});
}
function debounce(func, wait = 0, immediate = false) {
let timeout = null;
return function executedFunction(...args) {
const later = () => {
timeout = null;
if (!immediate) {
func.apply(this, args);
}
};
const callNow = immediate && timeout === null;
if (timeout !== null) {
window.clearTimeout(timeout);
}
timeout = window.setTimeout(later, wait);
if (callNow) {
func.apply(this, args);
}
};
}
function normalizeSvgFillStyle(input) {
const color = (input !== null && input !== void 0 ? input : "").trim();
const hex = color.startsWith("#") ? color.slice(1) : color;
if (/^[0-9a-fA-F]{8}$/.test(hex)) {
const rgb = hex.slice(0, 6);
const alpha = Number.parseInt(hex.slice(6, 8), 16) / 255;
return `fill:#${rgb} !important;fill-opacity:${alpha.toFixed(3)} !important;`;
}
if (/^[0-9a-fA-F]{6}$/.test(hex)) {
return `fill:#${hex} !important;fill-opacity:1 !important;`;
}
if (color.length > 0) {
return `fill:${color} !important;fill-opacity:1 !important;`;
}
return `fill:transparent !important;fill-opacity:1 !important;`;
}
function getColorSignature(input) {
const normalized = (input !== null && input !== void 0 ? input : "transparent").toLowerCase().replace(/[^a-z0-9]/g, "");
return normalized.length > 0 ? normalized : "transparent";
}
function getHighlighterPenIconId(highlighter, color) {
return `highlightr-pen-${highlighter}-${getColorSignature(color)}`.toLowerCase();
}
const icons = {
"highlightr-eraser": ``,
"highlightr-pen": ``,
"highlightr-add": ``,
"highlightr-save": ``,
"highlightr-delete": ``,
"highlightr-copy": ``,
};
function createHighlighterIcons(settings, plugin) {
const highlighterIcons = {};
const orderedHighlighters = plugin.settings.highlighterOrder.length > 0
? plugin.settings.highlighterOrder
: Object.keys(settings.highlighters);
for (const key of orderedHighlighters) {
const colorValue = settings.highlighters[key];
const fillStyle = normalizeSvgFillStyle(colorValue);
const highlighterPen = getHighlighterPenIconId(key, colorValue);
highlighterIcons[highlighterPen] = ``;
}
Object.keys(highlighterIcons).forEach((key) => {
obsidian.addIcon(key, highlighterIcons[key]);
});
return highlighterIcons;
}
function addIcons() {
Object.keys(icons).forEach((key) => {
obsidian.addIcon(key, icons[key]);
});
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var pickr_min = {exports: {}};
/*! Pickr 1.8.2 MIT | https://github.com/Simonwep/pickr */
var hasRequiredPickr_min;
function requirePickr_min () {
if (hasRequiredPickr_min) return pickr_min.exports;
hasRequiredPickr_min = 1;
(function (module, exports) {
!function(t,e){module.exports=e();}(self,(function(){return (()=>{var t={d:(e,o)=>{for(var n in o)t.o(o,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:true,get:o[n]});},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:true});}},e={};t.d(e,{default:()=>L});var o={};function n(t,e,o,n,i={}){e instanceof HTMLCollection||e instanceof NodeList?e=Array.from(e):Array.isArray(e)||(e=[e]),Array.isArray(o)||(o=[o]);for(const s of e)for(const e of o)s[t](e,n,{capture:false,...i});return Array.prototype.slice.call(arguments,1)}t.r(o),t.d(o,{adjustableInputNumbers:()=>p,createElementFromString:()=>r,createFromTemplate:()=>a,eventPath:()=>l,off:()=>s,on:()=>i,resolveElement:()=>c});const i=n.bind(null,"addEventListener"),s=n.bind(null,"removeEventListener");function r(t){const e=document.createElement("div");return e.innerHTML=t.trim(),e.firstElementChild}function a(t){const e=(t,e)=>{const o=t.getAttribute(e);return t.removeAttribute(e),o},o=(t,n={})=>{const i=e(t,":obj"),s=e(t,":ref"),r=i?n[i]={}:n;s&&(n[s]=t);for(const n of Array.from(t.children)){const t=e(n,":arr"),i=o(n,t?{}:r);t&&(r[t]||(r[t]=[])).push(Object.keys(i).length?i:n);}return n};return o(r(t))}function l(t){let e=t.path||t.composedPath&&t.composedPath();if(e)return e;let o=t.target.parentElement;for(e=[t.target,o];o=o.parentElement;)e.push(o);return e.push(document,window),e}function c(t){return t instanceof Element?t:"string"==typeof t?t.split(/>>/g).reduce(((t,e,o,n)=>(t=t.querySelector(e),ot)){function o(o){const n=[.001,.01,.1][Number(o.shiftKey||2*o.ctrlKey)]*(o.deltaY<0?1:-1);let i=0,s=t.selectionStart;t.value=t.value.replace(/[\d.]+/g,((t,o)=>o<=s&&o+t.length>=s?(s=o,e(Number(t),n,i)):(i++,t))),t.focus(),t.setSelectionRange(s,s),o.preventDefault(),t.dispatchEvent(new Event("input"));}i(t,"focus",(()=>i(window,"wheel",o,{passive:false}))),i(t,"blur",(()=>s(window,"wheel",o)));}const{min:u,max:h,floor:d,round:m}=Math;function f(t,e,o){e/=100,o/=100;const n=d(t=t/360*6),i=t-n,s=o*(1-e),r=o*(1-i*e),a=o*(1-(1-i)*e),l=n%6;return [255*[o,r,s,s,a,o][l],255*[a,o,o,r,s,s][l],255*[s,s,a,o,o,r][l]]}function v(t,e,o){const n=(2-(e/=100))*(o/=100)/2;return 0!==n&&(e=1===n?0:n<.5?e*o/(2*n):e*o/(2-2*n)),[t,100*e,100*n]}function b(t,e,o){const n=u(t/=255,e/=255,o/=255),i=h(t,e,o),s=i-n;let r,a;if(0===s)r=a=0;else {a=s/i;const n=((i-t)/6+s/2)/s,l=((i-e)/6+s/2)/s,c=((i-o)/6+s/2)/s;t===i?r=c-l:e===i?r=1/3+n-c:o===i&&(r=2/3+l-n),r<0?r+=1:r>1&&(r-=1);}return [360*r,100*a,100*i]}function y(t,e,o,n){e/=100,o/=100;return [...b(255*(1-u(1,(t/=100)*(1-(n/=100))+n)),255*(1-u(1,e*(1-n)+n)),255*(1-u(1,o*(1-n)+n)))]}function g(t,e,o){e/=100;const n=2*(e*=(o/=100)<.5?o:1-o)/(o+e)*100,i=100*(o+e);return [t,isNaN(n)?0:n,i]}function _(t){return b(...t.match(/.{2}/g).map((t=>parseInt(t,16))))}function w(t){t=t.match(/^[a-zA-Z]+$/)?function(t){if("black"===t.toLowerCase())return "#000";const e=document.createElement("canvas").getContext("2d");return e.fillStyle=t,"#000"===e.fillStyle?null:e.fillStyle}(t):t;const e={cmyk:/^cmyk[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)/i,rgba:/^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i,hsla:/^((hsla)|hsl)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i,hsva:/^((hsva)|hsv)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i,hexa:/^#?(([\dA-Fa-f]{3,4})|([\dA-Fa-f]{6})|([\dA-Fa-f]{8}))$/i},o=t=>t.map((t=>/^(|\d+)\.\d+|\d+$/.test(t)?Number(t):void 0));let n;t:for(const i in e){if(!(n=e[i].exec(t)))continue;const s=t=>!!n[2]==("number"==typeof t);switch(i){case "cmyk":{const[,t,e,s,r]=o(n);if(t>100||e>100||s>100||r>100)break t;return {values:y(t,e,s,r),type:i}}case "rgba":{const[,,,t,e,r,a]=o(n);if(t>255||e>255||r>255||a<0||a>1||!s(a))break t;return {values:[...b(t,e,r),a],a,type:i}}case "hexa":{let[,t]=n;4!==t.length&&3!==t.length||(t=t.split("").map((t=>t+t)).join(""));const e=t.substring(0,6);let o=t.substring(6);return o=o?parseInt(o,16)/255:void 0,{values:[..._(e),o],a:o,type:i}}case "hsla":{const[,,,t,e,r,a]=o(n);if(t>360||e>100||r>100||a<0||a>1||!s(a))break t;return {values:[...g(t,e,r),a],a,type:i}}case "hsva":{const[,,,t,e,r,a]=o(n);if(t>360||e>100||r>100||a<0||a>1||!s(a))break t;return {values:[t,e,r,a],a,type:i}}}}return {values:null,type:null}}function A(t=0,e=0,o=0,n=1){const i=(t,e)=>(o=-1)=>e(~o?t.map((t=>Number(t.toFixed(o)))):t),s={h:t,s:e,v:o,a:n,toHSVA(){const t=[s.h,s.s,s.v,s.a];return t.toString=i(t,(t=>`hsva(${t[0]}, ${t[1]}%, ${t[2]}%, ${s.a})`)),t},toHSLA(){const t=[...v(s.h,s.s,s.v),s.a];return t.toString=i(t,(t=>`hsla(${t[0]}, ${t[1]}%, ${t[2]}%, ${s.a})`)),t},toRGBA(){const t=[...f(s.h,s.s,s.v),s.a];return t.toString=i(t,(t=>`rgba(${t[0]}, ${t[1]}, ${t[2]}, ${s.a})`)),t},toCMYK(){const t=function(t,e,o){const n=f(t,e,o),i=n[0]/255,s=n[1]/255,r=n[2]/255,a=u(1-i,1-s,1-r);return [100*(1===a?0:(1-i-a)/(1-a)),100*(1===a?0:(1-s-a)/(1-a)),100*(1===a?0:(1-r-a)/(1-a)),100*a]}(s.h,s.s,s.v);return t.toString=i(t,(t=>`cmyk(${t[0]}%, ${t[1]}%, ${t[2]}%, ${t[3]}%)`)),t},toHEXA(){const t=function(t,e,o){return f(t,e,o).map((t=>m(t).toString(16).padStart(2,"0")))}(s.h,s.s,s.v),e=s.a>=1?"":Number((255*s.a).toFixed(0)).toString(16).toUpperCase().padStart(2,"0");return e&&t.push(e),t.toString=()=>`#${t.join("").toUpperCase()}`,t},clone:()=>A(s.h,s.s,s.v,s.a)};return s}const C=t=>Math.max(Math.min(t,1),0);function $(t){const e={options:Object.assign({lock:null,onchange:()=>0,onstop:()=>0},t),_keyboard(t){const{options:o}=e,{type:n,key:i}=t;if(document.activeElement===o.wrapper){const{lock:o}=e.options,s="ArrowUp"===i,r="ArrowRight"===i,a="ArrowDown"===i,l="ArrowLeft"===i;if("keydown"===n&&(s||r||a||l)){let n=0,i=0;"v"===o?n=s||r?1:-1:"h"===o?n=s||r?-1:1:(i=s?-1:a?1:0,n=l?-1:r?1:0),e.update(C(e.cache.x+.01*n),C(e.cache.y+.01*i)),t.preventDefault();}else i.startsWith("Arrow")&&(e.options.onstop(),t.preventDefault());}},_tapstart(t){i(document,["mouseup","touchend","touchcancel"],e._tapstop),i(document,["mousemove","touchmove"],e._tapmove),t.cancelable&&t.preventDefault(),e._tapmove(t);},_tapmove(t){const{options:o,cache:n}=e,{lock:i,element:s,wrapper:r}=o,a=r.getBoundingClientRect();let l=0,c=0;if(t){const e=t&&t.touches&&t.touches[0];l=t?(e||t).clientX:0,c=t?(e||t).clientY:0,la.left+a.width&&(l=a.left+a.width),ca.top+a.height&&(c=a.top+a.height),l-=a.left,c-=a.top;}else n&&(l=n.x*a.width,c=n.y*a.height);"h"!==i&&(s.style.left=`calc(${l/a.width*100}% - ${s.offsetWidth/2}px)`),"v"!==i&&(s.style.top=`calc(${c/a.height*100}% - ${s.offsetHeight/2}px)`),e.cache={x:l/a.width,y:c/a.height};const p=C(l/a.width),u=C(c/a.height);switch(i){case "v":return o.onchange(p);case "h":return o.onchange(u);default:return o.onchange(p,u)}},_tapstop(){e.options.onstop(),s(document,["mouseup","touchend","touchcancel"],e._tapstop),s(document,["mousemove","touchmove"],e._tapmove);},trigger(){e._tapmove();},update(t=0,o=0){const{left:n,top:i,width:s,height:r}=e.options.wrapper.getBoundingClientRect();"h"===e.options.lock&&(o=t),e._tapmove({clientX:n+s*t,clientY:i+r*o});},destroy(){const{options:t,_tapstart:o,_keyboard:n}=e;s(document,["keydown","keyup"],n),s([t.wrapper,t.element],"mousedown",o),s([t.wrapper,t.element],"touchstart",o,{passive:false});}},{options:o,_tapstart:n,_keyboard:r}=e;return i([o.wrapper,o.element],"mousedown",n),i([o.wrapper,o.element],"touchstart",n,{passive:false}),i(document,["keydown","keyup"],r),e}function k(t={}){t=Object.assign({onchange:()=>0,className:"",elements:[]},t);const e=i(t.elements,"click",(e=>{t.elements.forEach((o=>o.classList[e.target===o?"add":"remove"](t.className))),t.onchange(e),e.stopPropagation();}));return {destroy:()=>s(...e)}}const S={variantFlipOrder:{start:"sme",middle:"mse",end:"ems"},positionFlipOrder:{top:"tbrl",right:"rltb",bottom:"btrl",left:"lrbt"},position:"bottom",margin:8},O=(t,e,o)=>{const{container:n,margin:i,position:s,variantFlipOrder:r,positionFlipOrder:a}={container:document.documentElement.getBoundingClientRect(),...S,...o},{left:l,top:c}=e.style;e.style.left="0",e.style.top="0";const p=t.getBoundingClientRect(),u=e.getBoundingClientRect(),h={t:p.top-u.height-i,b:p.bottom+i,r:p.right+i,l:p.left-u.width-i},d={vs:p.left,vm:p.left+p.width/2+-u.width/2,ve:p.left+p.width-u.width,hs:p.top,hm:p.bottom-p.height/2-u.height/2,he:p.bottom-u.height},[m,f="middle"]=s.split("-"),v=a[m],b=r[f],{top:y,left:g,bottom:_,right:w}=n;for(const t of v){const o="t"===t||"b"===t,n=h[t],[i,s]=o?["top","left"]:["left","top"],[r,a]=o?[u.height,u.width]:[u.width,u.height],[l,c]=o?[_,w]:[w,_],[p,m]=o?[y,g]:[g,y];if(!(n
l))for(const r of b){const l=d[(o?"v":"h")+r];if(!(lc))return e.style[s]=l-u[s]+"px",e.style[i]=n-u[i]+"px",t+r}}return e.style.left=l,e.style.top=c,null};function E(t,e,o){return e in t?Object.defineProperty(t,e,{value:o,enumerable:true,configurable:true,writable:true}):t[e]=o,t}class L{constructor(t){E(this,"_initializingActive",true),E(this,"_recalc",true),E(this,"_nanopop",null),E(this,"_root",null),E(this,"_color",A()),E(this,"_lastColor",A()),E(this,"_swatchColors",[]),E(this,"_setupAnimationFrame",null),E(this,"_eventListener",{init:[],save:[],hide:[],show:[],clear:[],change:[],changestop:[],cancel:[],swatchselect:[]}),this.options=t=Object.assign({...L.DEFAULT_OPTIONS},t);const{swatches:e,components:o,theme:n,sliders:i,lockOpacity:s,padding:r}=t;["nano","monolith"].includes(n)&&!i&&(t.sliders="h"),o.interaction||(o.interaction={});const{preview:a,opacity:l,hue:c,palette:p}=o;o.opacity=!s&&l,o.palette=p||a||l||c,this._preBuild(),this._buildComponents(),this._bindEvents(),this._finalBuild(),e&&e.length&&e.forEach((t=>this.addSwatch(t)));const{button:u,app:h}=this._root;this._nanopop=((t,e,o)=>{const n="object"!=typeof t||t instanceof HTMLElement?{reference:t,popper:e,...o}:t;return {update(t=n){const{reference:e,popper:o}=Object.assign(n,t);if(!o||!e)throw new Error("Popper- or reference-element missing.");return O(e,o,n)}}})(u,h,{margin:r}),u.setAttribute("role","button"),u.setAttribute("aria-label",this._t("btn:toggle"));const d=this;this._setupAnimationFrame=requestAnimationFrame((function e(){if(!h.offsetWidth)return requestAnimationFrame(e);d.setColor(t.default),d._rePositioningPicker(),t.defaultRepresentation&&(d._representation=t.defaultRepresentation,d.setColorRepresentation(d._representation)),t.showAlways&&d.show(),d._initializingActive=false,d._emit("init");}));}_preBuild(){const{options:t}=this;for(const e of ["el","container"])t[e]=c(t[e]);this._root=(t=>{const{components:e,useAsButton:o,inline:n,appClass:i,theme:s,lockOpacity:r}=t.options,l=t=>t?"":'style="display:none" hidden',c=e=>t._t(e),p=a(`\n
\n\n ${o?"":''}\n\n
\n
\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n\n
\n \n \n
\n
\n\n \n\n
\n \n\n \n \n \n \n \n\n \n \n \n
\n
\n
\n `),u=p.interaction;return u.options.find((t=>!t.hidden&&!t.classList.add("active"))),u.type=()=>u.options.find((t=>t.classList.contains("active"))),p})(this),t.useAsButton&&(this._root.button=t.el),t.container.appendChild(this._root.root);}_finalBuild(){const t=this.options,e=this._root;if(t.container.removeChild(e.root),t.inline){const o=t.el.parentElement;t.el.nextSibling?o.insertBefore(e.app,t.el.nextSibling):o.appendChild(e.app);}else t.container.appendChild(e.app);t.useAsButton?t.inline&&t.el.remove():t.el.parentNode.replaceChild(e.root,t.el),t.disabled&&this.disable(),t.comparison||(e.button.style.transition="none",t.useAsButton||(e.preview.lastColor.style.transition="none")),this.hide();}_buildComponents(){const t=this,e=this.options.components,o=(t.options.sliders||"v").repeat(2),[n,i]=o.match(/^[vh]+$/g)?o:[],s=()=>this._color||(this._color=this._lastColor.clone()),r={palette:$({element:t._root.palette.picker,wrapper:t._root.palette.palette,onstop:()=>t._emit("changestop","slider",t),onchange(o,n){if(!e.palette)return;const i=s(),{_root:r,options:a}=t,{lastColor:l,currentColor:c}=r.preview;t._recalc&&(i.s=100*o,i.v=100-100*n,i.v<0&&(i.v=0),t._updateOutput("slider"));const p=i.toRGBA().toString(0);this.element.style.background=p,this.wrapper.style.background=`\n linear-gradient(to top, rgba(0, 0, 0, ${i.a}), transparent),\n linear-gradient(to left, hsla(${i.h}, 100%, 50%, ${i.a}), rgba(255, 255, 255, ${i.a}))\n `,a.comparison?a.useAsButton||t._lastColor||l.style.setProperty("--pcr-color",p):(r.button.style.setProperty("--pcr-color",p),r.button.classList.remove("clear"));const u=i.toHEXA().toString();for(const{el:e,color:o}of t._swatchColors)e.classList[u===o.toHEXA().toString()?"add":"remove"]("pcr-active");c.style.setProperty("--pcr-color",p);}}),hue:$({lock:"v"===i?"h":"v",element:t._root.hue.picker,wrapper:t._root.hue.slider,onstop:()=>t._emit("changestop","slider",t),onchange(o){if(!e.hue||!e.palette)return;const n=s();t._recalc&&(n.h=360*o),this.element.style.backgroundColor=`hsl(${n.h}, 100%, 50%)`,r.palette.trigger();}}),opacity:$({lock:"v"===n?"h":"v",element:t._root.opacity.picker,wrapper:t._root.opacity.slider,onstop:()=>t._emit("changestop","slider",t),onchange(o){if(!e.opacity||!e.palette)return;const n=s();t._recalc&&(n.a=Math.round(100*o)/100),this.element.style.background=`rgba(0, 0, 0, ${n.a})`,r.palette.trigger();}}),selectable:k({elements:t._root.interaction.options,className:"active",onchange(e){t._representation=e.target.getAttribute("data-type").toUpperCase(),t._recalc&&t._updateOutput("swatch");}})};this._components=r;}_bindEvents(){const{_root:t,options:e}=this,o=[i(t.interaction.clear,"click",(()=>this._clearColor())),i([t.interaction.cancel,t.preview.lastColor],"click",(()=>{this.setHSVA(...(this._lastColor||this._color).toHSVA(),true),this._emit("cancel");})),i(t.interaction.save,"click",(()=>{!this.applyColor()&&!e.showAlways&&this.hide();})),i(t.interaction.result,["keyup","input"],(t=>{this.setColor(t.target.value,true)&&!this._initializingActive&&(this._emit("change",this._color,"input",this),this._emit("changestop","input",this)),t.stopImmediatePropagation();})),i(t.interaction.result,["focus","blur"],(t=>{this._recalc="blur"===t.type,this._recalc&&this._updateOutput(null);})),i([t.palette.palette,t.palette.picker,t.hue.slider,t.hue.picker,t.opacity.slider,t.opacity.picker],["mousedown","touchstart"],(()=>this._recalc=true),{passive:true})];if(!e.showAlways){const n=e.closeWithKey;o.push(i(t.button,"click",(()=>this.isOpen()?this.hide():this.show())),i(document,"keyup",(t=>this.isOpen()&&(t.key===n||t.code===n)&&this.hide())),i(document,["touchstart","mousedown"],(e=>{this.isOpen()&&!l(e).some((e=>e===t.app||e===t.button))&&this.hide();}),{capture:true}));}if(e.adjustableNumbers){const e={rgba:[255,255,255,1],hsva:[360,100,100,1],hsla:[360,100,100,1],cmyk:[100,100,100,100]};p(t.interaction.result,((t,o,n)=>{const i=e[this.getColorRepresentation().toLowerCase()];if(i){const e=i[n],s=t+(e>=100?1e3*o:o);return s<=0?0:Number((s{n.isOpen()&&(e.closeOnScroll&&n.hide(),null===t?(t=setTimeout((()=>t=null),100),requestAnimationFrame((function e(){n._rePositioningPicker(),null!==t&&requestAnimationFrame(e);}))):(clearTimeout(t),t=setTimeout((()=>t=null),100)));}),{capture:true}));}this._eventBindings=o;}_rePositioningPicker(){const{options:t}=this;if(!t.inline){if(!this._nanopop.update({container:document.body.getBoundingClientRect(),position:t.position})){const t=this._root.app,e=t.getBoundingClientRect();t.style.top=(window.innerHeight-e.height)/2+"px",t.style.left=(window.innerWidth-e.width)/2+"px";}}}_updateOutput(t){const{_root:e,_color:o,options:n}=this;if(e.interaction.type()){const t=`to${e.interaction.type().getAttribute("data-type")}`;e.interaction.result.value="function"==typeof o[t]?o[t]().toString(n.outputPrecision):"";}!this._initializingActive&&this._recalc&&this._emit("change",o,t,this);}_clearColor(t=false){const{_root:e,options:o}=this;o.useAsButton||e.button.style.setProperty("--pcr-color","rgba(0, 0, 0, 0.15)"),e.button.classList.add("clear"),o.showAlways||this.hide(),this._lastColor=null,this._initializingActive||t||(this._emit("save",null),this._emit("clear"));}_parseLocalColor(t){const{values:e,type:o,a:n}=w(t),{lockOpacity:i}=this.options,s=void 0!==n&&1!==n;return e&&3===e.length&&(e[3]=void 0),{values:!e||i&&s?null:e,type:o}}_t(t){return this.options.i18n[t]||L.I18N_DEFAULTS[t]}_emit(t,...e){this._eventListener[t].forEach((t=>t(...e,this)));}on(t,e){return this._eventListener[t].push(e),this}off(t,e){const o=this._eventListener[t]||[],n=o.indexOf(e);return ~n&&o.splice(n,1),this}addSwatch(t){const{values:e}=this._parseLocalColor(t);if(e){const{_swatchColors:t,_root:o}=this,n=A(...e),s=r(``);return o.swatches.appendChild(s),t.push({el:s,color:n}),this._eventBindings.push(i(s,"click",(()=>{this.setHSVA(...n.toHSVA(),true),this._emit("swatchselect",n),this._emit("change",n,"swatch",this);}))),true}return false}removeSwatch(t){const e=this._swatchColors[t];if(e){const{el:o}=e;return this._root.swatches.removeChild(o),this._swatchColors.splice(t,1),true}return false}applyColor(t=false){const{preview:e,button:o}=this._root,n=this._color.toRGBA().toString(0);return e.lastColor.style.setProperty("--pcr-color",n),this.options.useAsButton||o.style.setProperty("--pcr-color",n),o.classList.remove("clear"),this._lastColor=this._color.clone(),this._initializingActive||t||this._emit("save",this._color),this}destroy(){cancelAnimationFrame(this._setupAnimationFrame),this._eventBindings.forEach((t=>s(...t))),Object.keys(this._components).forEach((t=>this._components[t].destroy()));}destroyAndRemove(){this.destroy();const{root:t,app:e}=this._root;t.parentElement&&t.parentElement.removeChild(t),e.parentElement.removeChild(e),Object.keys(this).forEach((t=>this[t]=null));}hide(){return !!this.isOpen()&&(this._root.app.classList.remove("visible"),this._emit("hide"),true)}show(){return !this.options.disabled&&!this.isOpen()&&(this._root.app.classList.add("visible"),this._rePositioningPicker(),this._emit("show",this._color),this)}isOpen(){return this._root.app.classList.contains("visible")}setHSVA(t=360,e=0,o=0,n=1,i=false){const s=this._recalc;if(this._recalc=false,t<0||t>360||e<0||e>100||o<0||o>100||n<0||n>1)return false;this._color=A(t,e,o,n);const{hue:r,opacity:a,palette:l}=this._components;return r.update(t/360),a.update(n),l.update(e/100,1-o/100),i||this.applyColor(),s&&this._updateOutput(),this._recalc=s,true}setColor(t,e=false){if(null===t)return this._clearColor(e),true;const{values:o,type:n}=this._parseLocalColor(t);if(o){const t=n.toUpperCase(),{options:i}=this._root.interaction,s=i.find((e=>e.getAttribute("data-type")===t));if(s&&!s.hidden)for(const t of i)t.classList[t===s?"add":"remove"]("active");return !!this.setHSVA(...o,e)&&this.setColorRepresentation(t)}return false}setColorRepresentation(t){return t=t.toUpperCase(),!!this._root.interaction.options.find((e=>e.getAttribute("data-type").startsWith(t)&&!e.click()))}getColorRepresentation(){return this._representation}getColor(){return this._color}getSelectedColor(){return this._lastColor}getRoot(){return this._root}disable(){return this.hide(),this.options.disabled=true,this._root.button.classList.add("disabled"),this}enable(){return this.options.disabled=false,this._root.button.classList.remove("disabled"),this}}return E(L,"utils",o),E(L,"version","1.8.2"),E(L,"I18N_DEFAULTS",{"ui:dialog":"color picker dialog","btn:toggle":"toggle color picker dialog","btn:swatch":"color swatch","btn:last-color":"use previous color","btn:save":"Save","btn:cancel":"Cancel","btn:clear":"Clear","aria:btn:save":"save and close","aria:btn:cancel":"cancel and close","aria:btn:clear":"clear and close","aria:input":"color input field","aria:palette":"color selection area","aria:hue":"hue selection slider","aria:opacity":"selection slider"}),E(L,"DEFAULT_OPTIONS",{appClass:null,theme:"classic",useAsButton:false,padding:8,disabled:false,comparison:true,closeOnScroll:false,outputPrecision:0,lockOpacity:false,autoReposition:true,container:"body",components:{interaction:{}},i18n:{},swatches:null,inline:false,sliders:null,default:"#42445a",defaultRepresentation:null,position:"bottom-middle",adjustableNumbers:true,showAlways:false,closeWithKey:"Escape"}),E(L,"create",(t=>new L(t))),e=e.default})()}));
} (pickr_min));
return pickr_min.exports;
}
var pickr_minExports = requirePickr_min();
var Pickr = /*@__PURE__*/getDefaultExportFromCjs(pickr_minExports);
/**!
* Sortable 1.15.0
* @author RubaXa
* @author owenm
* @license MIT
*/
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) {
symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
}
keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
if (i % 2) {
ownKeys(Object(source), true).forEach(function (key) {
_defineProperty(target, key, source[key]);
});
} else if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
}
return target;
}
function _typeof(obj) {
"@babel/helpers - typeof";
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
var version = "1.15.0";
function userAgent(pattern) {
if (typeof window !== 'undefined' && window.navigator) {
return !! /*@__PURE__*/navigator.userAgent.match(pattern);
}
}
var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
var Edge = userAgent(/Edge/i);
var FireFox = userAgent(/firefox/i);
var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
var IOS = userAgent(/iP(ad|od|hone)/i);
var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
var captureMode = {
capture: false,
passive: false
};
function on(el, event, fn) {
el.addEventListener(event, fn, !IE11OrLess && captureMode);
}
function off(el, event, fn) {
el.removeEventListener(event, fn, !IE11OrLess && captureMode);
}
function matches(
/**HTMLElement*/
el,
/**String*/
selector) {
if (!selector) return;
selector[0] === '>' && (selector = selector.substring(1));
if (el) {
try {
if (el.matches) {
return el.matches(selector);
} else if (el.msMatchesSelector) {
return el.msMatchesSelector(selector);
} else if (el.webkitMatchesSelector) {
return el.webkitMatchesSelector(selector);
}
} catch (_) {
return false;
}
}
return false;
}
function getParentOrHost(el) {
return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
}
function closest(
/**HTMLElement*/
el,
/**String*/
selector,
/**HTMLElement*/
ctx, includeCTX) {
if (el) {
ctx = ctx || document;
do {
if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
return el;
}
if (el === ctx) break;
/* jshint boss:true */
} while (el = getParentOrHost(el));
}
return null;
}
var R_SPACE = /\s+/g;
function toggleClass(el, name, state) {
if (el && name) {
if (el.classList) {
el.classList[state ? 'add' : 'remove'](name);
} else {
var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
}
}
}
function css(el, prop, val) {
var style = el && el.style;
if (style) {
if (val === void 0) {
if (document.defaultView && document.defaultView.getComputedStyle) {
val = document.defaultView.getComputedStyle(el, '');
} else if (el.currentStyle) {
val = el.currentStyle;
}
return prop === void 0 ? val : val[prop];
} else {
if (!(prop in style) && prop.indexOf('webkit') === -1) {
prop = '-webkit-' + prop;
}
style[prop] = val + (typeof val === 'string' ? '' : 'px');
}
}
}
function matrix(el, selfOnly) {
var appliedTransforms = '';
if (typeof el === 'string') {
appliedTransforms = el;
} else {
do {
var transform = css(el, 'transform');
if (transform && transform !== 'none') {
appliedTransforms = transform + ' ' + appliedTransforms;
}
/* jshint boss:true */
} while (!selfOnly && (el = el.parentNode));
}
var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
/*jshint -W056 */
return matrixFn && new matrixFn(appliedTransforms);
}
function find(ctx, tagName, iterator) {
if (ctx) {
var list = ctx.getElementsByTagName(tagName),
i = 0,
n = list.length;
if (iterator) {
for (; i < n; i++) {
iterator(list[i], i);
}
}
return list;
}
return [];
}
function getWindowScrollingElement() {
var scrollingElement = document.scrollingElement;
if (scrollingElement) {
return scrollingElement;
} else {
return document.documentElement;
}
}
/**
* Returns the "bounding client rect" of given element
* @param {HTMLElement} el The element whose boundingClientRect is wanted
* @param {[Boolean]} relativeToContainingBlock Whether the rect should be relative to the containing block of (including) the container
* @param {[Boolean]} relativeToNonStaticParent Whether the rect should be relative to the relative parent of (including) the contaienr
* @param {[Boolean]} undoScale Whether the container's scale() should be undone
* @param {[HTMLElement]} container The parent the element will be placed in
* @return {Object} The boundingClientRect of el, with specified adjustments
*/
function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
if (!el.getBoundingClientRect && el !== window) return;
var elRect, top, left, bottom, right, height, width;
if (el !== window && el.parentNode && el !== getWindowScrollingElement()) {
elRect = el.getBoundingClientRect();
top = elRect.top;
left = elRect.left;
bottom = elRect.bottom;
right = elRect.right;
height = elRect.height;
width = elRect.width;
} else {
top = 0;
left = 0;
bottom = window.innerHeight;
right = window.innerWidth;
height = window.innerHeight;
width = window.innerWidth;
}
if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
// Adjust for translate()
container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
// Not needed on <= IE11
if (!IE11OrLess) {
do {
if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container
top -= containerRect.top + parseInt(css(container, 'border-top-width'));
left -= containerRect.left + parseInt(css(container, 'border-left-width'));
bottom = top + elRect.height;
right = left + elRect.width;
break;
}
/* jshint boss:true */
} while (container = container.parentNode);
}
}
if (undoScale && el !== window) {
// Adjust for scale()
var elMatrix = matrix(container || el),
scaleX = elMatrix && elMatrix.a,
scaleY = elMatrix && elMatrix.d;
if (elMatrix) {
top /= scaleY;
left /= scaleX;
width /= scaleX;
height /= scaleY;
bottom = top + height;
right = left + width;
}
}
return {
top: top,
left: left,
bottom: bottom,
right: right,
width: width,
height: height
};
}
/**
* Checks if a side of an element is scrolled past a side of its parents
* @param {HTMLElement} el The element who's side being scrolled out of view is in question
* @param {String} elSide Side of the element in question ('top', 'left', 'right', 'bottom')
* @param {String} parentSide Side of the parent in question ('top', 'left', 'right', 'bottom')
* @return {HTMLElement} The parent scroll element that the el's side is scrolled past, or null if there is no such element
*/
function isScrolledPast(el, elSide, parentSide) {
var parent = getParentAutoScrollElement(el, true),
elSideVal = getRect(el)[elSide];
/* jshint boss:true */
while (parent) {
var parentSideVal = getRect(parent)[parentSide],
visible = void 0;
{
visible = elSideVal >= parentSideVal;
}
if (!visible) return parent;
if (parent === getWindowScrollingElement()) break;
parent = getParentAutoScrollElement(parent, false);
}
return false;
}
/**
* Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
* and non-draggable elements
* @param {HTMLElement} el The parent element
* @param {Number} childNum The index of the child
* @param {Object} options Parent Sortable's options
* @return {HTMLElement} The child at index childNum, or null if not found
*/
function getChild(el, childNum, options, includeDragEl) {
var currentChild = 0,
i = 0,
children = el.children;
while (i < children.length) {
if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && (includeDragEl || children[i] !== Sortable.dragged) && closest(children[i], options.draggable, el, false)) {
if (currentChild === childNum) {
return children[i];
}
currentChild++;
}
i++;
}
return null;
}
/**
* Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
* @param {HTMLElement} el Parent element
* @param {selector} selector Any other elements that should be ignored
* @return {HTMLElement} The last child, ignoring ghostEl
*/
function lastChild(el, selector) {
var last = el.lastElementChild;
while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
last = last.previousElementSibling;
}
return last || null;
}
/**
* Returns the index of an element within its parent for a selected set of
* elements
* @param {HTMLElement} el
* @param {selector} selector
* @return {number}
*/
function index(el, selector) {
var index = 0;
if (!el || !el.parentNode) {
return -1;
}
/* jshint boss:true */
while (el = el.previousElementSibling) {
if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
index++;
}
}
return index;
}
/**
* Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
* The value is returned in real pixels.
* @param {HTMLElement} el
* @return {Array} Offsets in the format of [left, top]
*/
function getRelativeScrollOffset(el) {
var offsetLeft = 0,
offsetTop = 0,
winScroller = getWindowScrollingElement();
if (el) {
do {
var elMatrix = matrix(el),
scaleX = elMatrix.a,
scaleY = elMatrix.d;
offsetLeft += el.scrollLeft * scaleX;
offsetTop += el.scrollTop * scaleY;
} while (el !== winScroller && (el = el.parentNode));
}
return [offsetLeft, offsetTop];
}
/**
* Returns the index of the object within the given array
* @param {Array} arr Array that may or may not hold the object
* @param {Object} obj An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
* @return {Number} The index of the object in the array, or -1
*/
function indexOfObject(arr, obj) {
for (var i in arr) {
if (!arr.hasOwnProperty(i)) continue;
for (var key in obj) {
if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
}
}
return -1;
}
function getParentAutoScrollElement(el, includeSelf) {
// skip to window
if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
var elem = el;
var gotSelf = false;
do {
// we don't need to get elem css if it isn't even overflowing in the first place (performance)
if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
var elemCSS = css(elem);
if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
if (gotSelf || includeSelf) return elem;
gotSelf = true;
}
}
/* jshint boss:true */
} while (elem = elem.parentNode);
return getWindowScrollingElement();
}
function extend(dst, src) {
if (dst && src) {
for (var key in src) {
if (src.hasOwnProperty(key)) {
dst[key] = src[key];
}
}
}
return dst;
}
function isRectEqual(rect1, rect2) {
return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
}
var _throttleTimeout;
function throttle(callback, ms) {
return function () {
if (!_throttleTimeout) {
var args = arguments,
_this = this;
if (args.length === 1) {
callback.call(_this, args[0]);
} else {
callback.apply(_this, args);
}
_throttleTimeout = setTimeout(function () {
_throttleTimeout = void 0;
}, ms);
}
};
}
function cancelThrottle() {
clearTimeout(_throttleTimeout);
_throttleTimeout = void 0;
}
function scrollBy(el, x, y) {
el.scrollLeft += x;
el.scrollTop += y;
}
function clone(el) {
var Polymer = window.Polymer;
var $ = window.jQuery || window.Zepto;
if (Polymer && Polymer.dom) {
return Polymer.dom(el).cloneNode(true);
} else if ($) {
return $(el).clone(true)[0];
} else {
return el.cloneNode(true);
}
}
var expando = 'Sortable' + new Date().getTime();
function AnimationStateManager() {
var animationStates = [],
animationCallbackId;
return {
captureAnimationState: function captureAnimationState() {
animationStates = [];
if (!this.options.animation) return;
var children = [].slice.call(this.el.children);
children.forEach(function (child) {
if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
animationStates.push({
target: child,
rect: getRect(child)
});
var fromRect = _objectSpread2({}, animationStates[animationStates.length - 1].rect); // If animating: compensate for current animation
if (child.thisAnimationDuration) {
var childMatrix = matrix(child, true);
if (childMatrix) {
fromRect.top -= childMatrix.f;
fromRect.left -= childMatrix.e;
}
}
child.fromRect = fromRect;
});
},
addAnimationState: function addAnimationState(state) {
animationStates.push(state);
},
removeAnimationState: function removeAnimationState(target) {
animationStates.splice(indexOfObject(animationStates, {
target: target
}), 1);
},
animateAll: function animateAll(callback) {
var _this = this;
if (!this.options.animation) {
clearTimeout(animationCallbackId);
if (typeof callback === 'function') callback();
return;
}
var animating = false,
animationTime = 0;
animationStates.forEach(function (state) {
var time = 0,
target = state.target,
fromRect = target.fromRect,
toRect = getRect(target),
prevFromRect = target.prevFromRect,
prevToRect = target.prevToRect,
animatingRect = state.rect,
targetMatrix = matrix(target, true);
if (targetMatrix) {
// Compensate for current animation
toRect.top -= targetMatrix.f;
toRect.left -= targetMatrix.e;
}
target.toRect = toRect;
if (target.thisAnimationDuration) {
// Could also check if animatingRect is between fromRect and toRect
if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect
(animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
// If returning to same place as started from animation and on same axis
time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
}
} // if fromRect != toRect: animate
if (!isRectEqual(toRect, fromRect)) {
target.prevFromRect = fromRect;
target.prevToRect = toRect;
if (!time) {
time = _this.options.animation;
}
_this.animate(target, animatingRect, toRect, time);
}
if (time) {
animating = true;
animationTime = Math.max(animationTime, time);
clearTimeout(target.animationResetTimer);
target.animationResetTimer = setTimeout(function () {
target.animationTime = 0;
target.prevFromRect = null;
target.fromRect = null;
target.prevToRect = null;
target.thisAnimationDuration = null;
}, time);
target.thisAnimationDuration = time;
}
});
clearTimeout(animationCallbackId);
if (!animating) {
if (typeof callback === 'function') callback();
} else {
animationCallbackId = setTimeout(function () {
if (typeof callback === 'function') callback();
}, animationTime);
}
animationStates = [];
},
animate: function animate(target, currentRect, toRect, duration) {
if (duration) {
css(target, 'transition', '');
css(target, 'transform', '');
var elMatrix = matrix(this.el),
scaleX = elMatrix && elMatrix.a,
scaleY = elMatrix && elMatrix.d,
translateX = (currentRect.left - toRect.left) / (scaleX || 1),
translateY = (currentRect.top - toRect.top) / (scaleY || 1);
target.animatingX = !!translateX;
target.animatingY = !!translateY;
css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
this.forRepaintDummy = repaint(target); // repaint
css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
css(target, 'transform', 'translate3d(0,0,0)');
typeof target.animated === 'number' && clearTimeout(target.animated);
target.animated = setTimeout(function () {
css(target, 'transition', '');
css(target, 'transform', '');
target.animated = false;
target.animatingX = false;
target.animatingY = false;
}, duration);
}
}
};
}
function repaint(target) {
return target.offsetWidth;
}
function calculateRealTime(animatingRect, fromRect, toRect, options) {
return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
}
var plugins = [];
var defaults = {
initializeByDefault: true
};
var PluginManager = {
mount: function mount(plugin) {
// Set default static properties
for (var option in defaults) {
if (defaults.hasOwnProperty(option) && !(option in plugin)) {
plugin[option] = defaults[option];
}
}
plugins.forEach(function (p) {
if (p.pluginName === plugin.pluginName) {
throw "Sortable: Cannot mount plugin ".concat(plugin.pluginName, " more than once");
}
});
plugins.push(plugin);
},
pluginEvent: function pluginEvent(eventName, sortable, evt) {
var _this = this;
this.eventCanceled = false;
evt.cancel = function () {
_this.eventCanceled = true;
};
var eventNameGlobal = eventName + 'Global';
plugins.forEach(function (plugin) {
if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable
if (sortable[plugin.pluginName][eventNameGlobal]) {
sortable[plugin.pluginName][eventNameGlobal](_objectSpread2({
sortable: sortable
}, evt));
} // Only fire plugin event if plugin is enabled in this sortable,
// and plugin has event defined
if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
sortable[plugin.pluginName][eventName](_objectSpread2({
sortable: sortable
}, evt));
}
});
},
initializePlugins: function initializePlugins(sortable, el, defaults, options) {
plugins.forEach(function (plugin) {
var pluginName = plugin.pluginName;
if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
var initialized = new plugin(sortable, el, sortable.options);
initialized.sortable = sortable;
initialized.options = sortable.options;
sortable[pluginName] = initialized; // Add default options from plugin
_extends(defaults, initialized.defaults);
});
for (var option in sortable.options) {
if (!sortable.options.hasOwnProperty(option)) continue;
var modified = this.modifyOption(sortable, option, sortable.options[option]);
if (typeof modified !== 'undefined') {
sortable.options[option] = modified;
}
}
},
getEventProperties: function getEventProperties(name, sortable) {
var eventProperties = {};
plugins.forEach(function (plugin) {
if (typeof plugin.eventProperties !== 'function') return;
_extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
});
return eventProperties;
},
modifyOption: function modifyOption(sortable, name, value) {
var modifiedValue;
plugins.forEach(function (plugin) {
// Plugin must exist on the Sortable
if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
}
});
return modifiedValue;
}
};
function dispatchEvent$1(_ref) {
var sortable = _ref.sortable,
rootEl = _ref.rootEl,
name = _ref.name,
targetEl = _ref.targetEl,
cloneEl = _ref.cloneEl,
toEl = _ref.toEl,
fromEl = _ref.fromEl,
oldIndex = _ref.oldIndex,
newIndex = _ref.newIndex,
oldDraggableIndex = _ref.oldDraggableIndex,
newDraggableIndex = _ref.newDraggableIndex,
originalEvent = _ref.originalEvent,
putSortable = _ref.putSortable,
extraEventProperties = _ref.extraEventProperties;
sortable = sortable || rootEl && rootEl[expando];
if (!sortable) return;
var evt,
options = sortable.options,
onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature
if (window.CustomEvent && !IE11OrLess && !Edge) {
evt = new CustomEvent(name, {
bubbles: true,
cancelable: true
});
} else {
evt = document.createEvent('Event');
evt.initEvent(name, true, true);
}
evt.to = toEl || rootEl;
evt.from = fromEl || rootEl;
evt.item = targetEl || rootEl;
evt.clone = cloneEl;
evt.oldIndex = oldIndex;
evt.newIndex = newIndex;
evt.oldDraggableIndex = oldDraggableIndex;
evt.newDraggableIndex = newDraggableIndex;
evt.originalEvent = originalEvent;
evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
var allEventProperties = _objectSpread2(_objectSpread2({}, extraEventProperties), PluginManager.getEventProperties(name, sortable));
for (var option in allEventProperties) {
evt[option] = allEventProperties[option];
}
if (rootEl) {
rootEl.dispatchEvent(evt);
}
if (options[onName]) {
options[onName].call(sortable, evt);
}
}
var _excluded = ["evt"];
var pluginEvent = function pluginEvent(eventName, sortable) {
var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
originalEvent = _ref.evt,
data = _objectWithoutProperties(_ref, _excluded);
PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread2({
dragEl: dragEl,
parentEl: parentEl,
ghostEl: ghostEl,
rootEl: rootEl,
nextEl: nextEl,
lastDownEl: lastDownEl,
cloneEl: cloneEl,
cloneHidden: cloneHidden,
dragStarted: moved,
putSortable: putSortable,
activeSortable: Sortable.active,
originalEvent: originalEvent,
oldIndex: oldIndex,
oldDraggableIndex: oldDraggableIndex,
newIndex: newIndex,
newDraggableIndex: newDraggableIndex,
hideGhostForTarget: _hideGhostForTarget,
unhideGhostForTarget: _unhideGhostForTarget,
cloneNowHidden: function cloneNowHidden() {
cloneHidden = true;
},
cloneNowShown: function cloneNowShown() {
cloneHidden = false;
},
dispatchSortableEvent: function dispatchSortableEvent(name) {
_dispatchEvent({
sortable: sortable,
name: name,
originalEvent: originalEvent
});
}
}, data));
};
function _dispatchEvent(info) {
dispatchEvent$1(_objectSpread2({
putSortable: putSortable,
cloneEl: cloneEl,
targetEl: dragEl,
rootEl: rootEl,
oldIndex: oldIndex,
oldDraggableIndex: oldDraggableIndex,
newIndex: newIndex,
newDraggableIndex: newDraggableIndex
}, info));
}
var dragEl,
parentEl,
ghostEl,
rootEl,
nextEl,
lastDownEl,
cloneEl,
cloneHidden,
oldIndex,
newIndex,
oldDraggableIndex,
newDraggableIndex,
activeGroup,
putSortable,
awaitingDragStarted = false,
ignoreNextClick = false,
sortables = [],
tapEvt,
touchEvt,
lastDx,
lastDy,
tapDistanceLeft,
tapDistanceTop,
moved,
lastTarget,
lastDirection,
pastFirstInvertThresh = false,
isCircumstantialInvert = false,
targetMoveDistance,
// For positioning ghost absolutely
ghostRelativeParent,
ghostRelativeParentInitialScroll = [],
// (left, top)
_silent = false,
savedInputChecked = [];
/** @const */
var documentExists = typeof document !== 'undefined',
PositionGhostAbsolutely = IOS,
CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
// This will not pass for IE9, because IE9 DnD only works on anchors
supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
supportCssPointerEvents = function () {
if (!documentExists) return; // false when <= IE11
if (IE11OrLess) {
return false;
}
var el = document.createElement('x');
el.style.cssText = 'pointer-events:auto';
return el.style.pointerEvents === 'auto';
}(),
_detectDirection = function _detectDirection(el, options) {
var elCSS = css(el),
elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
child1 = getChild(el, 0, options),
child2 = getChild(el, 1, options),
firstChildCSS = child1 && css(child1),
secondChildCSS = child2 && css(child2),
firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
if (elCSS.display === 'flex') {
return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
}
if (elCSS.display === 'grid') {
return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
}
if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
}
return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
},
_dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
dragElOppLength = vertical ? dragRect.width : dragRect.height,
targetS1Opp = vertical ? targetRect.left : targetRect.top,
targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
targetOppLength = vertical ? targetRect.width : targetRect.height;
return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
},
/**
* Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
* @param {Number} x X position
* @param {Number} y Y position
* @return {HTMLElement} Element of the first found nearest Sortable
*/
_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
var ret;
sortables.some(function (sortable) {
var threshold = sortable[expando].options.emptyInsertThreshold;
if (!threshold || lastChild(sortable)) return;
var rect = getRect(sortable),
insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
if (insideHorizontally && insideVertically) {
return ret = sortable;
}
});
return ret;
},
_prepareGroup = function _prepareGroup(options) {
function toFn(value, pull) {
return function (to, from, dragEl, evt) {
var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
if (value == null && (pull || sameGroup)) {
// Default pull value
// Default pull and put value if same group
return true;
} else if (value == null || value === false) {
return false;
} else if (pull && value === 'clone') {
return value;
} else if (typeof value === 'function') {
return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
} else {
var otherGroup = (pull ? to : from).options.group.name;
return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
}
};
}
var group = {};
var originalGroup = options.group;
if (!originalGroup || _typeof(originalGroup) != 'object') {
originalGroup = {
name: originalGroup
};
}
group.name = originalGroup.name;
group.checkPull = toFn(originalGroup.pull, true);
group.checkPut = toFn(originalGroup.put);
group.revertClone = originalGroup.revertClone;
options.group = group;
},
_hideGhostForTarget = function _hideGhostForTarget() {
if (!supportCssPointerEvents && ghostEl) {
css(ghostEl, 'display', 'none');
}
},
_unhideGhostForTarget = function _unhideGhostForTarget() {
if (!supportCssPointerEvents && ghostEl) {
css(ghostEl, 'display', '');
}
}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position
if (documentExists && !ChromeForAndroid) {
document.addEventListener('click', function (evt) {
if (ignoreNextClick) {
evt.preventDefault();
evt.stopPropagation && evt.stopPropagation();
evt.stopImmediatePropagation && evt.stopImmediatePropagation();
ignoreNextClick = false;
return false;
}
}, true);
}
var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
if (dragEl) {
evt = evt.touches ? evt.touches[0] : evt;
var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
if (nearest) {
// Create imitation event
var event = {};
for (var i in evt) {
if (evt.hasOwnProperty(i)) {
event[i] = evt[i];
}
}
event.target = event.rootEl = nearest;
event.preventDefault = void 0;
event.stopPropagation = void 0;
nearest[expando]._onDragOver(event);
}
}
};
var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
if (dragEl) {
dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
}
};
/**
* @class Sortable
* @param {HTMLElement} el
* @param {Object} [options]
*/
function Sortable(el, options) {
if (!(el && el.nodeType && el.nodeType === 1)) {
throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
}
this.el = el; // root element
this.options = options = _extends({}, options); // Export instance
el[expando] = this;
var defaults = {
group: null,
sort: true,
disabled: false,
store: null,
handle: null,
draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
swapThreshold: 1,
// percentage; 0 <= x <= 1
invertSwap: false,
// invert always
invertedSwapThreshold: null,
// will be set to same as swapThreshold if default
removeCloneOnHide: true,
direction: function direction() {
return _detectDirection(el, this.options);
},
ghostClass: 'sortable-ghost',
chosenClass: 'sortable-chosen',
dragClass: 'sortable-drag',
ignore: 'a, img',
filter: null,
preventOnFilter: true,
animation: 0,
easing: null,
setData: function setData(dataTransfer, dragEl) {
dataTransfer.setData('Text', dragEl.textContent);
},
dropBubble: false,
dragoverBubble: false,
dataIdAttr: 'data-id',
delay: 0,
delayOnTouchOnly: false,
touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
forceFallback: false,
fallbackClass: 'sortable-fallback',
fallbackOnBody: false,
fallbackTolerance: 0,
fallbackOffset: {
x: 0,
y: 0
},
supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window && !Safari,
emptyInsertThreshold: 5
};
PluginManager.initializePlugins(this, el, defaults); // Set default options
for (var name in defaults) {
!(name in options) && (options[name] = defaults[name]);
}
_prepareGroup(options); // Bind all private methods
for (var fn in this) {
if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
this[fn] = this[fn].bind(this);
}
} // Setup drag mode
this.nativeDraggable = options.forceFallback ? false : supportDraggable;
if (this.nativeDraggable) {
// Touch start threshold cannot be greater than the native dragstart threshold
this.options.touchStartThreshold = 1;
} // Bind events
if (options.supportPointer) {
on(el, 'pointerdown', this._onTapStart);
} else {
on(el, 'mousedown', this._onTapStart);
on(el, 'touchstart', this._onTapStart);
}
if (this.nativeDraggable) {
on(el, 'dragover', this);
on(el, 'dragenter', this);
}
sortables.push(this.el); // Restore sorting
options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager
_extends(this, AnimationStateManager());
}
Sortable.prototype =
/** @lends Sortable.prototype */
{
constructor: Sortable,
_isOutsideThisEl: function _isOutsideThisEl(target) {
if (!this.el.contains(target) && target !== this.el) {
lastTarget = null;
}
},
_getDirection: function _getDirection(evt, target) {
return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
},
_onTapStart: function _onTapStart(
/** Event|TouchEvent */
evt) {
if (!evt.cancelable) return;
var _this = this,
el = this.el,
options = this.options,
preventOnFilter = options.preventOnFilter,
type = evt.type,
touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
target = (touch || evt).target,
originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
filter = options.filter;
_saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
if (dragEl) {
return;
}
if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
return; // only left button and enabled
} // cancel dnd if original target is content editable
if (originalTarget.isContentEditable) {
return;
} // Safari ignores further event handling after mousedown
if (!this.nativeDraggable && Safari && target && target.tagName.toUpperCase() === 'SELECT') {
return;
}
target = closest(target, options.draggable, el, false);
if (target && target.animated) {
return;
}
if (lastDownEl === target) {
// Ignoring duplicate `down`
return;
} // Get the index of the dragged element within its parent
oldIndex = index(target);
oldDraggableIndex = index(target, options.draggable); // Check filter
if (typeof filter === 'function') {
if (filter.call(this, evt, target, this)) {
_dispatchEvent({
sortable: _this,
rootEl: originalTarget,
name: 'filter',
targetEl: target,
toEl: el,
fromEl: el
});
pluginEvent('filter', _this, {
evt: evt
});
preventOnFilter && evt.cancelable && evt.preventDefault();
return; // cancel dnd
}
} else if (filter) {
filter = filter.split(',').some(function (criteria) {
criteria = closest(originalTarget, criteria.trim(), el, false);
if (criteria) {
_dispatchEvent({
sortable: _this,
rootEl: criteria,
name: 'filter',
targetEl: target,
fromEl: el,
toEl: el
});
pluginEvent('filter', _this, {
evt: evt
});
return true;
}
});
if (filter) {
preventOnFilter && evt.cancelable && evt.preventDefault();
return; // cancel dnd
}
}
if (options.handle && !closest(originalTarget, options.handle, el, false)) {
return;
} // Prepare `dragstart`
this._prepareDragStart(evt, touch, target);
},
_prepareDragStart: function _prepareDragStart(
/** Event */
evt,
/** Touch */
touch,
/** HTMLElement */
target) {
var _this = this,
el = _this.el,
options = _this.options,
ownerDocument = el.ownerDocument,
dragStartFn;
if (target && !dragEl && target.parentNode === el) {
var dragRect = getRect(target);
rootEl = el;
dragEl = target;
parentEl = dragEl.parentNode;
nextEl = dragEl.nextSibling;
lastDownEl = target;
activeGroup = options.group;
Sortable.dragged = dragEl;
tapEvt = {
target: dragEl,
clientX: (touch || evt).clientX,
clientY: (touch || evt).clientY
};
tapDistanceLeft = tapEvt.clientX - dragRect.left;
tapDistanceTop = tapEvt.clientY - dragRect.top;
this._lastX = (touch || evt).clientX;
this._lastY = (touch || evt).clientY;
dragEl.style['will-change'] = 'all';
dragStartFn = function dragStartFn() {
pluginEvent('delayEnded', _this, {
evt: evt
});
if (Sortable.eventCanceled) {
_this._onDrop();
return;
} // Delayed drag has been triggered
// we can re-enable the events: touchmove/mousemove
_this._disableDelayedDragEvents();
if (!FireFox && _this.nativeDraggable) {
dragEl.draggable = true;
} // Bind the events: dragstart/dragend
_this._triggerDragStart(evt, touch); // Drag start event
_dispatchEvent({
sortable: _this,
name: 'choose',
originalEvent: evt
}); // Chosen item
toggleClass(dragEl, options.chosenClass, true);
}; // Disable "draggable"
options.ignore.split(',').forEach(function (criteria) {
find(dragEl, criteria.trim(), _disableDraggable);
});
on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
on(ownerDocument, 'mouseup', _this._onDrop);
on(ownerDocument, 'touchend', _this._onDrop);
on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox)
if (FireFox && this.nativeDraggable) {
this.options.touchStartThreshold = 4;
dragEl.draggable = true;
}
pluginEvent('delayStart', this, {
evt: evt
}); // Delay is impossible for native DnD in Edge or IE
if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
if (Sortable.eventCanceled) {
this._onDrop();
return;
} // If the user moves the pointer or let go the click or touch
// before the delay has been reached:
// disable the delayed drag
on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
on(ownerDocument, 'touchend', _this._disableDelayedDrag);
on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
_this._dragStartTimer = setTimeout(dragStartFn, options.delay);
} else {
dragStartFn();
}
}
},
_delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler(
/** TouchEvent|PointerEvent **/
e) {
var touch = e.touches ? e.touches[0] : e;
if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
this._disableDelayedDrag();
}
},
_disableDelayedDrag: function _disableDelayedDrag() {
dragEl && _disableDraggable(dragEl);
clearTimeout(this._dragStartTimer);
this._disableDelayedDragEvents();
},
_disableDelayedDragEvents: function _disableDelayedDragEvents() {
var ownerDocument = this.el.ownerDocument;
off(ownerDocument, 'mouseup', this._disableDelayedDrag);
off(ownerDocument, 'touchend', this._disableDelayedDrag);
off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
},
_triggerDragStart: function _triggerDragStart(
/** Event */
evt,
/** Touch */
touch) {
touch = touch || evt.pointerType == 'touch' && evt;
if (!this.nativeDraggable || touch) {
if (this.options.supportPointer) {
on(document, 'pointermove', this._onTouchMove);
} else if (touch) {
on(document, 'touchmove', this._onTouchMove);
} else {
on(document, 'mousemove', this._onTouchMove);
}
} else {
on(dragEl, 'dragend', this);
on(rootEl, 'dragstart', this._onDragStart);
}
try {
if (document.selection) {
// Timeout neccessary for IE9
_nextTick(function () {
document.selection.empty();
});
} else {
window.getSelection().removeAllRanges();
}
} catch (err) {}
},
_dragStarted: function _dragStarted(fallback, evt) {
awaitingDragStarted = false;
if (rootEl && dragEl) {
pluginEvent('dragStarted', this, {
evt: evt
});
if (this.nativeDraggable) {
on(document, 'dragover', _checkOutsideTargetEl);
}
var options = this.options; // Apply effect
!fallback && toggleClass(dragEl, options.dragClass, false);
toggleClass(dragEl, options.ghostClass, true);
Sortable.active = this;
fallback && this._appendGhost(); // Drag start event
_dispatchEvent({
sortable: this,
name: 'start',
originalEvent: evt
});
} else {
this._nulling();
}
},
_emulateDragOver: function _emulateDragOver() {
if (touchEvt) {
this._lastX = touchEvt.clientX;
this._lastY = touchEvt.clientY;
_hideGhostForTarget();
var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
var parent = target;
while (target && target.shadowRoot) {
target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
if (target === parent) break;
parent = target;
}
dragEl.parentNode[expando]._isOutsideThisEl(target);
if (parent) {
do {
if (parent[expando]) {
var inserted = void 0;
inserted = parent[expando]._onDragOver({
clientX: touchEvt.clientX,
clientY: touchEvt.clientY,
target: target,
rootEl: parent
});
if (inserted && !this.options.dragoverBubble) {
break;
}
}
target = parent; // store last element
}
/* jshint boss:true */
while (parent = parent.parentNode);
}
_unhideGhostForTarget();
}
},
_onTouchMove: function _onTouchMove(
/**TouchEvent*/
evt) {
if (tapEvt) {
var options = this.options,
fallbackTolerance = options.fallbackTolerance,
fallbackOffset = options.fallbackOffset,
touch = evt.touches ? evt.touches[0] : evt,
ghostMatrix = ghostEl && matrix(ghostEl, true),
scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1); // only set the status to dragging, when we are actually dragging
if (!Sortable.active && !awaitingDragStarted) {
if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
return;
}
this._onDragStart(evt, true);
}
if (ghostEl) {
if (ghostMatrix) {
ghostMatrix.e += dx - (lastDx || 0);
ghostMatrix.f += dy - (lastDy || 0);
} else {
ghostMatrix = {
a: 1,
b: 0,
c: 0,
d: 1,
e: dx,
f: dy
};
}
var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
css(ghostEl, 'webkitTransform', cssMatrix);
css(ghostEl, 'mozTransform', cssMatrix);
css(ghostEl, 'msTransform', cssMatrix);
css(ghostEl, 'transform', cssMatrix);
lastDx = dx;
lastDy = dy;
touchEvt = touch;
}
evt.cancelable && evt.preventDefault();
}
},
_appendGhost: function _appendGhost() {
// Bug if using scale(): https://stackoverflow.com/questions/2637058
// Not being adjusted for
if (!ghostEl) {
var container = this.options.fallbackOnBody ? document.body : rootEl,
rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
options = this.options; // Position absolutely
if (PositionGhostAbsolutely) {
// Get relatively positioned parent
ghostRelativeParent = container;
while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
ghostRelativeParent = ghostRelativeParent.parentNode;
}
if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
rect.top += ghostRelativeParent.scrollTop;
rect.left += ghostRelativeParent.scrollLeft;
} else {
ghostRelativeParent = getWindowScrollingElement();
}
ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
}
ghostEl = dragEl.cloneNode(true);
toggleClass(ghostEl, options.ghostClass, false);
toggleClass(ghostEl, options.fallbackClass, true);
toggleClass(ghostEl, options.dragClass, true);
css(ghostEl, 'transition', '');
css(ghostEl, 'transform', '');
css(ghostEl, 'box-sizing', 'border-box');
css(ghostEl, 'margin', 0);
css(ghostEl, 'top', rect.top);
css(ghostEl, 'left', rect.left);
css(ghostEl, 'width', rect.width);
css(ghostEl, 'height', rect.height);
css(ghostEl, 'opacity', '0.8');
css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
css(ghostEl, 'zIndex', '100000');
css(ghostEl, 'pointerEvents', 'none');
Sortable.ghost = ghostEl;
container.appendChild(ghostEl); // Set transform-origin
css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
}
},
_onDragStart: function _onDragStart(
/**Event*/
evt,
/**boolean*/
fallback) {
var _this = this;
var dataTransfer = evt.dataTransfer;
var options = _this.options;
pluginEvent('dragStart', this, {
evt: evt
});
if (Sortable.eventCanceled) {
this._onDrop();
return;
}
pluginEvent('setupClone', this);
if (!Sortable.eventCanceled) {
cloneEl = clone(dragEl);
cloneEl.removeAttribute("id");
cloneEl.draggable = false;
cloneEl.style['will-change'] = '';
this._hideClone();
toggleClass(cloneEl, this.options.chosenClass, false);
Sortable.clone = cloneEl;
} // #1143: IFrame support workaround
_this.cloneId = _nextTick(function () {
pluginEvent('clone', _this);
if (Sortable.eventCanceled) return;
if (!_this.options.removeCloneOnHide) {
rootEl.insertBefore(cloneEl, dragEl);
}
_this._hideClone();
_dispatchEvent({
sortable: _this,
name: 'clone'
});
});
!fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events
if (fallback) {
ignoreNextClick = true;
_this._loopId = setInterval(_this._emulateDragOver, 50);
} else {
// Undo what was set in _prepareDragStart before drag started
off(document, 'mouseup', _this._onDrop);
off(document, 'touchend', _this._onDrop);
off(document, 'touchcancel', _this._onDrop);
if (dataTransfer) {
dataTransfer.effectAllowed = 'move';
options.setData && options.setData.call(_this, dataTransfer, dragEl);
}
on(document, 'drop', _this); // #1276 fix:
css(dragEl, 'transform', 'translateZ(0)');
}
awaitingDragStarted = true;
_this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
on(document, 'selectstart', _this);
moved = true;
if (Safari) {
css(document.body, 'user-select', 'none');
}
},
// Returns true - if no further action is needed (either inserted or another condition)
_onDragOver: function _onDragOver(
/**Event*/
evt) {
var el = this.el,
target = evt.target,
dragRect,
targetRect,
revert,
options = this.options,
group = options.group,
activeSortable = Sortable.active,
isOwner = activeGroup === group,
canSort = options.sort,
fromSortable = putSortable || activeSortable,
vertical,
_this = this,
completedFired = false;
if (_silent) return;
function dragOverEvent(name, extra) {
pluginEvent(name, _this, _objectSpread2({
evt: evt,
isOwner: isOwner,
axis: vertical ? 'vertical' : 'horizontal',
revert: revert,
dragRect: dragRect,
targetRect: targetRect,
canSort: canSort,
fromSortable: fromSortable,
target: target,
completed: completed,
onMove: function onMove(target, after) {
return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
},
changed: changed
}, extra));
} // Capture animation state
function capture() {
dragOverEvent('dragOverAnimationCapture');
_this.captureAnimationState();
if (_this !== fromSortable) {
fromSortable.captureAnimationState();
}
} // Return invocation when dragEl is inserted (or completed)
function completed(insertion) {
dragOverEvent('dragOverCompleted', {
insertion: insertion
});
if (insertion) {
// Clones must be hidden before folding animation to capture dragRectAbsolute properly
if (isOwner) {
activeSortable._hideClone();
} else {
activeSortable._showClone(_this);
}
if (_this !== fromSortable) {
// Set ghost class to new sortable's ghost class
toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
toggleClass(dragEl, options.ghostClass, true);
}
if (putSortable !== _this && _this !== Sortable.active) {
putSortable = _this;
} else if (_this === Sortable.active && putSortable) {
putSortable = null;
} // Animation
if (fromSortable === _this) {
_this._ignoreWhileAnimating = target;
}
_this.animateAll(function () {
dragOverEvent('dragOverAnimationComplete');
_this._ignoreWhileAnimating = null;
});
if (_this !== fromSortable) {
fromSortable.animateAll();
fromSortable._ignoreWhileAnimating = null;
}
} // Null lastTarget if it is not inside a previously swapped element
if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
lastTarget = null;
} // no bubbling and not fallback
if (!options.dragoverBubble && !evt.rootEl && target !== document) {
dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted
!insertion && nearestEmptyInsertDetectEvent(evt);
}
!options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
return completedFired = true;
} // Call when dragEl has been inserted
function changed() {
newIndex = index(dragEl);
newDraggableIndex = index(dragEl, options.draggable);
_dispatchEvent({
sortable: _this,
name: 'change',
toEl: el,
newIndex: newIndex,
newDraggableIndex: newDraggableIndex,
originalEvent: evt
});
}
if (evt.preventDefault !== void 0) {
evt.cancelable && evt.preventDefault();
}
target = closest(target, options.draggable, el, true);
dragOverEvent('dragOver');
if (Sortable.eventCanceled) return completedFired;
if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
return completed(false);
}
ignoreNextClick = false;
if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = parentEl !== rootEl) // Reverting item into the original list
: putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
vertical = this._getDirection(evt, target) === 'vertical';
dragRect = getRect(dragEl);
dragOverEvent('dragOverValid');
if (Sortable.eventCanceled) return completedFired;
if (revert) {
parentEl = rootEl; // actualization
capture();
this._hideClone();
dragOverEvent('revert');
if (!Sortable.eventCanceled) {
if (nextEl) {
rootEl.insertBefore(dragEl, nextEl);
} else {
rootEl.appendChild(dragEl);
}
}
return completed(true);
}
var elLastChild = lastChild(el, options.draggable);
if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
// Insert to end of list
// If already at end of list: Do not insert
if (elLastChild === dragEl) {
return completed(false);
} // if there is a last element, it is the target
if (elLastChild && el === evt.target) {
target = elLastChild;
}
if (target) {
targetRect = getRect(target);
}
if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
capture();
if (elLastChild && elLastChild.nextSibling) {
// the last draggable element is not the last node
el.insertBefore(dragEl, elLastChild.nextSibling);
} else {
el.appendChild(dragEl);
}
parentEl = el; // actualization
changed();
return completed(true);
}
} else if (elLastChild && _ghostIsFirst(evt, vertical, this)) {
// Insert to start of list
var firstChild = getChild(el, 0, options, true);
if (firstChild === dragEl) {
return completed(false);
}
target = firstChild;
targetRect = getRect(target);
if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, false) !== false) {
capture();
el.insertBefore(dragEl, firstChild);
parentEl = el; // actualization
changed();
return completed(true);
}
} else if (target.parentNode === el) {
targetRect = getRect(target);
var direction = 0,
targetBeforeFirstSwap,
differentLevel = dragEl.parentNode !== el,
differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
side1 = vertical ? 'top' : 'left',
scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
if (lastTarget !== target) {
targetBeforeFirstSwap = targetRect[side1];
pastFirstInvertThresh = false;
isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
}
direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
var sibling;
if (direction !== 0) {
// Check if target is beside dragEl in respective direction (ignoring hidden elements)
var dragIndex = index(dragEl);
do {
dragIndex -= direction;
sibling = parentEl.children[dragIndex];
} while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
} // If dragEl is already beside target: Do not insert
if (direction === 0 || sibling === target) {
return completed(false);
}
lastTarget = target;
lastDirection = direction;
var nextSibling = target.nextElementSibling,
after = false;
after = direction === 1;
var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
if (moveVector !== false) {
if (moveVector === 1 || moveVector === -1) {
after = moveVector === 1;
}
_silent = true;
setTimeout(_unsilent, 30);
capture();
if (after && !nextSibling) {
el.appendChild(dragEl);
} else {
target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
} // Undo chrome's scroll adjustment (has no effect on other browsers)
if (scrolledPastTop) {
scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
}
parentEl = dragEl.parentNode; // actualization
// must be done before animation
if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
}
changed();
return completed(true);
}
}
if (el.contains(dragEl)) {
return completed(false);
}
}
return false;
},
_ignoreWhileAnimating: null,
_offMoveEvents: function _offMoveEvents() {
off(document, 'mousemove', this._onTouchMove);
off(document, 'touchmove', this._onTouchMove);
off(document, 'pointermove', this._onTouchMove);
off(document, 'dragover', nearestEmptyInsertDetectEvent);
off(document, 'mousemove', nearestEmptyInsertDetectEvent);
off(document, 'touchmove', nearestEmptyInsertDetectEvent);
},
_offUpEvents: function _offUpEvents() {
var ownerDocument = this.el.ownerDocument;
off(ownerDocument, 'mouseup', this._onDrop);
off(ownerDocument, 'touchend', this._onDrop);
off(ownerDocument, 'pointerup', this._onDrop);
off(ownerDocument, 'touchcancel', this._onDrop);
off(document, 'selectstart', this);
},
_onDrop: function _onDrop(
/**Event*/
evt) {
var el = this.el,
options = this.options; // Get the index of the dragged element within its parent
newIndex = index(dragEl);
newDraggableIndex = index(dragEl, options.draggable);
pluginEvent('drop', this, {
evt: evt
});
parentEl = dragEl && dragEl.parentNode; // Get again after plugin event
newIndex = index(dragEl);
newDraggableIndex = index(dragEl, options.draggable);
if (Sortable.eventCanceled) {
this._nulling();
return;
}
awaitingDragStarted = false;
isCircumstantialInvert = false;
pastFirstInvertThresh = false;
clearInterval(this._loopId);
clearTimeout(this._dragStartTimer);
_cancelNextTick(this.cloneId);
_cancelNextTick(this._dragStartId); // Unbind events
if (this.nativeDraggable) {
off(document, 'drop', this);
off(el, 'dragstart', this._onDragStart);
}
this._offMoveEvents();
this._offUpEvents();
if (Safari) {
css(document.body, 'user-select', '');
}
css(dragEl, 'transform', '');
if (evt) {
if (moved) {
evt.cancelable && evt.preventDefault();
!options.dropBubble && evt.stopPropagation();
}
ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
// Remove clone(s)
cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
}
if (dragEl) {
if (this.nativeDraggable) {
off(dragEl, 'dragend', this);
}
_disableDraggable(dragEl);
dragEl.style['will-change'] = ''; // Remove classes
// ghostClass is added in dragStarted
if (moved && !awaitingDragStarted) {
toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
}
toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event
_dispatchEvent({
sortable: this,
name: 'unchoose',
toEl: parentEl,
newIndex: null,
newDraggableIndex: null,
originalEvent: evt
});
if (rootEl !== parentEl) {
if (newIndex >= 0) {
// Add event
_dispatchEvent({
rootEl: parentEl,
name: 'add',
toEl: parentEl,
fromEl: rootEl,
originalEvent: evt
}); // Remove event
_dispatchEvent({
sortable: this,
name: 'remove',
toEl: parentEl,
originalEvent: evt
}); // drag from one list and drop into another
_dispatchEvent({
rootEl: parentEl,
name: 'sort',
toEl: parentEl,
fromEl: rootEl,
originalEvent: evt
});
_dispatchEvent({
sortable: this,
name: 'sort',
toEl: parentEl,
originalEvent: evt
});
}
putSortable && putSortable.save();
} else {
if (newIndex !== oldIndex) {
if (newIndex >= 0) {
// drag & drop within the same list
_dispatchEvent({
sortable: this,
name: 'update',
toEl: parentEl,
originalEvent: evt
});
_dispatchEvent({
sortable: this,
name: 'sort',
toEl: parentEl,
originalEvent: evt
});
}
}
}
if (Sortable.active) {
/* jshint eqnull:true */
if (newIndex == null || newIndex === -1) {
newIndex = oldIndex;
newDraggableIndex = oldDraggableIndex;
}
_dispatchEvent({
sortable: this,
name: 'end',
toEl: parentEl,
originalEvent: evt
}); // Save sorting
this.save();
}
}
}
this._nulling();
},
_nulling: function _nulling() {
pluginEvent('nulling', this);
rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
savedInputChecked.forEach(function (el) {
el.checked = true;
});
savedInputChecked.length = lastDx = lastDy = 0;
},
handleEvent: function handleEvent(
/**Event*/
evt) {
switch (evt.type) {
case 'drop':
case 'dragend':
this._onDrop(evt);
break;
case 'dragenter':
case 'dragover':
if (dragEl) {
this._onDragOver(evt);
_globalDragOver(evt);
}
break;
case 'selectstart':
evt.preventDefault();
break;
}
},
/**
* Serializes the item into an array of string.
* @returns {String[]}
*/
toArray: function toArray() {
var order = [],
el,
children = this.el.children,
i = 0,
n = children.length,
options = this.options;
for (; i < n; i++) {
el = children[i];
if (closest(el, options.draggable, this.el, false)) {
order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
}
}
return order;
},
/**
* Sorts the elements according to the array.
* @param {String[]} order order of the items
*/
sort: function sort(order, useAnimation) {
var items = {},
rootEl = this.el;
this.toArray().forEach(function (id, i) {
var el = rootEl.children[i];
if (closest(el, this.options.draggable, rootEl, false)) {
items[id] = el;
}
}, this);
useAnimation && this.captureAnimationState();
order.forEach(function (id) {
if (items[id]) {
rootEl.removeChild(items[id]);
rootEl.appendChild(items[id]);
}
});
useAnimation && this.animateAll();
},
/**
* Save the current sorting
*/
save: function save() {
var store = this.options.store;
store && store.set && store.set(this);
},
/**
* For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
* @param {HTMLElement} el
* @param {String} [selector] default: `options.draggable`
* @returns {HTMLElement|null}
*/
closest: function closest$1(el, selector) {
return closest(el, selector || this.options.draggable, this.el, false);
},
/**
* Set/get option
* @param {string} name
* @param {*} [value]
* @returns {*}
*/
option: function option(name, value) {
var options = this.options;
if (value === void 0) {
return options[name];
} else {
var modifiedValue = PluginManager.modifyOption(this, name, value);
if (typeof modifiedValue !== 'undefined') {
options[name] = modifiedValue;
} else {
options[name] = value;
}
if (name === 'group') {
_prepareGroup(options);
}
}
},
/**
* Destroy
*/
destroy: function destroy() {
pluginEvent('destroy', this);
var el = this.el;
el[expando] = null;
off(el, 'mousedown', this._onTapStart);
off(el, 'touchstart', this._onTapStart);
off(el, 'pointerdown', this._onTapStart);
if (this.nativeDraggable) {
off(el, 'dragover', this);
off(el, 'dragenter', this);
} // Remove draggable attributes
Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
el.removeAttribute('draggable');
});
this._onDrop();
this._disableDelayedDragEvents();
sortables.splice(sortables.indexOf(this.el), 1);
this.el = el = null;
},
_hideClone: function _hideClone() {
if (!cloneHidden) {
pluginEvent('hideClone', this);
if (Sortable.eventCanceled) return;
css(cloneEl, 'display', 'none');
if (this.options.removeCloneOnHide && cloneEl.parentNode) {
cloneEl.parentNode.removeChild(cloneEl);
}
cloneHidden = true;
}
},
_showClone: function _showClone(putSortable) {
if (putSortable.lastPutMode !== 'clone') {
this._hideClone();
return;
}
if (cloneHidden) {
pluginEvent('showClone', this);
if (Sortable.eventCanceled) return; // show clone at dragEl or original position
if (dragEl.parentNode == rootEl && !this.options.group.revertClone) {
rootEl.insertBefore(cloneEl, dragEl);
} else if (nextEl) {
rootEl.insertBefore(cloneEl, nextEl);
} else {
rootEl.appendChild(cloneEl);
}
if (this.options.group.revertClone) {
this.animate(dragEl, cloneEl);
}
css(cloneEl, 'display', '');
cloneHidden = false;
}
}
};
function _globalDragOver(
/**Event*/
evt) {
if (evt.dataTransfer) {
evt.dataTransfer.dropEffect = 'move';
}
evt.cancelable && evt.preventDefault();
}
function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
var evt,
sortable = fromEl[expando],
onMoveFn = sortable.options.onMove,
retVal; // Support for new CustomEvent feature
if (window.CustomEvent && !IE11OrLess && !Edge) {
evt = new CustomEvent('move', {
bubbles: true,
cancelable: true
});
} else {
evt = document.createEvent('Event');
evt.initEvent('move', true, true);
}
evt.to = toEl;
evt.from = fromEl;
evt.dragged = dragEl;
evt.draggedRect = dragRect;
evt.related = targetEl || toEl;
evt.relatedRect = targetRect || getRect(toEl);
evt.willInsertAfter = willInsertAfter;
evt.originalEvent = originalEvent;
fromEl.dispatchEvent(evt);
if (onMoveFn) {
retVal = onMoveFn.call(sortable, evt, originalEvent);
}
return retVal;
}
function _disableDraggable(el) {
el.draggable = false;
}
function _unsilent() {
_silent = false;
}
function _ghostIsFirst(evt, vertical, sortable) {
var rect = getRect(getChild(sortable.el, 0, sortable.options, true));
var spacer = 10;
return vertical ? evt.clientX < rect.left - spacer || evt.clientY < rect.top && evt.clientX < rect.right : evt.clientY < rect.top - spacer || evt.clientY < rect.bottom && evt.clientX < rect.left;
}
function _ghostIsLast(evt, vertical, sortable) {
var rect = getRect(lastChild(sortable.el, sortable.options.draggable));
var spacer = 10;
return vertical ? evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left : evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer;
}
function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
targetLength = vertical ? targetRect.height : targetRect.width,
targetS1 = vertical ? targetRect.top : targetRect.left,
targetS2 = vertical ? targetRect.bottom : targetRect.right,
invert = false;
if (!invertSwap) {
// Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
// multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
// check if past first invert threshold on side opposite of lastDirection
if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
// past first invert threshold, do not restrict inverted threshold to dragEl shadow
pastFirstInvertThresh = true;
}
if (!pastFirstInvertThresh) {
// dragEl shadow (target move distance shadow)
if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
: mouseOnAxis > targetS2 - targetMoveDistance) {
return -lastDirection;
}
} else {
invert = true;
}
} else {
// Regular
if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
return _getInsertDirection(target);
}
}
}
invert = invert || invertSwap;
if (invert) {
// Invert of regular
if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
}
}
return 0;
}
/**
* Gets the direction dragEl must be swapped relative to target in order to make it
* seem that dragEl has been "inserted" into that element's position
* @param {HTMLElement} target The target whose position dragEl is being inserted at
* @return {Number} Direction dragEl must be swapped
*/
function _getInsertDirection(target) {
if (index(dragEl) < index(target)) {
return 1;
} else {
return -1;
}
}
/**
* Generate id
* @param {HTMLElement} el
* @returns {String}
* @private
*/
function _generateId(el) {
var str = el.tagName + el.className + el.src + el.href + el.textContent,
i = str.length,
sum = 0;
while (i--) {
sum += str.charCodeAt(i);
}
return sum.toString(36);
}
function _saveInputCheckedState(root) {
savedInputChecked.length = 0;
var inputs = root.getElementsByTagName('input');
var idx = inputs.length;
while (idx--) {
var el = inputs[idx];
el.checked && savedInputChecked.push(el);
}
}
function _nextTick(fn) {
return setTimeout(fn, 0);
}
function _cancelNextTick(id) {
return clearTimeout(id);
} // Fixed #973:
if (documentExists) {
on(document, 'touchmove', function (evt) {
if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
evt.preventDefault();
}
});
} // Export utils
Sortable.utils = {
on: on,
off: off,
css: css,
find: find,
is: function is(el, selector) {
return !!closest(el, selector, el, false);
},
extend: extend,
throttle: throttle,
closest: closest,
toggleClass: toggleClass,
clone: clone,
index: index,
nextTick: _nextTick,
cancelNextTick: _cancelNextTick,
detectDirection: _detectDirection,
getChild: getChild
};
/**
* Get the Sortable instance of an element
* @param {HTMLElement} element The element
* @return {Sortable|undefined} The instance of Sortable
*/
Sortable.get = function (element) {
return element[expando];
};
/**
* Mount a plugin to Sortable
* @param {...SortablePlugin|SortablePlugin[]} plugins Plugins being mounted
*/
Sortable.mount = function () {
for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
plugins[_key] = arguments[_key];
}
if (plugins[0].constructor === Array) plugins = plugins[0];
plugins.forEach(function (plugin) {
if (!plugin.prototype || !plugin.prototype.constructor) {
throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
}
if (plugin.utils) Sortable.utils = _objectSpread2(_objectSpread2({}, Sortable.utils), plugin.utils);
PluginManager.mount(plugin);
});
};
/**
* Create sortable instance
* @param {HTMLElement} el
* @param {Object} [options]
*/
Sortable.create = function (el, options) {
return new Sortable(el, options);
}; // Export
Sortable.version = version;
var autoScrolls = [],
scrollEl,
scrollRootEl,
scrolling = false,
lastAutoScrollX,
lastAutoScrollY,
touchEvt$1,
pointerElemChangedInterval;
function AutoScrollPlugin() {
function AutoScroll() {
this.defaults = {
scroll: true,
forceAutoScrollFallback: false,
scrollSensitivity: 30,
scrollSpeed: 10,
bubbleScroll: true
}; // Bind all private methods
for (var fn in this) {
if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
this[fn] = this[fn].bind(this);
}
}
}
AutoScroll.prototype = {
dragStarted: function dragStarted(_ref) {
var originalEvent = _ref.originalEvent;
if (this.sortable.nativeDraggable) {
on(document, 'dragover', this._handleAutoScroll);
} else {
if (this.options.supportPointer) {
on(document, 'pointermove', this._handleFallbackAutoScroll);
} else if (originalEvent.touches) {
on(document, 'touchmove', this._handleFallbackAutoScroll);
} else {
on(document, 'mousemove', this._handleFallbackAutoScroll);
}
}
},
dragOverCompleted: function dragOverCompleted(_ref2) {
var originalEvent = _ref2.originalEvent;
// For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
if (!this.options.dragOverBubble && !originalEvent.rootEl) {
this._handleAutoScroll(originalEvent);
}
},
drop: function drop() {
if (this.sortable.nativeDraggable) {
off(document, 'dragover', this._handleAutoScroll);
} else {
off(document, 'pointermove', this._handleFallbackAutoScroll);
off(document, 'touchmove', this._handleFallbackAutoScroll);
off(document, 'mousemove', this._handleFallbackAutoScroll);
}
clearPointerElemChangedInterval();
clearAutoScrolls();
cancelThrottle();
},
nulling: function nulling() {
touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
autoScrolls.length = 0;
},
_handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
this._handleAutoScroll(evt, true);
},
_handleAutoScroll: function _handleAutoScroll(evt, fallback) {
var _this = this;
var x = (evt.touches ? evt.touches[0] : evt).clientX,
y = (evt.touches ? evt.touches[0] : evt).clientY,
elem = document.elementFromPoint(x, y);
touchEvt$1 = evt; // IE does not seem to have native autoscroll,
// Edge's autoscroll seems too conditional,
// MACOS Safari does not have autoscroll,
// Firefox and Chrome are good
if (fallback || this.options.forceAutoScrollFallback || Edge || IE11OrLess || Safari) {
autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change
var ogElemScroller = getParentAutoScrollElement(elem, true);
if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour
pointerElemChangedInterval = setInterval(function () {
var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
if (newElem !== ogElemScroller) {
ogElemScroller = newElem;
clearAutoScrolls();
}
autoScroll(evt, _this.options, newElem, fallback);
}, 10);
lastAutoScrollX = x;
lastAutoScrollY = y;
}
} else {
// if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
clearAutoScrolls();
return;
}
autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
}
}
};
return _extends(AutoScroll, {
pluginName: 'scroll',
initializeByDefault: true
});
}
function clearAutoScrolls() {
autoScrolls.forEach(function (autoScroll) {
clearInterval(autoScroll.pid);
});
autoScrolls = [];
}
function clearPointerElemChangedInterval() {
clearInterval(pointerElemChangedInterval);
}
var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
// Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
if (!options.scroll) return;
var x = (evt.touches ? evt.touches[0] : evt).clientX,
y = (evt.touches ? evt.touches[0] : evt).clientY,
sens = options.scrollSensitivity,
speed = options.scrollSpeed,
winScroller = getWindowScrollingElement();
var scrollThisInstance = false,
scrollCustomFn; // New scroll root, set scrollEl
if (scrollRootEl !== rootEl) {
scrollRootEl = rootEl;
clearAutoScrolls();
scrollEl = options.scroll;
scrollCustomFn = options.scrollFn;
if (scrollEl === true) {
scrollEl = getParentAutoScrollElement(rootEl, true);
}
}
var layersOut = 0;
var currentParent = scrollEl;
do {
var el = currentParent,
rect = getRect(el),
top = rect.top,
bottom = rect.bottom,
left = rect.left,
right = rect.right,
width = rect.width,
height = rect.height,
canScrollX = void 0,
canScrollY = void 0,
scrollWidth = el.scrollWidth,
scrollHeight = el.scrollHeight,
elCSS = css(el),
scrollPosX = el.scrollLeft,
scrollPosY = el.scrollTop;
if (el === winScroller) {
canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
} else {
canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
}
var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
if (!autoScrolls[layersOut]) {
for (var i = 0; i <= layersOut; i++) {
if (!autoScrolls[i]) {
autoScrolls[i] = {};
}
}
}
if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
autoScrolls[layersOut].el = el;
autoScrolls[layersOut].vx = vx;
autoScrolls[layersOut].vy = vy;
clearInterval(autoScrolls[layersOut].pid);
if (vx != 0 || vy != 0) {
scrollThisInstance = true;
/* jshint loopfunc:true */
autoScrolls[layersOut].pid = setInterval(function () {
// emulate drag over during autoscroll (fallback), emulating native DnD behaviour
if (isFallback && this.layer === 0) {
Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
}
var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
if (typeof scrollCustomFn === 'function') {
if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
return;
}
}
scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
}.bind({
layer: layersOut
}), 24);
}
}
layersOut++;
} while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
}, 30);
var drop = function drop(_ref) {
var originalEvent = _ref.originalEvent,
putSortable = _ref.putSortable,
dragEl = _ref.dragEl,
activeSortable = _ref.activeSortable,
dispatchSortableEvent = _ref.dispatchSortableEvent,
hideGhostForTarget = _ref.hideGhostForTarget,
unhideGhostForTarget = _ref.unhideGhostForTarget;
if (!originalEvent) return;
var toSortable = putSortable || activeSortable;
hideGhostForTarget();
var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
var target = document.elementFromPoint(touch.clientX, touch.clientY);
unhideGhostForTarget();
if (toSortable && !toSortable.el.contains(target)) {
dispatchSortableEvent('spill');
this.onSpill({
dragEl: dragEl,
putSortable: putSortable
});
}
};
function Revert() {}
Revert.prototype = {
startIndex: null,
dragStart: function dragStart(_ref2) {
var oldDraggableIndex = _ref2.oldDraggableIndex;
this.startIndex = oldDraggableIndex;
},
onSpill: function onSpill(_ref3) {
var dragEl = _ref3.dragEl,
putSortable = _ref3.putSortable;
this.sortable.captureAnimationState();
if (putSortable) {
putSortable.captureAnimationState();
}
var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
if (nextSibling) {
this.sortable.el.insertBefore(dragEl, nextSibling);
} else {
this.sortable.el.appendChild(dragEl);
}
this.sortable.animateAll();
if (putSortable) {
putSortable.animateAll();
}
},
drop: drop
};
_extends(Revert, {
pluginName: 'revertOnSpill'
});
function Remove() {}
Remove.prototype = {
onSpill: function onSpill(_ref4) {
var dragEl = _ref4.dragEl,
putSortable = _ref4.putSortable;
var parentSortable = putSortable || this.sortable;
parentSortable.captureAnimationState();
dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
parentSortable.animateAll();
},
drop: drop
};
_extends(Remove, {
pluginName: 'removeOnSpill'
});
Sortable.mount(new AutoScrollPlugin());
Sortable.mount(Remove, Revert);
const HIGHLIGHTER_STYLES = [
"none",
"lowlight",
"floating",
"rounded",
"realistic",
];
const HIGHLIGHTER_METHODS = ["css-classes", "inline-styles"];
function createDefaultHighlighterClass(colorName) {
return colorName
.trim()
.toLowerCase()
.replace(/\s+/g, "-")
.replace(/[^a-z0-9-_]/g, "");
}
const DEFAULT_SETTINGS = {
highlighterStyle: "none",
focusHighlightsAndNotes: false,
highlighterMethods: "inline-styles",
highlighters: {
Pink: "#FFB8EBA6",
Red: "#FF5582A6",
Orange: "#FFB86CA6",
Yellow: "#FFF3A3A6",
Green: "#BBFABBA6",
Cyan: "#ABF7F7A6",
Blue: "#ADCCFFA6",
Purple: "#D2B3FFA6",
Grey: "#CACFD9A6",
},
highlighterClasses: {},
highlighterActivity: {},
highlighterOrder: [],
conflictScanScope: "active-file",
conflictScanFolder: "",
};
DEFAULT_SETTINGS.highlighterOrder = Object.keys(DEFAULT_SETTINGS.highlighters);
DEFAULT_SETTINGS.highlighterOrder.forEach((highlighter) => {
DEFAULT_SETTINGS.highlighterClasses[highlighter] = createDefaultHighlighterClass(highlighter);
DEFAULT_SETTINGS.highlighterActivity[highlighter] = true;
});
function setAttributes(element, attributes) {
for (const key of Object.keys(attributes)) {
element.setAttribute(key, attributes[key]);
}
}
class DeleteHighlighterModal extends obsidian.Modal {
constructor(app, onSubmit) {
super(app);
this.resolved = false;
this.onSubmit = onSubmit;
}
onOpen() {
const { contentEl } = this;
contentEl.empty();
contentEl.createEl("p", {
text: "This action will permanently remove the highlight color. In the future, using the same color name for a new highlight color may create a conflict.",
});
const controls = contentEl.createDiv();
new obsidian.Setting(controls)
.addButton((button) => {
button.setButtonText("Cancel").onClick(() => {
this.resolved = true;
this.onSubmit(false);
this.close();
});
})
.addButton((button) => {
button.setButtonText("OK").setCta().onClick(() => {
this.resolved = true;
this.onSubmit(true);
this.close();
});
});
}
onClose() {
this.contentEl.empty();
if (!this.resolved) {
this.onSubmit(false);
}
}
}
class HighlighterClassConflictModal extends obsidian.Modal {
constructor(app, summary, colorName, targetColorHex, onSubmit) {
super(app);
this.resolved = false;
this.summary = summary;
this.colorName = colorName;
this.targetColorHex = targetColorHex;
this.onSubmit = onSubmit;
}
onOpen() {
const { contentEl } = this;
contentEl.empty();
contentEl.createEl("h3", { text: "Potential highlight class conflict" });
contentEl.createEl("p", {
text: `A highlight class conflict was found for ${this.colorName}: ${this.summary.classToken}.`,
});
contentEl.createEl("p", {
text: `Found ${this.summary.totalMarks} matching mark(s) in ${this.summary.fileCount} file(s). New color value: ${this.targetColorHex}.`,
});
const colorsFound = Object.keys(this.summary.inlineColorCounts).map((color) => ({
color,
count: this.summary.inlineColorCounts[color],
}));
if (colorsFound.length > 0) {
const details = contentEl.createEl("ul");
colorsFound.forEach((entry) => {
details.createEl("li", { text: `${entry.color}: ${entry.count}` });
});
}
if (this.summary.topFiles.length > 0) {
contentEl.createEl("p", { text: "Top impacted files:" });
const fileDetails = contentEl.createEl("ul");
this.summary.topFiles.forEach((entry) => {
fileDetails.createEl("li", { text: `${entry.path} (${entry.marks})` });
});
}
contentEl.createEl("p", {
text: "Do you wish to overwrite highlight colors using the same name or choose a different highlight color name to keep both colors?",
});
const controls = contentEl.createDiv();
new obsidian.Setting(controls)
.addButton((button) => {
button.setButtonText("Choose different name").onClick(() => {
this.resolved = true;
this.onSubmit("rename");
this.close();
});
})
.addButton((button) => {
button.setButtonText("Reuse without migration").onClick(() => {
this.resolved = true;
this.onSubmit("reuse-without-migration");
this.close();
});
})
.addButton((button) => {
button.setButtonText("Reuse and migrate").setCta().onClick(() => {
this.resolved = true;
this.onSubmit("reuse-with-migration");
this.close();
});
});
}
onClose() {
this.contentEl.empty();
if (!this.resolved) {
this.onSubmit("rename");
}
}
}
class HighlightrSettingTab extends obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
getActiveHighlighters() {
const ordered = this.plugin.settings.highlighterOrder.length > 0
? this.plugin.settings.highlighterOrder
: Object.keys(this.plugin.settings.highlighters);
return ordered.filter((highlighter) => { var _a; return ((_a = this.plugin.settings.highlighterActivity) === null || _a === void 0 ? void 0 : _a[highlighter]) !== false; });
}
getInactiveHighlighters() {
const ordered = this.plugin.settings.highlighterOrder.length > 0
? this.plugin.settings.highlighterOrder
: Object.keys(this.plugin.settings.highlighters);
return ordered.filter((highlighter) => { var _a; return ((_a = this.plugin.settings.highlighterActivity) === null || _a === void 0 ? void 0 : _a[highlighter]) === false; });
}
confirmPermanentDeletion() {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => {
const modal = new DeleteHighlighterModal(this.app, (confirmed) => resolve(confirmed));
modal.open();
});
});
}
getClassTokens(markTag) {
const classMatch = markTag.match(/\bclass\s*=\s*(["'])(.*?)\1/i);
if (!classMatch || !classMatch[2]) {
return [];
}
return classMatch[2]
.split(/\s+/)
.map((token) => token.trim())
.filter((token) => token.length > 0);
}
getInlineHltrColor(markTag) {
var _a, _b;
const styleMatch = markTag.match(/\bstyle\s*=\s*(["'])(.*?)\1/i);
if (!styleMatch || !styleMatch[2]) {
return null;
}
const colorMatch = styleMatch[2].match(/--hltr-color\s*:\s*([^;]+)/i);
return (_b = (_a = colorMatch === null || colorMatch === void 0 ? void 0 : colorMatch[1]) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : null;
}
getConflictScanFiles() {
const scope = this.plugin.settings.conflictScanScope;
if (scope === "active-file") {
const activeFile = this.app.workspace.getActiveFile();
return activeFile ? [activeFile] : [];
}
const markdownFiles = this.app.vault.getMarkdownFiles();
if (scope === "folder") {
const folder = this.plugin.settings.conflictScanFolder.trim().replace(/^\/+|\/+$/g, "");
if (!folder) {
return [];
}
const prefix = `${folder}/`;
return markdownFiles.filter((file) => file.path === folder || file.path.startsWith(prefix));
}
return markdownFiles;
}
getConflictScanScopeLabel() {
const scope = this.plugin.settings.conflictScanScope;
if (scope === "active-file") {
return "active file";
}
if (scope === "folder") {
const folder = this.plugin.settings.conflictScanFolder.trim();
return folder ? `folder: ${folder}` : "folder";
}
return "entire vault";
}
scanClassConflictSummary(classToken) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const files = this.getConflictScanFiles();
let totalMarks = 0;
let fileCount = 0;
const inlineColorCounts = {};
const fileMatches = [];
for (const file of files) {
const content = yield this.app.vault.read(file);
const markTags = (_a = content.match(/]*>/gi)) !== null && _a !== void 0 ? _a : [];
let fileMatchCount = 0;
markTags.forEach((markTag) => {
var _a;
const classTokens = this.getClassTokens(markTag);
if (classTokens.indexOf(classToken) === -1) {
return;
}
fileMatchCount += 1;
totalMarks += 1;
const color = this.getInlineHltrColor(markTag);
if (!color) {
return;
}
inlineColorCounts[color] = ((_a = inlineColorCounts[color]) !== null && _a !== void 0 ? _a : 0) + 1;
});
if (fileMatchCount > 0) {
fileCount += 1;
fileMatches.push({ path: file.path, marks: fileMatchCount });
}
}
const topFiles = fileMatches
.sort((a, b) => b.marks - a.marks)
.slice(0, 5);
return {
classToken,
totalMarks,
fileCount,
inlineColorCounts,
topFiles,
};
});
}
confirmClassConflict(summary, colorName, targetColorHex) {
return __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve) => {
const modal = new HighlighterClassConflictModal(this.app, summary, colorName, targetColorHex, (action) => resolve(action));
modal.open();
});
});
}
setHighlighterActivity(highlighter, active) {
return __awaiter(this, void 0, void 0, function* () {
this.plugin.settings.highlighterActivity[highlighter] = active;
yield this.plugin.saveSettings();
window.setTimeout(() => {
dispatchEvent(new Event("Highlightr-NewCommand"));
}, 100);
});
}
getHighlighterHotkeyLabel(highlighter) {
var _a;
const commandId = `highlightr-plugin:${highlighter}`;
const appWithHotkeys = this.app;
const hotkeyManager = appWithHotkeys.hotkeyManager;
if (!hotkeyManager || typeof hotkeyManager.getHotkeys !== "function") {
return null;
}
const hotkeys = hotkeyManager.getHotkeys(commandId);
if (!hotkeys || hotkeys.length === 0) {
return null;
}
const firstHotkey = hotkeys[0];
if (typeof hotkeyManager.printHotkey === "function") {
return hotkeyManager.printHotkey(firstHotkey);
}
const modifiers = Array.isArray(firstHotkey.modifiers) ? firstHotkey.modifiers : [];
const key = (_a = firstHotkey.key) !== null && _a !== void 0 ? _a : "";
const parts = [...modifiers, key].filter(Boolean);
return parts.length ? parts.join("+") : null;
}
removeHighlighterCommand(highlighter) {
var _a, _b;
const appWithCommands = this.app;
(_b = (_a = appWithCommands.commands) === null || _a === void 0 ? void 0 : _a.removeCommand) === null || _b === void 0 ? void 0 : _b.call(_a, `highlightr-plugin:${highlighter}`);
}
handleDeleteHighlighter(highlighter, isActive) {
return __awaiter(this, void 0, void 0, function* () {
if (isActive) {
yield this.setHighlighterActivity(highlighter, false);
this.removeHighlighterCommand(highlighter);
new obsidian.Notice(`${highlighter} highlight moved to inactive`);
this.display();
return;
}
const confirmed = yield this.confirmPermanentDeletion();
if (!confirmed) {
return;
}
this.removeHighlighterCommand(highlighter);
delete this.plugin.settings.highlighters[highlighter];
delete this.plugin.settings.highlighterClasses[highlighter];
delete this.plugin.settings.highlighterActivity[highlighter];
this.plugin.settings.highlighterOrder.remove(highlighter);
yield this.plugin.saveSettings();
window.setTimeout(() => {
dispatchEvent(new Event("Highlightr-NewCommand"));
}, 100);
new obsidian.Notice(`${highlighter} highlight permanently deleted`);
this.display();
});
}
migrateClassHighlights(classToken, targetColorHex) {
return __awaiter(this, void 0, void 0, function* () {
const files = this.getConflictScanFiles();
let fileCount = 0;
let updatedMarks = 0;
for (const file of files) {
const content = yield this.app.vault.read(file);
let fileUpdatedMarks = 0;
const replaced = content.replace(/]*>/gi, (markTag) => {
const classTokens = this.getClassTokens(markTag);
if (classTokens.indexOf(classToken) === -1) {
return markTag;
}
fileUpdatedMarks += 1;
const styleMatch = markTag.match(/\bstyle\s*=\s*(["'])(.*?)\1/i);
if (!styleMatch) {
const insertAt = markTag.endsWith(">") ? markTag.length - 1 : markTag.length;
return `${markTag.slice(0, insertAt)} style="--hltr-color: ${targetColorHex};"${markTag.slice(insertAt)}`;
}
const quote = styleMatch[1];
const styleValue = styleMatch[2];
let nextStyleValue = styleValue;
if (/--hltr-color\s*:/i.test(styleValue)) {
nextStyleValue = styleValue.replace(/--hltr-color\s*:\s*[^;]+/i, `--hltr-color: ${targetColorHex}`);
}
else {
const separator = styleValue.trim().length === 0 || styleValue.trim().endsWith(";") ? "" : ";";
nextStyleValue = `${styleValue}${separator} --hltr-color: ${targetColorHex};`;
}
return markTag.replace(styleMatch[0], `style=${quote}${nextStyleValue}${quote}`);
});
if (fileUpdatedMarks > 0 && replaced !== content) {
if (file instanceof obsidian.TFile) {
yield this.app.vault.modify(file, replaced);
fileCount += 1;
updatedMarks += fileUpdatedMarks;
}
}
}
return { fileCount, updatedMarks };
});
}
saveHighlighter(colorName, colorHex, className) {
return __awaiter(this, void 0, void 0, function* () {
const trimmedColorHex = colorHex.trim();
const normalizedColorHex = (trimmedColorHex.startsWith("#") ? trimmedColorHex : `#${trimmedColorHex}`).toUpperCase();
const existingIndex = this.plugin.settings.highlighterOrder.indexOf(colorName);
if (existingIndex === -1) {
this.plugin.settings.highlighterOrder.push(colorName);
}
this.plugin.settings.highlighters[colorName] = normalizedColorHex;
this.plugin.settings.highlighterClasses[colorName] = className;
this.plugin.settings.highlighterActivity[colorName] = true;
window.setTimeout(() => {
dispatchEvent(new Event("Highlightr-NewCommand"));
}, 100);
yield this.plugin.saveSettings();
this.display();
});
}
renderHighlighterItem(container, highlighter, isActive) {
var _a;
const settingItem = container.createEl("div");
settingItem.addClass("highlighter-item-draggable");
const colorIcon = settingItem.createEl("span");
colorIcon.addClass("highlighter-setting-icon");
const svgIcon = activeDocument.createElementNS("http://www.w3.org/2000/svg", "svg");
svgIcon.setAttribute("viewBox", "0 0 24 24");
svgIcon.setAttribute("fill", this.plugin.settings.highlighters[highlighter]);
svgIcon.setAttribute("stroke", this.plugin.settings.highlighters[highlighter]);
svgIcon.setAttribute("stroke-width", "0");
svgIcon.setAttribute("stroke-linecap", "round");
svgIcon.setAttribute("stroke-linejoin", "round");
const svgPath = activeDocument.createElementNS("http://www.w3.org/2000/svg", "path");
svgPath.setAttribute("d", "M20.707 5.826l-3.535-3.533a.999.999 0 0 0-1.408-.006L7.096 10.82a1.01 1.01 0 0 0-.273.488l-1.024 4.437L4 18h2.828l1.142-1.129l3.588-.828c.18-.042.345-.133.477-.262l8.667-8.535a1 1 0 0 0 .005-1.42zm-9.369 7.833l-2.121-2.12l7.243-7.131l2.12 2.12l-7.242 7.131zM4 20h16v2H4z");
svgIcon.appendChild(svgPath);
colorIcon.appendChild(svgIcon);
const highlighterClassName = ((_a = this.plugin.settings.highlighterClasses) === null || _a === void 0 ? void 0 : _a[highlighter]) || createDefaultHighlighterClass(highlighter);
const highlighterSettingItem = new obsidian.Setting(settingItem)
.setClass("highlighter-setting-item")
.setName(highlighter)
.setDesc(this.plugin.settings.highlighters[highlighter]);
const classNameEl = highlighterSettingItem.infoEl.createEl("div", {
cls: "highlighter-setting-classname",
text: `class="hltr-${highlighterClassName.toLowerCase()}"`,
});
const descriptionEl = highlighterSettingItem.infoEl.getElementsByClassName("setting-item-description")[0];
if (descriptionEl) {
highlighterSettingItem.infoEl.insertBefore(classNameEl, descriptionEl);
}
const hotkeyLabel = this.getHighlighterHotkeyLabel(highlighter);
if (hotkeyLabel) {
highlighterSettingItem.infoEl.createEl("div", {
cls: "highlighter-setting-hotkey",
text: hotkeyLabel,
});
}
if (!isActive) {
highlighterSettingItem
.addButton((button) => {
button
.setClass("HighlightrSettingsButton")
.setIcon("highlightr-add")
.setTooltip("Reactivate")
.onClick(() => __awaiter(this, void 0, void 0, function* () {
yield this.setHighlighterActivity(highlighter, true);
new obsidian.Notice(`${highlighter} highlight reactivated`);
this.display();
}));
});
}
highlighterSettingItem
.addButton((button) => {
button
.setClass("HighlightrSettingsButton")
.setClass("HighlightrSettingsButtonDelete")
.setIcon("highlightr-delete")
.setTooltip("Remove")
.onClick(() => __awaiter(this, void 0, void 0, function* () {
yield this.handleDeleteHighlighter(highlighter, isActive);
}));
});
}
display() {
const { containerEl } = this;
containerEl.empty();
new obsidian.Setting(containerEl).setName("Highlightr+ Plugin").setHeading();
const createdBy = containerEl.createEl("p", { text: "Created by " });
createdBy.createEl("a", {
text: "Chetachi 👩🏽💻",
href: "https://github.com/chetachiezikeuzor",
});
createdBy.createEl("span", { text: " and " });
createdBy.createEl("a", {
text: "Olivier 👨🏼💻",
href: "https://github.com/bluelephant825",
});
new obsidian.Setting(containerEl)
.setName("Choose highlight method")
.setDesc(`Choose between highlighting with inline CSS or CSS classes. Please note that there are pros and cons to both choices. Inline CSS will keep you from being reliant on external CSS files if you choose to export your notes. CSS classes are more flexible and easier to customize.`)
.addDropdown((dropdown) => {
let methods = {};
HIGHLIGHTER_METHODS.map((method) => (methods[method] = method));
dropdown.addOptions(methods);
dropdown
.setValue(this.plugin.settings.highlighterMethods)
.onChange((highlightrMethod) => {
this.plugin.settings.highlighterMethods = highlightrMethod;
window.setTimeout(() => {
dispatchEvent(new Event("Highlightr-NewCommand"));
}, 100);
void this.plugin.saveSettings();
void this.plugin.saveData(this.plugin.settings);
this.display();
});
});
const stylesSetting = new obsidian.Setting(containerEl);
stylesSetting
.setName("Choose highlight style")
.setDesc(`Depending on your design aesthetic, you may want to customize the style of your highlights. Choose from an assortment of different highlighter styles by using the dropdown. Depending on your theme, this plugin's CSS may be overriden.`)
.addDropdown((dropdown) => {
let styles = {};
HIGHLIGHTER_STYLES.map((style) => (styles[style] = style));
dropdown.addOptions(styles);
dropdown
.setValue(this.plugin.settings.highlighterStyle)
.onChange((highlighterStyle) => {
this.plugin.settings.highlighterStyle = highlighterStyle;
void this.plugin.saveSettings();
void this.plugin.saveData(this.plugin.settings);
this.plugin.refresh();
});
});
const styleDemo = () => {
const demo = createEl("p");
demo.addClass("highlightr-style-demo");
const lowlight = createEl("span", { text: "Lowlight" });
lowlight.addClass("highlightr-style-demo-lowlight");
demo.appendChild(lowlight);
demo.appendChild(activeDocument.createTextNode(" "));
const floating = createEl("span", { text: "Floating" });
floating.addClass("highlightr-style-demo-floating");
demo.appendChild(floating);
demo.appendChild(activeDocument.createTextNode(" "));
const realistic = createEl("span", { text: "Realistic" });
realistic.addClass("highlightr-style-demo-realistic");
demo.appendChild(realistic);
demo.appendChild(activeDocument.createTextNode(" "));
const rounded = createEl("span", { text: "Rounded" });
rounded.addClass("highlightr-style-demo-rounded");
demo.appendChild(rounded);
return demo;
};
stylesSetting.infoEl.appendChild(styleDemo());
new obsidian.Setting(containerEl)
.setName("Focus Highlights & Notes")
.setDesc("Automatically open and focus the Highlights & Notes tab when a file with highlights is opened.")
.addToggle((toggle) => {
toggle
.setValue(this.plugin.settings.focusHighlightsAndNotes)
.onChange((focusHighlightsAndNotes) => {
this.plugin.settings.focusHighlightsAndNotes = focusHighlightsAndNotes;
void this.plugin.saveSettings();
void this.plugin.saveData(this.plugin.settings);
});
});
const vaultScanSetting = new obsidian.Setting(containerEl)
.setName("Vault scan scope for conflict checks")
.setDesc("Controls which files are scanned when checking and migrating class conflicts. Narrower scope reduces path exposure.")
.addDropdown((dropdown) => {
dropdown
.addOption("active-file", "Active file only")
.addOption("folder", "Specific folder")
.addOption("vault", "Entire vault")
.setValue(this.plugin.settings.conflictScanScope)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
this.plugin.settings.conflictScanScope = value;
yield this.plugin.saveSettings();
this.display();
}));
});
const vaultScanInfo = vaultScanSetting.nameEl.createSpan({ cls: "hltr-vault-scan-info" });
const vaultScanInfoIcon = activeDocument.createElementNS("http://www.w3.org/2000/svg", "svg");
vaultScanInfoIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
vaultScanInfoIcon.setAttribute("width", "24");
vaultScanInfoIcon.setAttribute("height", "24");
vaultScanInfoIcon.setAttribute("viewBox", "0 0 24 24");
vaultScanInfoIcon.setAttribute("fill", "none");
vaultScanInfoIcon.setAttribute("stroke", "currentColor");
vaultScanInfoIcon.setAttribute("stroke-width", "2");
vaultScanInfoIcon.setAttribute("stroke-linecap", "round");
vaultScanInfoIcon.setAttribute("stroke-linejoin", "round");
vaultScanInfoIcon.addClass("lucide", "lucide-info-icon", "lucide-info");
const vaultScanInfoCircle = activeDocument.createElementNS("http://www.w3.org/2000/svg", "circle");
vaultScanInfoCircle.setAttribute("cx", "12");
vaultScanInfoCircle.setAttribute("cy", "12");
vaultScanInfoCircle.setAttribute("r", "10");
const vaultScanInfoPath1 = activeDocument.createElementNS("http://www.w3.org/2000/svg", "path");
vaultScanInfoPath1.setAttribute("d", "M12 16v-4");
const vaultScanInfoPath2 = activeDocument.createElementNS("http://www.w3.org/2000/svg", "path");
vaultScanInfoPath2.setAttribute("d", "M12 8h.01");
vaultScanInfoIcon.appendChild(vaultScanInfoCircle);
vaultScanInfoIcon.appendChild(vaultScanInfoPath1);
vaultScanInfoIcon.appendChild(vaultScanInfoPath2);
vaultScanInfo.appendChild(vaultScanInfoIcon);
const vaultScanInfoBubble = vaultScanInfo.createEl("div", { cls: "hltr-vault-scan-info-bubble" });
const infoMarkdown = `Think of this setting like a **digital security guard** for your Obsidian notes.
When you install a plugin that alters how things look or work (like changing styles or managing "classes"), it needs to look through your files to make sure its instructions don't smash into another plugin's instructions. That's a **conflict check**.
Here is exactly what that setting means, broken down into plain English:
## 1. Vault Scan Scope
* **The Vault:** This is your entire Obsidian project—the main folder where all your notes, images, and folders live.
* **The Scope:** This just means the boundary line. Changing the scope tells the plugin: "You are only allowed to look inside this specific folder," instead of letting it wander through your whole vault.
## 2. Class Conflicts
In web development and plugins, a **class** is like a label you put on a note or a piece of text to give it special powers or styles (for example, a class called important-note might make the background glowing red).
If two different plugins try to use the exact same class name for completely different things, Obsidian gets confused. This setting controls how far the plugin searches to find and fix (migrate) those identical, conflicting labels.
## 3. Path Exposure (The Privacy Part)
This is the most important part of the sentence. Every file on your computer has a "path" (like Documents/School/ObsidianVault/SecretDiary.md).
If you give a plugin a wide scope (letting it scan everything), it has to read the file paths of every single note you own to do its job. If you give it a narrower scope (restricting it to just one folder), it never sees the names or paths of your other private files. It keeps your vault's structure private.
---
### Summary Table
| Scope Setting | What it does | Pros | Cons |
| --- | --- | --- | --- |
| **Wide / Full Vault** | Scans every single note you have. | Catches 100% of conflicts everywhere. | The plugin sees all your file names/paths. |
| **Narrow / Restricted** | Only scans a specific folder. | High privacy; super fast scanning. | Might miss a conflict hidden in an un-scanned folder. |`;
vaultScanInfoBubble.empty();
void obsidian.MarkdownRenderer.renderMarkdown(infoMarkdown, vaultScanInfoBubble, "", this.plugin);
let vaultScanInfoHideTimer = null;
const showVaultScanInfoBubble = () => {
if (vaultScanInfoHideTimer !== null) {
window.clearTimeout(vaultScanInfoHideTimer);
vaultScanInfoHideTimer = null;
}
const rect = vaultScanInfo.getBoundingClientRect();
const width = Math.min(610, Math.floor(window.innerWidth * 0.8));
const margin = 12;
const left = Math.max(margin, Math.min(rect.left, window.innerWidth - width - margin));
const top = Math.min(window.innerHeight - 80, rect.bottom + 8);
vaultScanInfoBubble.style.left = `${left}px`;
vaultScanInfoBubble.style.top = `${top}px`;
vaultScanInfoBubble.classList.add("is-visible");
};
const scheduleHideVaultScanInfoBubble = () => {
if (vaultScanInfoHideTimer !== null) {
window.clearTimeout(vaultScanInfoHideTimer);
}
vaultScanInfoHideTimer = window.setTimeout(() => {
vaultScanInfoBubble.classList.remove("is-visible");
vaultScanInfoHideTimer = null;
}, 150);
};
vaultScanInfo.addEventListener("mouseenter", showVaultScanInfoBubble);
vaultScanInfo.addEventListener("mouseleave", scheduleHideVaultScanInfoBubble);
vaultScanInfoBubble.addEventListener("mouseenter", showVaultScanInfoBubble);
vaultScanInfoBubble.addEventListener("mouseleave", scheduleHideVaultScanInfoBubble);
if (this.plugin.settings.conflictScanScope === "folder") {
new obsidian.Setting(containerEl)
.setName("Conflict scan folder")
.setDesc("Folder path relative to vault root used for conflict scan/migration.")
.addText((text) => {
text
.setPlaceholder("e.g. Projects/Research")
.setValue(this.plugin.settings.conflictScanFolder)
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
this.plugin.settings.conflictScanFolder = value;
yield this.plugin.saveSettings();
}));
});
}
new obsidian.Setting(containerEl)
.setName("Privacy note")
.setDesc("Conflict checks can scan note paths in the selected scope. Highlightr+ performs scans only on explicit save/migrate action and does not persist or transmit scanned file path lists.");
const highlighterSetting = new obsidian.Setting(containerEl);
highlighterSetting
.setName("Choose highlight colors")
.setClass("highlighterplugin-setting-item")
.setDesc(`Create new highlight colors by providing a color name and using the color picker to set the hex code value. Don't forget to save the color before exiting the color picker. Drag and drop the highlight color to change the order for your highlighter component.`);
const colorInput = new obsidian.TextComponent(highlighterSetting.controlEl);
colorInput.setPlaceholder("Color name");
colorInput.inputEl.addClass("highlighter-settings-color");
const classInput = new obsidian.TextComponent(highlighterSetting.controlEl);
classInput.setPlaceholder("Class name (optional)");
classInput.inputEl.addClass("highlighter-settings-class");
const valueInput = new obsidian.TextComponent(highlighterSetting.controlEl);
valueInput.setPlaceholder("Color hex code");
valueInput.inputEl.addClass("highlighter-settings-value");
highlighterSetting
.addButton((button) => {
button.setClass("highlightr-color-picker");
})
.then(() => {
let input = valueInput.inputEl;
const colorMap = this.plugin.settings.highlighterOrder
.map((highlightKey) => this.plugin.settings.highlighters[highlightKey])
.filter((value) => typeof value === "string" && value.length > 0);
let colorHex;
let pickrCreate = new Pickr({
el: ".highlightr-color-picker",
theme: "nano",
swatches: colorMap,
defaultRepresentation: "HEXA",
default: colorMap[colorMap.length - 1],
comparison: false,
components: {
preview: true,
opacity: true,
hue: true,
interaction: {
hex: true,
rgba: true,
hsla: false,
hsva: false,
cmyk: false,
input: true,
clear: true,
cancel: true,
save: true,
},
},
});
pickrCreate
.on("clear", function (instance) {
instance.hide();
input.trigger("change");
})
.on("cancel", function (instance) {
input.trigger("change");
instance.hide();
})
.on("change", function (color) {
colorHex = color.toHEXA().toString();
let newColor;
if (colorHex.length == 6) {
newColor = `${color.toHEXA().toString()}A6`;
}
else {
newColor = color.toHEXA().toString();
}
colorInput.inputEl.setAttribute("style", `background-color: ${newColor}; color: var(--text-normal);`);
setAttributes(input, {
value: newColor,
style: `background-color: ${newColor}; color: var(--text-normal);`,
});
input.setText(newColor);
input.textContent = newColor;
input.value = newColor;
input.trigger("change");
})
.on("save", function (color, instance) {
let newColorValue = color.toHEXA().toString();
input.setText(newColorValue);
input.textContent = newColorValue;
input.value = newColorValue;
input.trigger("change");
instance.hide();
instance.addSwatch(color.toHEXA().toString());
});
})
.addButton((button) => {
button
.setClass("HighlightrSettingsButton")
.setClass("HighlightrSettingsButtonAdd")
.setIcon("highlightr-save")
.setTooltip("Save")
.onClick((buttonEl) => __awaiter(this, void 0, void 0, function* () {
var _a;
let color = colorInput.inputEl.value.replace(" ", "-");
let customClass = classInput.inputEl.value.trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-_]/g, "");
let value = valueInput.inputEl.value;
if (color && value) {
const existingIndex = this.plugin.settings.highlighterOrder.indexOf(color);
if (existingIndex === -1 || ((_a = this.plugin.settings.highlighterActivity) === null || _a === void 0 ? void 0 : _a[color]) === false) {
const className = customClass || createDefaultHighlighterClass(color);
const classToken = `hltr-${className.toLowerCase()}`;
if (this.plugin.settings.highlighterMethods === "css-classes") {
const summary = yield this.scanClassConflictSummary(classToken);
new obsidian.Notice(`Conflict scan scope: ${this.getConflictScanScopeLabel()}`);
if (summary.totalMarks > 0) {
const action = yield this.confirmClassConflict(summary, color, value);
if (action === "rename") {
new obsidian.Notice("Choose a different highlight name or class to keep both colors.");
return;
}
if (action === "reuse-with-migration") {
const migration = yield this.migrateClassHighlights(classToken, value);
new obsidian.Notice(`Updated ${migration.updatedMarks} highlight(s) across ${migration.fileCount} file(s).`);
}
}
}
yield this.saveHighlighter(color, value, className);
return;
}
buttonEl.stopImmediatePropagation();
new obsidian.Notice("This color already exists");
return;
}
if (color && !value) {
new obsidian.Notice("Highlighter hex code missing");
}
else if (!color && value) {
new obsidian.Notice("Highlighter name missing");
}
else {
new obsidian.Notice("Highlighter values missing");
}
}));
});
const activeHeader = new obsidian.Setting(containerEl)
.setName("Active highlight colors")
.setHeading();
activeHeader.setClass("highlightr-section-heading");
const activeInfo = activeHeader.nameEl.createSpan({ cls: "hltr-active-colors-info" });
const activeInfoIcon = activeInfo.createSpan();
obsidian.setIcon(activeInfoIcon, "info");
const activeInfoBubble = activeInfo.createEl("div", {
cls: "hltr-active-colors-info-bubble",
text: "Appear in the context menu and the command palette.",
});
let activeInfoHideTimer = null;
const showActiveInfoBubble = () => {
if (activeInfoHideTimer !== null) {
window.clearTimeout(activeInfoHideTimer);
activeInfoHideTimer = null;
}
const rect = activeInfo.getBoundingClientRect();
const width = 200;
const margin = 12;
const left = Math.max(margin, Math.min(rect.left, window.innerWidth - width - margin));
const top = Math.min(window.innerHeight - 80, rect.bottom + 8);
activeInfoBubble.style.left = `${left}px`;
activeInfoBubble.style.top = `${top}px`;
activeInfoBubble.classList.add("is-visible");
};
const scheduleHideActiveInfoBubble = () => {
if (activeInfoHideTimer !== null) {
window.clearTimeout(activeInfoHideTimer);
}
activeInfoHideTimer = window.setTimeout(() => {
activeInfoBubble.classList.remove("is-visible");
activeInfoHideTimer = null;
}, 150);
};
activeInfo.addEventListener("mouseenter", showActiveInfoBubble);
activeInfo.addEventListener("mouseleave", scheduleHideActiveInfoBubble);
activeInfoBubble.addEventListener("mouseenter", showActiveInfoBubble);
activeInfoBubble.addEventListener("mouseleave", scheduleHideActiveInfoBubble);
const activeContainer = containerEl.createEl("div", {
cls: "HighlightrSettingsTabsContainer",
});
Sortable.create(activeContainer, {
animation: 500,
ghostClass: "highlighter-sortable-ghost",
chosenClass: "highlighter-sortable-chosen",
dragClass: "highlighter-sortable-drag",
dragoverBubble: true,
forceFallback: true,
fallbackClass: "highlighter-sortable-fallback",
easing: "cubic-bezier(1, 0, 0, 1)",
onSort: (command) => {
const oldIndex = command.oldIndex;
const newIndex = command.newIndex;
if (oldIndex == null || newIndex == null) {
return;
}
const active = this.getActiveHighlighters();
const moved = active[oldIndex];
const anchor = active[newIndex];
if (!moved || !anchor) {
return;
}
const order = [...this.plugin.settings.highlighterOrder];
const from = order.indexOf(moved);
const to = order.indexOf(anchor);
if (from === -1 || to === -1) {
return;
}
order.splice(from, 1);
order.splice(to, 0, moved);
this.plugin.settings.highlighterOrder = order;
void this.plugin.saveSettings();
},
});
this.getActiveHighlighters().forEach((highlighter) => {
this.renderHighlighterItem(activeContainer, highlighter, true);
});
const inactiveHeader = new obsidian.Setting(containerEl)
.setName("Inactive highlight colors")
.setHeading();
inactiveHeader.setClass("highlightr-section-heading");
const inactiveContainer = containerEl.createEl("div", {
cls: "HighlightrSettingsTabsContainer",
});
this.getInactiveHighlighters().forEach((highlighter) => {
this.renderHighlighterItem(inactiveContainer, highlighter, false);
});
const hltrDonationDiv = containerEl.createEl("div", {
cls: "hltrDonationSection",
});
const donateText = createEl("p");
donateText.appendText("If you like this Plugin and are considering donating to support continued development, use the buttons below!");
hltrDonationDiv.appendChild(donateText);
const donateToChetachi = createEl("div");
new obsidian.Setting(donateToChetachi).setName("Donate to Chetachi").setHeading();
hltrDonationDiv.appendChild(donateToChetachi);
hltrDonationDiv.appendChild(paypalButton("https://paypal.me/chelseaezikeuzor"));
hltrDonationDiv.appendChild(buyMeACoffeeButton("https://www.buymeacoffee.com/chetachi"));
hltrDonationDiv.appendChild(kofiButton("https://ko-fi.com/chetachi"));
const donateToOlivier = createEl("div");
donateToOlivier.addClass("hltrDonationHeadingSpacing");
new obsidian.Setting(donateToOlivier).setName("Donate to Olivier").setHeading();
hltrDonationDiv.appendChild(donateToOlivier);
hltrDonationDiv.appendChild(paypalButton("https://paypal.me/odebroqueville"));
}
}
const buyMeACoffeeButton = (link) => {
const a = createEl("a");
a.setAttribute("href", link);
a.addClass("buymeacoffee-chetachi-img");
const img = createEl("img", {
attr: {
src: "https://img.buymeacoffee.com/button-api/?text=Buy me a coffee&emoji=&slug=chetachi&button_colour=e3e7ef&font_colour=262626&font_family=Poppins&outline_colour=262626&coffee_colour=ff0000",
height: "42",
alt: "Buy me a coffee",
},
});
a.appendChild(img);
return a;
};
const paypalButton = (link) => {
const a = createEl("a");
a.setAttribute("href", link);
a.addClass("buymeacoffee-chetachi-img");
const svgMarkup = ``;
const img = createEl("img", {
attr: {
src: `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgMarkup)}`,
height: "40",
alt: "PayPal button",
},
});
a.appendChild(img);
return a;
};
const kofiButton = (link) => {
const a = createEl("a");
a.setAttribute("href", link);
a.addClass("buymeacoffee-chetachi-img");
const img = createEl("img", {
attr: {
src: "https://raw.githubusercontent.com/chetachiezikeuzor/Highlightr-Plugin/master/assets/kofi_color.svg",
height: "50",
alt: "Ko-fi button",
},
});
a.appendChild(img);
return a;
};
const MARK_REGEX = /]*>[\s\S]*?<\/mark>/g;
const lastContextClick = {
target: null,
x: 0,
y: 0,
time: 0,
};
let listenerInstalled = false;
class AnnotationModal extends obsidian.Modal {
constructor(app, initialNote, initialTags, onSubmit) {
super(app);
this.resolved = false;
this.initialNote = initialNote;
this.initialTags = initialTags;
this.onSubmit = onSubmit;
}
onOpen() {
this.modalEl.classList.add("highlightr-annotation-modal");
const { contentEl } = this;
contentEl.empty();
contentEl.classList.add("highlightr-annotation-content");
const noteLabel = contentEl.createEl("label", { text: "Annotation:" });
noteLabel.classList.add("highlightr-annotation-label");
const noteArea = contentEl.createEl("textarea");
noteArea.value = this.initialNote;
noteArea.classList.add("highlightr-annotation-textarea");
const tagsLabel = contentEl.createEl("label", { text: "Tags:" });
tagsLabel.classList.add("highlightr-annotation-label");
const tagsInput = contentEl.createEl("input", { type: "text" });
tagsInput.value = this.initialTags;
tagsInput.classList.add("highlightr-annotation-input");
const controls = contentEl.createDiv();
controls.classList.add("highlightr-annotation-controls");
new obsidian.Setting(controls)
.addButton((button) => {
button.setButtonText("Cancel").onClick(() => {
this.resolved = true;
this.onSubmit(null);
this.close();
});
})
.addButton((button) => {
button.setButtonText("OK").setCta().onClick(() => {
this.resolved = true;
this.onSubmit({
note: noteArea.value,
tags: tagsInput.value,
});
this.close();
});
});
}
onClose() {
this.contentEl.empty();
if (!this.resolved) {
this.onSubmit(null);
}
}
}
function ensureContextMenuListener() {
if (listenerInstalled)
return;
listenerInstalled = true;
window.addEventListener("contextmenu", (evt) => {
lastContextClick.target = evt.target;
lastContextClick.x = evt.clientX;
lastContextClick.y = evt.clientY;
lastContextClick.time = Date.now();
}, true);
}
function findAncestor(el, className, doc) {
var _a;
let node = el;
const body = (_a = doc === null || doc === void 0 ? void 0 : doc.body) !== null && _a !== void 0 ? _a : activeDocument.body;
while (node && node !== body) {
if (node.classList.contains(className))
return node;
node = node.parentElement;
}
return null;
}
function isHighlightedElement(el, doc) {
var _a;
let node = el;
const body = (_a = doc === null || doc === void 0 ? void 0 : doc.body) !== null && _a !== void 0 ? _a : activeDocument.body;
while (node && node !== body) {
if (node.tagName === "MARK")
return true;
const cls = node.classList;
if (cls && (cls.contains("cm-highlight") || cls.contains("cm-formatting-highlight"))) {
return true;
}
if (cls) {
for (let i = 0; i < cls.length; i++) {
if (cls[i].startsWith("hltr-"))
return true;
}
}
node = node.parentElement;
}
return false;
}
function findMarkRangeAt(editor, pos) {
const line = editor.getLine(pos.line);
MARK_REGEX.lastIndex = 0;
let match;
while ((match = MARK_REGEX.exec(line)) !== null) {
const start = match.index;
const end = start + match[0].length;
if (pos.ch >= start && pos.ch <= end) {
return {
from: { line: pos.line, ch: start },
to: { line: pos.line, ch: end },
};
}
}
return null;
}
function findLastMarkRangeBefore(editor, pos) {
const line = editor.getLine(pos.line);
MARK_REGEX.lastIndex = 0;
let result = null;
let match;
while ((match = MARK_REGEX.exec(line)) !== null) {
const start = match.index;
const end = start + match[0].length;
if (end <= pos.ch + 1) {
result = {
from: { line: pos.line, ch: start },
to: { line: pos.line, ch: end },
};
continue;
}
break;
}
return result;
}
function findMarkRangeAtCoords(editor, x, y) {
const cm = editor.cm;
if (!cm)
return null;
let offset = null;
try {
if (typeof cm.posAtCoords === "function") {
const result = cm.posAtCoords({ x, y });
if (typeof result === "number")
offset = result;
else if (result && typeof result.pos === "number")
offset = result.pos;
}
}
catch (_a) {
offset = null;
}
if (offset == null)
return null;
try {
const pos = editor.offsetToPos(offset);
return findMarkRangeAt(editor, pos);
}
catch (_b) {
return null;
}
}
function findMarkRangeBeforeCoords(editor, x, y) {
const cm = editor.cm;
if (!cm)
return null;
let offset = null;
try {
if (typeof cm.posAtCoords === "function") {
const result = cm.posAtCoords({ x, y });
if (typeof result === "number")
offset = result;
else if (result && typeof result.pos === "number")
offset = result.pos;
}
}
catch (_a) {
offset = null;
}
if (offset == null)
return null;
try {
const pos = editor.offsetToPos(offset);
return findLastMarkRangeBefore(editor, pos);
}
catch (_b) {
return null;
}
}
function findMarkRangeAtCursor(editor) {
return findMarkRangeAt(editor, editor.getCursor("from"));
}
function escapeAttributeValue(value) {
return value
.replace(/&/g, "&")
.replace(/"/g, """)
.replace(//g, ">");
}
function unescapeAttributeValue(value) {
return value
.replace(/"/g, '"')
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/&/g, "&");
}
function getAttribute(attributes, name) {
const match = attributes.match(new RegExp(`\\b${name}="([^"]*)"`, "i"));
return match ? unescapeAttributeValue(match[1]) : null;
}
function hasHighlightClass(attributes) {
const classValue = getAttribute(attributes, "class");
if (!classValue)
return false;
return classValue.split(/\s+/).some((token) => token.startsWith("hltr-"));
}
function parseMark(markText) {
var _a, _b;
const match = markText.match(/^]*)>([\s\S]*?)<\/mark>$/i);
if (!match)
return null;
const attributes = (match[1] || "").trim();
const note = (_a = getAttribute(attributes, "data-note")) !== null && _a !== void 0 ? _a : "";
const tags = (_b = getAttribute(attributes, "data-tags")) !== null && _b !== void 0 ? _b : "";
const hasDataNote = /\bdata-note\s*=/.test(attributes);
const hasDataTags = /\bdata-tags\s*=/.test(attributes);
const hasStyle = /\bstyle\s*=/.test(attributes);
const highlightClass = hasHighlightClass(attributes);
return {
attributes,
innerContent: match[2],
hasStyle,
hasHighlightClass: highlightClass,
hasHighlight: hasStyle || highlightClass,
hasDataNote,
hasDataTags,
hasAnnotation: hasDataNote || hasDataTags,
note,
tags,
};
}
function setAttribute(attributes, name, value) {
const escaped = escapeAttributeValue(value);
const regex = new RegExp(`\\b${name}="[^"]*"`, "i");
if (regex.test(attributes)) {
return attributes.replace(regex, `${name}="${escaped}"`).trim();
}
return `${attributes} ${name}="${escaped}"`.trim();
}
function removeAttribute(attributes, name) {
return attributes
.replace(new RegExp(`\\s*\\b${name}="[^"]*"`, "ig"), "")
.replace(/\s{2,}/g, " ")
.trim();
}
function removeHighlightStyling(attributes) {
let next = removeAttribute(attributes, "style");
const classValue = getAttribute(next, "class");
if (!classValue)
return next;
const remainingClasses = classValue
.split(/\s+/)
.map((token) => token.trim())
.filter((token) => token.length > 0 && !token.startsWith("hltr-"));
if (remainingClasses.length === 0) {
next = removeAttribute(next, "class");
return next;
}
return setAttribute(next, "class", remainingClasses.join(" "));
}
function createMark(innerContent, attributes) {
const attr = attributes.trim();
if (!attr)
return `${innerContent}`;
return `${innerContent}`;
}
function replaceRange(editor, range, nextText) {
editor.setSelection(range.from, range.to);
editor.replaceSelection(nextText);
editor.focus();
}
function annotateWithModal(app, note, tags) {
return new Promise((resolve) => {
const modal = new AnnotationModal(app, note, tags, (result) => resolve(result));
modal.open();
});
}
function getActiveHighlighters(settings) {
const ordered = settings.highlighterOrder.length > 0
? settings.highlighterOrder
: Object.keys(settings.highlighters);
return ordered.filter((highlighter) => { var _a; return ((_a = settings.highlighterActivity) === null || _a === void 0 ? void 0 : _a[highlighter]) !== false; });
}
function addColorSubmenu(menu, title, settings, onColor) {
const orderedHighlighters = getActiveHighlighters(settings);
if (orderedHighlighters.length === 0) {
return;
}
menu.addItem((item) => {
var _a;
item.setTitle(title).setIcon("highlightr-pen");
const contextItem = item;
if (typeof contextItem.setSubmenu !== "function") {
item.onClick(() => {
const first = getActiveHighlighters(settings)[0];
if (!first)
return;
onColor(first, settings.highlighters[first]);
});
return;
}
const submenu = contextItem.setSubmenu();
(_a = submenu === null || submenu === void 0 ? void 0 : submenu.setUseNativeMenu) === null || _a === void 0 ? void 0 : _a.call(submenu, false);
const orderedHighlighters = getActiveHighlighters(settings);
orderedHighlighters.forEach((highlighter) => {
submenu === null || submenu === void 0 ? void 0 : submenu.addItem((highlighterItem) => {
var _a, _b, _c;
const menuItem = highlighterItem;
const color = settings.highlighters[highlighter];
(_a = menuItem.setTitle) === null || _a === void 0 ? void 0 : _a.call(menuItem, highlighter);
(_b = menuItem.setIcon) === null || _b === void 0 ? void 0 : _b.call(menuItem, "highlighter");
(_c = menuItem.onClick) === null || _c === void 0 ? void 0 : _c.call(menuItem, () => onColor(highlighter, color));
const itemDom = menuItem.dom;
if (itemDom) {
itemDom.addClass("highlightr-color-menu-item");
itemDom.style.setProperty("--highlightr-color", color && color.trim().length > 0 ? color : "transparent");
}
});
});
});
}
function contextMenu(app, menu, editor, plugin, settings) {
var _a, _b, _c;
ensureContextMenuListener();
const selection = editor.getSelection();
const hasSelection = selection.length > 0;
const initialSelectionRange = hasSelection
? { from: editor.getCursor("from"), to: editor.getCursor("to") }
: null;
const menuWithNativeToggle = menu;
(_a = menuWithNativeToggle.setUseNativeMenu) === null || _a === void 0 ? void 0 : _a.call(menuWithNativeToggle, false);
const selectedMark = hasSelection ? parseMark(selection) : null;
const selectedMarkRange = selectedMark
? { from: editor.getCursor("from"), to: editor.getCursor("to") }
: null;
let clickedMarkRange = null;
let clickedNoteIcon = false;
if (Date.now() - lastContextClick.time < 1500) {
const target = lastContextClick.target;
const activeDoc = (_b = app.workspace.activeDocument) !== null && _b !== void 0 ? _b : activeDocument;
const noteIcon = target ? findAncestor(target, "note-icon", activeDoc) : null;
clickedNoteIcon = !!noteIcon;
if (clickedNoteIcon) {
clickedMarkRange = findMarkRangeBeforeCoords(editor, lastContextClick.x, lastContextClick.y);
}
else if (target && isHighlightedElement(target, activeDoc)) {
clickedMarkRange = findMarkRangeAtCoords(editor, lastContextClick.x, lastContextClick.y);
}
}
const cursorMarkRange = !selectedMark ? findMarkRangeAtCursor(editor) : null;
const activeRange = (_c = selectedMarkRange !== null && selectedMarkRange !== void 0 ? selectedMarkRange : clickedMarkRange) !== null && _c !== void 0 ? _c : cursorMarkRange;
const activeMarkText = activeRange ? editor.getRange(activeRange.from, activeRange.to) : null;
const activeMark = activeMarkText ? parseMark(activeMarkText) : null;
const hasActiveMark = !!activeRange && !!activeMark;
const hasActiveAnnotation = hasActiveMark ? activeMark.hasAnnotation : false;
const hasActiveHighlight = hasActiveMark ? activeMark.hasHighlight : false;
const finalizeAfterEdit = () => {
plugin.suppressFullPostProcessing(450);
plugin.syncDecorationsNearSelection(editor);
};
const annotateSelection = () => __awaiter(this, void 0, void 0, function* () {
if (!initialSelectionRange)
return;
const selectionText = editor.getRange(initialSelectionRange.from, initialSelectionRange.to);
if (!selectionText.length)
return;
const result = yield annotateWithModal(app, "", "");
if (!result)
return;
if (!result.note.trim() && !result.tags.trim())
return;
const wrapped = `${selectionText}`;
replaceRange(editor, initialSelectionRange, wrapped);
finalizeAfterEdit();
});
const annotateMark = (range, parsed, isEdit) => __awaiter(this, void 0, void 0, function* () {
const startNote = isEdit ? parsed.note : "";
const startTags = isEdit ? parsed.tags : "";
const result = yield annotateWithModal(app, startNote, startTags);
if (!result)
return;
let attributes = parsed.attributes;
attributes = setAttribute(attributes, "data-note", result.note);
attributes = setAttribute(attributes, "data-tags", result.tags);
replaceRange(editor, range, createMark(parsed.innerContent, attributes));
finalizeAfterEdit();
});
const applyHighlightToSelection = (highlighter, color) => {
var _a, _b;
if (!initialSelectionRange)
return;
const selectionText = editor.getRange(initialSelectionRange.from, initialSelectionRange.to);
if (!selectionText.length)
return;
const isCssClassesMode = settings.highlighterMethods === "css-classes";
const className = ((_b = (_a = settings.highlighterClasses) === null || _a === void 0 ? void 0 : _a[highlighter]) !== null && _b !== void 0 ? _b : createDefaultHighlighterClass(highlighter)).toLowerCase();
const wrapped = isCssClassesMode
? `${selectionText}`
: `${selectionText}`;
replaceRange(editor, initialSelectionRange, wrapped);
finalizeAfterEdit();
};
const applyHighlightToMark = (range, parsed, highlighter, color) => {
var _a, _b;
let attributes = parsed.attributes;
attributes = removeHighlightStyling(attributes);
if (settings.highlighterMethods === "css-classes") {
const className = ((_b = (_a = settings.highlighterClasses) === null || _a === void 0 ? void 0 : _a[highlighter]) !== null && _b !== void 0 ? _b : createDefaultHighlighterClass(highlighter)).toLowerCase();
const classValue = getAttribute(attributes, "class");
const remainingClasses = classValue
? classValue
.split(/\s+/)
.map((token) => token.trim())
.filter((token) => token.length > 0 && !token.startsWith("hltr-"))
: [];
remainingClasses.push(`hltr-${className}`);
attributes = setAttribute(attributes, "class", remainingClasses.join(" "));
attributes = setAttribute(attributes, "style", `--hltr-color: ${color};`);
}
else {
attributes = setAttribute(attributes, "style", `background-color: ${color};`);
}
replaceRange(editor, range, createMark(parsed.innerContent, attributes));
finalizeAfterEdit();
};
const eraseHighlight = (range, parsed) => {
if (parsed.hasAnnotation) {
const attributes = removeHighlightStyling(parsed.attributes);
replaceRange(editor, range, createMark(parsed.innerContent, attributes));
finalizeAfterEdit();
return;
}
replaceRange(editor, range, parsed.innerContent);
finalizeAfterEdit();
};
const eraseAnnotation = (range, parsed) => {
let attributes = parsed.attributes;
attributes = removeAttribute(attributes, "data-note");
attributes = removeAttribute(attributes, "data-tags");
if (!attributes.trim()) {
replaceRange(editor, range, parsed.innerContent);
finalizeAfterEdit();
return;
}
replaceRange(editor, range, createMark(parsed.innerContent, attributes));
finalizeAfterEdit();
};
const eraseHighlightAndAnnotation = (range, parsed) => {
replaceRange(editor, range, parsed.innerContent);
finalizeAfterEdit();
};
if (!hasActiveMark && hasSelection) {
addColorSubmenu(menu, "Highlight", settings, (highlighter, color) => {
applyHighlightToSelection(highlighter, color);
});
menu.addItem((item) => {
item
.setTitle("Annotate")
.setIcon("sticky-note")
.onClick(() => {
void annotateSelection();
});
});
return;
}
if (!hasActiveMark || !activeRange || !activeMark) {
return;
}
if (hasActiveHighlight && !hasActiveAnnotation) {
menu.addItem((item) => {
item
.setTitle("Unhighlight")
.setIcon("highlightr-eraser")
.onClick(() => eraseHighlight(activeRange, activeMark));
});
addColorSubmenu(menu, "Change highlight color", settings, (highlighter, color) => {
applyHighlightToMark(activeRange, activeMark, highlighter, color);
});
menu.addItem((item) => {
item
.setTitle("Annotate")
.setIcon("sticky-note")
.onClick(() => {
void annotateMark(activeRange, activeMark, false);
});
});
return;
}
if (hasActiveHighlight && hasActiveAnnotation) {
menu.addItem((item) => {
item
.setTitle("Unhighlight")
.setIcon("highlightr-eraser")
.onClick(() => eraseHighlight(activeRange, activeMark));
});
addColorSubmenu(menu, "Change highlight color", settings, (highlighter, color) => {
applyHighlightToMark(activeRange, activeMark, highlighter, color);
});
menu.addItem((item) => {
item
.setTitle("Erase annotation")
.setIcon("trash")
.onClick(() => eraseAnnotation(activeRange, activeMark));
});
menu.addItem((item) => {
item
.setTitle("Erase highlight & annotation")
.setIcon("trash")
.onClick(() => eraseHighlightAndAnnotation(activeRange, activeMark));
});
menu.addItem((item) => {
item
.setTitle("Edit annotation")
.setIcon("pencil")
.onClick(() => {
void annotateMark(activeRange, activeMark, true);
});
});
return;
}
if (!hasActiveHighlight && hasActiveAnnotation) {
addColorSubmenu(menu, "Highlight", settings, (highlighter, color) => {
applyHighlightToMark(activeRange, activeMark, highlighter, color);
});
menu.addItem((item) => {
item
.setTitle("Erase annotation")
.setIcon("trash")
.onClick(() => eraseAnnotation(activeRange, activeMark));
});
menu.addItem((item) => {
item
.setTitle("Edit annotation")
.setIcon("pencil")
.onClick(() => {
void annotateMark(activeRange, activeMark, true);
});
});
return;
}
if (clickedNoteIcon) {
addColorSubmenu(menu, "Highlight", settings, (highlighter, color) => {
applyHighlightToMark(activeRange, activeMark, highlighter, color);
});
}
}
function createStyles(settings, activeDocument) {
if (!activeDocument) {
return;
}
const root = activeDocument.documentElement;
Object.keys(settings.highlighters).forEach((highlighter) => {
var _a, _b;
const className = ((_b = (_a = settings.highlighterClasses) === null || _a === void 0 ? void 0 : _a[highlighter]) !== null && _b !== void 0 ? _b : createDefaultHighlighterClass(highlighter)).toLowerCase();
root.style.setProperty(`--hltr-${className}`, settings.highlighters[highlighter]);
});
}
const NOTES_VIEW_TYPE = "highlightr-notes-view";
class NotesTab extends obsidian.ItemView {
constructor(leaf, plugin) {
super(leaf);
this.updateRequestId = 0;
this.activeFilePath = null;
this.title = 'Highlights & Notes';
this.plugin = plugin;
}
getActiveDocument() {
var _a;
const app = this.app;
return (_a = app.workspace.activeDocument) !== null && _a !== void 0 ? _a : activeDocument;
}
getViewType() {
return NOTES_VIEW_TYPE;
}
getDisplayText() {
return this.title;
}
getIcon() {
return "sticky-note"; // Uses a sticky-note icon
}
resolveColorFromClass(cssClass) {
var _a, _b;
if (!cssClass) {
return null;
}
const settings = this.plugin.settings;
for (const highlighterKey of settings.highlighterOrder) {
const configuredClass = (_a = settings.highlighterClasses) === null || _a === void 0 ? void 0 : _a[highlighterKey];
if (!configuredClass) {
continue;
}
if (`hltr-${configuredClass.toLowerCase()}` === cssClass) {
return (_b = settings.highlighters[highlighterKey]) !== null && _b !== void 0 ? _b : null;
}
}
return null;
}
updateNotesList(container, filePath) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f;
const requestId = ++this.updateRequestId;
try {
console.log("Starting updateNotesList");
container.empty();
if (filePath) {
this.activeFilePath = filePath;
}
else {
const focusedMarkdownFilePath = this.plugin.getFocusedMarkdownFilePath();
if (focusedMarkdownFilePath) {
this.activeFilePath = focusedMarkdownFilePath;
}
}
const activeFilePath = this.activeFilePath;
const markdownLeaves = this.app.workspace.getLeavesOfType("markdown");
console.log("Markdown leaves found:", markdownLeaves.length);
if (!activeFilePath) {
container.createEl('div', {
cls: 'highlightr-message',
text: 'No markdown file in focus'
});
return;
}
const allHighlights = [];
let content = null;
for (const leaf of markdownLeaves) {
if (requestId !== this.updateRequestId) {
return;
}
const view = leaf.view;
if (view instanceof obsidian.MarkdownView && ((_a = view.file) === null || _a === void 0 ? void 0 : _a.path) === activeFilePath) {
console.log("Processing file:", view.file.path);
content = (_c = (_b = view.editor) === null || _b === void 0 ? void 0 : _b.getValue()) !== null && _c !== void 0 ? _c : yield this.app.vault.read(view.file);
console.log("File content loaded:", content.length);
break;
}
}
if (content === null) {
const file = this.app.vault.getAbstractFileByPath(activeFilePath);
if (file instanceof obsidian.TFile) {
console.log("Processing file from vault:", file.path);
content = yield this.app.vault.read(file);
console.log("File content loaded:", content.length);
}
}
if (requestId !== this.updateRequestId) {
return;
}
if (content !== null) {
// Updated regex patterns
const noteRegex = /data-note="([^"]*)"/;
const tagsRegex = /data-tags="([^"]*)"/;
const colorRegex = /(?:background(?:-color)?|--hltr-color):\s*((?:rgba?\([^)]+\)|#[A-Fa-f0-9]+))/i;
const classRegex = /\bclass="([^"]*)"/i;
const highlightRegex = /]*>(.*?)<\/mark>/g;
let match;
while ((match = highlightRegex.exec(content)) !== null) {
const fullMatch = match[0];
const text = match[1];
console.log("Processing mark:", fullMatch);
// Extract note
const noteMatch = fullMatch.match(noteRegex);
const note = noteMatch ? noteMatch[1] : null;
console.log("Found note:", note);
// Extract tags with improved handling
const tagsMatch = fullMatch.match(tagsRegex);
const tags = Array.isArray(tagsMatch) && typeof tagsMatch[1] === 'string'
? tagsMatch[1].split(',')
.map(tag => tag.trim())
.filter(tag => tag.length > 0)
.map(tag => `#${tag.replace(/\s+/g, '-')}`)
: [];
console.log("Found tags:", tags);
// Extract color
const colorMatch = fullMatch.match(colorRegex);
const color = colorMatch ? colorMatch[1] : null;
console.log("Found color:", color);
const classMatch = fullMatch.match(classRegex);
const classTokens = (_e = (_d = classMatch === null || classMatch === void 0 ? void 0 : classMatch[1]) === null || _d === void 0 ? void 0 : _d.split(/\s+/).map((token) => token.trim()).filter((token) => token.length > 0)) !== null && _e !== void 0 ? _e : [];
const cssClass = (_f = classTokens.find((token) => token.startsWith("hltr-"))) !== null && _f !== void 0 ? _f : null;
console.log("Found css class:", cssClass);
allHighlights.push({
text,
note,
color,
tags,
filePath: activeFilePath,
cssClass
});
}
}
if (requestId !== this.updateRequestId) {
return;
}
this.displayHighlights(container, allHighlights, activeFilePath);
}
catch (error) {
console.error("Error in updateNotesList:", error);
container.createEl('div', {
cls: 'highlightr-error',
text: 'Error processing markdown content'
});
}
});
}
decodeHtmlEntities(text) {
const namedEntities = {
amp: '&',
lt: '<',
gt: '>',
quot: '"',
apos: "'",
nbsp: '\u00A0'
};
return text.replace(/&(#x?[0-9a-fA-F]+|[a-zA-Z]+);/g, (match, entity) => {
var _a;
if (entity.startsWith('#x') || entity.startsWith('#X')) {
const codePoint = Number.parseInt(entity.slice(2), 16);
return Number.isNaN(codePoint) ? match : String.fromCodePoint(codePoint);
}
if (entity.startsWith('#')) {
const codePoint = Number.parseInt(entity.slice(1), 10);
return Number.isNaN(codePoint) ? match : String.fromCodePoint(codePoint);
}
return (_a = namedEntities[entity]) !== null && _a !== void 0 ? _a : match;
});
}
appendSanitized(node, target) {
var _a;
const doc = this.getActiveDocument();
if (node.nodeType === Node.TEXT_NODE) {
target.appendChild(doc.createTextNode((_a = node.textContent) !== null && _a !== void 0 ? _a : ''));
return;
}
if (node.nodeType !== Node.ELEMENT_NODE) {
return;
}
const element = node;
const tagName = element.tagName.toLowerCase();
if (tagName === 'sub' || tagName === 'sup' || tagName === 'code') {
const safeElement = doc.createElement(tagName);
Array.from(element.childNodes).forEach((child) => this.appendSanitized(child, safeElement));
target.appendChild(safeElement);
return;
}
Array.from(element.childNodes).forEach((child) => this.appendSanitized(child, target));
}
renderHtmlFragment(container, text) {
if (!text) {
return;
}
const doc = this.getActiveDocument();
if (!text.includes('<')) {
container.appendChild(doc.createTextNode(this.decodeHtmlEntities(text)));
return;
}
const parser = new DOMParser();
const parsed = parser.parseFromString(text, 'text/html');
Array.from(parsed.body.childNodes).forEach((node) => this.appendSanitized(node, container));
}
renderHighlightText(container, text) {
var _a, _b;
const inlineCodeRegex = /`([^`]+)`|]*>([\s\S]*?)<\/code>/gi;
let cursor = 0;
let match;
const doc = this.getActiveDocument();
while ((match = inlineCodeRegex.exec(text)) !== null) {
const fullMatch = match[0];
const inlineCode = (_b = (_a = match[1]) !== null && _a !== void 0 ? _a : match[2]) !== null && _b !== void 0 ? _b : '';
const beforeText = text.slice(cursor, match.index);
this.renderHtmlFragment(container, beforeText);
const codeEl = doc.createElement('code');
codeEl.textContent = this.decodeHtmlEntities(inlineCode);
container.appendChild(codeEl);
cursor = match.index + fullMatch.length;
}
this.renderHtmlFragment(container, text.slice(cursor));
}
renderNoteText(container, text) {
const decodedText = this.decodeHtmlEntities(text);
const lines = decodedText.split(/\r?\n/);
let index = 0;
const doc = this.getActiveDocument();
while (index < lines.length) {
const line = lines[index].trim();
if (!line) {
index += 1;
continue;
}
const bulletMatch = line.match(/^[-*+]\s+(.+)$/);
const numberedMatch = line.match(/^\d+[.)]\s+(.+)$/);
if (bulletMatch || numberedMatch) {
const listEl = doc.createElement(numberedMatch ? 'ol' : 'ul');
while (index < lines.length) {
const currentLine = lines[index].trim();
if (!currentLine) {
index += 1;
continue;
}
const currentBulletMatch = currentLine.match(/^[-*+]\s+(.+)$/);
const currentNumberedMatch = currentLine.match(/^\d+[.)]\s+(.+)$/);
if (numberedMatch && currentNumberedMatch) {
const listItem = doc.createElement('li');
this.renderHighlightText(listItem, currentNumberedMatch[1]);
listEl.appendChild(listItem);
index += 1;
continue;
}
if (bulletMatch && currentBulletMatch) {
const listItem = doc.createElement('li');
this.renderHighlightText(listItem, currentBulletMatch[1]);
listEl.appendChild(listItem);
index += 1;
continue;
}
break;
}
container.appendChild(listEl);
continue;
}
const lineEl = doc.createElement('div');
this.renderHighlightText(lineEl, line);
container.appendChild(lineEl);
index += 1;
}
}
displayHighlights(container, highlights, activeFilePath) {
var _a;
const existingFormattedContent = container.querySelector('.highlightr-formatted-content');
if (existingFormattedContent) {
existingFormattedContent.remove();
}
const formattedContent = container.createDiv({ cls: "highlightr-formatted-content" });
const sectionFilePath = activeFilePath !== null && activeFilePath !== void 0 ? activeFilePath : (_a = highlights[0]) === null || _a === void 0 ? void 0 : _a.filePath;
if (!sectionFilePath) {
container.createDiv({
cls: 'highlightr-message highlightr-empty-state',
text: "No highlights found"
});
return;
}
const fileNameWithExtension = sectionFilePath.split('/').pop() || sectionFilePath;
const fileNameWithoutExtension = fileNameWithExtension.replace(/\.[^/.]+$/, "");
const fileSection = formattedContent.createDiv({ cls: "file-section" });
fileSection.createEl("h3", { text: "Highlights & Notes" });
fileSection.createEl("h4", { text: fileNameWithoutExtension });
const fileHighlights = highlights.filter(highlight => highlight.filePath === sectionFilePath);
if (fileHighlights.length === 0) {
fileSection.createDiv({
cls: 'highlightr-message highlightr-empty-state',
text: "No highlights found"
});
return;
}
fileHighlights.forEach(({ text, note, color, tags, cssClass }) => {
const highlightEl = fileSection.createDiv({ cls: "highlight-item" });
const textEl = highlightEl.createDiv({ cls: "highlight-text" });
if (cssClass) {
textEl.addClass(cssClass);
}
if (color) {
textEl.style.setProperty('--hltr-color', color);
}
else if (cssClass) {
const resolvedClassColor = this.resolveColorFromClass(cssClass);
if (resolvedClassColor) {
textEl.style.setProperty('--hltr-color', resolvedClassColor);
}
}
this.renderHighlightText(textEl, text);
// Create note if exists
if (note) {
const noteEl = highlightEl.createDiv({
cls: "highlight-note"
});
const noteIconEl = noteEl.createSpan({ cls: "note-icon" });
obsidian.setIcon(noteIconEl, "sticky-note");
const noteContentEl = noteEl.createDiv({ cls: "highlight-note-content" });
this.renderNoteText(noteContentEl, note);
}
// Create tags if exist
if (tags.length > 0) {
const tagsContainer = highlightEl.createDiv({
cls: "highlight-tags"
});
tags.forEach((tag) => {
const tagEl = tagsContainer.createSpan({
cls: "highlight-tag",
text: tag
});
// Add click event to filter by tag (optional feature)
tagEl.addEventListener('click', () => {
// Implement tag filtering if desired
});
});
}
});
}
// Enhanced force update method
forceUpdate(filePath) {
try {
const container = this.contentEl.querySelector('.highlightr-notes-container');
if (container && container.instanceOf(HTMLDivElement)) {
void this.updateNotesList(container, filePath);
}
else {
// If container doesn't exist, create it inside the view content
const newContainer = this.contentEl.createDiv({
cls: "highlightr-notes-container"
});
void this.updateNotesList(newContainer, filePath);
}
}
catch (error) {
console.error("Error in forceUpdate:", error);
}
}
onClose() {
return __awaiter(this, void 0, void 0, function* () {
// Cleanup logic
});
}
onOpen() {
return __awaiter(this, void 0, void 0, function* () {
try {
const existingContainer = this.contentEl.querySelector('.highlightr-notes-container');
const container = existingContainer && existingContainer.instanceOf(HTMLDivElement)
? existingContainer
: this.contentEl.createDiv({ cls: "highlightr-notes-container" });
// Layout and sizing are handled via CSS (.highlightr-notes-container)
// Avoid inline styles to keep theming and maintainability intact.
// Register for workspace events
this.registerEvent(this.app.workspace.on("file-open", (file) => {
if ((file === null || file === void 0 ? void 0 : file.extension) === "md") {
void this.updateNotesList(container, file.path);
}
}));
this.registerEvent(this.app.workspace.on("editor-change", () => {
void this.updateNotesList(container);
}));
// Initial update
yield this.updateNotesList(container);
}
catch (error) {
console.error("Error in onOpen:", error);
this.containerEl.createDiv({
text: "Failed to load Highlights & Notes side view",
cls: "highlightr-error-message"
});
}
});
}
}
const showHighlightrMenuFromCommand = (plugin, editor) => {
var _a, _b, _c;
if (!editor || !editor.hasFocus()) {
new obsidian.Notice("Focus must be in editor");
return;
}
const menu = new obsidian.Menu();
contextMenu(plugin.app, menu, editor, plugin, plugin.settings);
const cursor = editor.getCursor("from");
let coords = null;
if (editor.cursorCoords) {
coords = editor.cursorCoords(true, "window");
}
else if (editor.coordsAtPos) {
const offset = editor.posToOffset(cursor);
coords = (_c = (_b = (_a = editor.cm).coordsAtPos) === null || _b === void 0 ? void 0 : _b.call(_a, offset)) !== null && _c !== void 0 ? _c : editor.coordsAtPos(offset);
}
if (!coords) {
return;
}
menu.showAtPosition({
x: coords.right + 25,
y: coords.top + 20,
});
};
class HighlightrPlugin extends obsidian.Plugin {
constructor() {
super(...arguments);
this.editorMenuEventRef = null;
this.isUpdatingEditorContent = false;
this.suppressFullProcessingUntil = 0;
this.isRefreshingPreviewAfterOpen = false;
this.activeMarkdownFilePath = null;
this.markRegex = /]*>[\s\S]*?<\/mark>/g;
this.eraseHighlight = (editor) => {
const currentStr = editor.getSelection();
const newStr = currentStr
.replace(/]*>/gi, "")
.replace(/<\/mark\s*>/gi, "");
editor.replaceSelection(newStr);
editor.focus();
};
this.refresh = () => {
this.updateStyle();
};
this.updateStyle = () => {
var _a, _b, _c, _d, _e, _f, _g;
const activeDoc = this.getActiveDocument();
// Apply style classes to both the active document body and the workspace container
const applyClass = (el, cls, cond) => {
if (!el)
return;
el.classList.toggle(cls, cond);
};
const condLow = this.settings.highlighterStyle === "lowlight";
const condFloat = this.settings.highlighterStyle === "floating";
const condRound = this.settings.highlighterStyle === "rounded";
const condReal = this.settings.highlighterStyle === "realistic";
applyClass((_a = activeDoc === null || activeDoc === void 0 ? void 0 : activeDoc.body) !== null && _a !== void 0 ? _a : null, "highlightr-lowlight", condLow);
applyClass((_b = activeDoc === null || activeDoc === void 0 ? void 0 : activeDoc.body) !== null && _b !== void 0 ? _b : null, "highlightr-floating", condFloat);
applyClass((_c = activeDoc === null || activeDoc === void 0 ? void 0 : activeDoc.body) !== null && _c !== void 0 ? _c : null, "highlightr-rounded", condRound);
applyClass((_d = activeDoc === null || activeDoc === void 0 ? void 0 : activeDoc.body) !== null && _d !== void 0 ? _d : null, "highlightr-realistic", condReal);
const workspaceEl = (_g = (_f = (_e = this.app) === null || _e === void 0 ? void 0 : _e.workspace) === null || _f === void 0 ? void 0 : _f.containerEl) !== null && _g !== void 0 ? _g : null;
applyClass(workspaceEl, "highlightr-lowlight", condLow);
applyClass(workspaceEl, "highlightr-floating", condFloat);
applyClass(workspaceEl, "highlightr-rounded", condRound);
applyClass(workspaceEl, "highlightr-realistic", condReal);
};
this.handleHighlighterInContextMenu = (menu, editor) => {
contextMenu(this.app, menu, editor, this, this.settings);
};
}
getActiveDocument() {
var _a;
return (_a = this.app.workspace.activeDocument) !== null && _a !== void 0 ? _a : activeDocument;
}
getActiveEditorScroller() {
const activeDoc = this.getActiveDocument();
return activeDoc.querySelector('.workspace-leaf.mod-active .cm-scroller');
}
getFocusedMarkdownFilePath() {
var _a, _b, _c;
const activeLeafView = (_a = this.app.workspace.activeLeaf) === null || _a === void 0 ? void 0 : _a.view;
if (activeLeafView instanceof obsidian.MarkdownView) {
return (_c = (_b = activeLeafView.file) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : null;
}
return this.activeMarkdownFilePath;
}
findMarkRangeAt(line, offset) {
this.markRegex.lastIndex = 0;
let match;
while ((match = this.markRegex.exec(line)) !== null) {
const start = match.index;
const end = start + match[0].length;
if (offset >= start && offset <= end) {
return { start, end };
}
}
return null;
}
findNearestRangeByText(editor, text, preferredOffset) {
if (!text.length || !editor.posToOffset || !editor.offsetToPos) {
return null;
}
const content = editor.getValue();
const fallbackOffset = editor.posToOffset(editor.getCursor("from"));
const targetOffset = preferredOffset !== null && preferredOffset !== void 0 ? preferredOffset : fallbackOffset;
let matchIndex = content.indexOf(text);
if (matchIndex === -1) {
return null;
}
let closestIndex = matchIndex;
let closestDistance = Math.abs(matchIndex - targetOffset);
while (matchIndex !== -1) {
const distance = Math.abs(matchIndex - targetOffset);
if (distance < closestDistance) {
closestDistance = distance;
closestIndex = matchIndex;
}
matchIndex = content.indexOf(text, matchIndex + 1);
}
return {
from: editor.offsetToPos(closestIndex),
to: editor.offsetToPos(closestIndex + text.length),
};
}
findRangeByTextOccurrence(editor, text, occurrence) {
if (!text.length || occurrence < 0 || !editor.offsetToPos) {
return null;
}
const content = editor.getValue();
let fromIndex = -1;
let searchStart = 0;
let current = 0;
while (current <= occurrence) {
fromIndex = content.indexOf(text, searchStart);
if (fromIndex === -1) {
return null;
}
searchStart = fromIndex + 1;
current += 1;
}
return {
from: editor.offsetToPos(fromIndex),
to: editor.offsetToPos(fromIndex + text.length),
};
}
getMarkAttributeValue(attributes, name) {
const match = attributes.match(new RegExp(`\\b${name}="([^"]*)"`, "i"));
if (!match) {
return "";
}
return match[1]
.replace(/"/g, '"')
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/&/g, "&");
}
normalizeMarkText(value) {
return value
.replace(/`<\s*([^`<>\s\/]+)\s*>`/g, " $1 ")
.replace(/<[^>]*>/g, " ")
.replace(/ /gi, " ")
.replace(/"/g, '"')
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/&/g, "&")
.replace(/<\s*([^<>\s\/]+)\s*>/g, " $1 ")
.replace(/`/g, " ")
.replace(/\s+/g, " ")
.trim();
}
findMarkRangeFromPreviewElement(editor, markEl, preferredOffset) {
var _a, _b, _c, _d;
if (!editor.offsetToPos) {
return null;
}
const content = editor.getValue();
const targetText = this.normalizeMarkText(markEl.innerHTML);
const targetNote = (_a = markEl.getAttribute("data-note")) !== null && _a !== void 0 ? _a : "";
const targetTags = (_b = markEl.getAttribute("data-tags")) !== null && _b !== void 0 ? _b : "";
const matchRegex = /]*)>([\s\S]*?)<\/mark>/gi;
const candidates = [];
let match;
while ((match = matchRegex.exec(content)) !== null) {
const attributes = (_c = match[1]) !== null && _c !== void 0 ? _c : "";
const inner = (_d = match[2]) !== null && _d !== void 0 ? _d : "";
const text = this.normalizeMarkText(inner);
if (text !== targetText) {
continue;
}
let score = 10;
const note = this.getMarkAttributeValue(attributes, "data-note");
const tags = this.getMarkAttributeValue(attributes, "data-tags");
if (note === targetNote) {
score += 3;
}
if (tags === targetTags) {
score += 3;
}
candidates.push({ start: match.index, end: match.index + match[0].length, score });
}
if (candidates.length === 0) {
return null;
}
const target = preferredOffset !== null && preferredOffset !== void 0 ? preferredOffset : 0;
candidates.sort((a, b) => {
if (b.score !== a.score) {
return b.score - a.score;
}
return Math.abs(a.start - target) - Math.abs(b.start - target);
});
const selected = candidates[0];
return {
from: editor.offsetToPos(selected.start),
to: editor.offsetToPos(selected.end),
};
}
withPreservedEditorScroll(applyUpdate) {
var _a;
const scroller = this.getActiveEditorScroller();
const previousTop = (_a = scroller === null || scroller === void 0 ? void 0 : scroller.scrollTop) !== null && _a !== void 0 ? _a : null;
applyUpdate();
if (scroller && previousTop !== null) {
scroller.scrollTop = previousTop;
}
}
setMarkdownViewMode(view, mode) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const leaf = view.leaf;
const viewState = leaf.getViewState();
yield leaf.setViewState(Object.assign(Object.assign({}, viewState), { state: Object.assign(Object.assign({}, ((_a = viewState.state) !== null && _a !== void 0 ? _a : {})), { mode }) }));
});
}
restorePreviewWhenAnnotationModalCloses(view) {
const activeDoc = this.getActiveDocument();
const restoreIfReady = () => {
const hasOpenAnnotationModal = !!activeDoc.querySelector('.highlightr-annotation-modal');
if (hasOpenAnnotationModal) {
window.setTimeout(restoreIfReady, 100);
return;
}
void this.setMarkdownViewMode(view, "preview");
};
window.setTimeout(restoreIfReady, 0);
}
showReadingModeContextMenu(event) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f;
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
if (!(view === null || view === void 0 ? void 0 : view.editor)) {
return;
}
const target = event.target;
if (!target) {
return;
}
const previewRoot = target.closest('.markdown-preview-view');
if (!previewRoot) {
return;
}
const markEl = target.closest('mark');
const noteIconEl = target.closest('.note-icon');
const noteIconMark = ((_a = noteIconEl === null || noteIconEl === void 0 ? void 0 : noteIconEl.previousElementSibling) === null || _a === void 0 ? void 0 : _a.tagName.toLowerCase()) === 'mark'
? noteIconEl.previousElementSibling
: null;
const activeMarkEl = markEl !== null && markEl !== void 0 ? markEl : noteIconMark;
const editor = view.editor;
const activeDoc = this.getActiveDocument();
const selection = (_b = activeDoc.defaultView) === null || _b === void 0 ? void 0 : _b.getSelection();
const selectedText = (_c = selection === null || selection === void 0 ? void 0 : selection.toString()) !== null && _c !== void 0 ? _c : "";
if (!activeMarkEl && !selectedText.trim().length) {
return;
}
const shouldRestorePreview = view.getMode() === "preview";
if (shouldRestorePreview) {
yield this.setMarkdownViewMode(view, "source");
}
const clickOffset = (_d = editor.posToOffset) === null || _d === void 0 ? void 0 : _d.call(editor, editor.getCursor("from"));
const restorePreview = () => __awaiter(this, void 0, void 0, function* () {
if (shouldRestorePreview) {
yield this.setMarkdownViewMode(view, "preview");
}
});
const menu = new obsidian.Menu();
const menuWithNativeToggle = menu;
(_e = menuWithNativeToggle.setUseNativeMenu) === null || _e === void 0 ? void 0 : _e.call(menuWithNativeToggle, false);
if (activeMarkEl) {
const resolvedRange = this.findMarkRangeFromPreviewElement(editor, activeMarkEl, clickOffset);
if (!resolvedRange) {
yield restorePreview();
return;
}
editor.setSelection(resolvedRange.from, resolvedRange.to);
}
else if (selection && selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
const startNode = range.startContainer;
const endNode = range.endContainer;
const markdownSourceRoot = (_f = previewRoot.querySelector('.markdown-preview-sizer')) !== null && _f !== void 0 ? _f : previewRoot;
if (!markdownSourceRoot.contains(startNode) || !markdownSourceRoot.contains(endNode)) {
yield restorePreview();
return;
}
const nearestRange = this.findNearestRangeByText(editor, selectedText, clickOffset);
if (!nearestRange) {
yield restorePreview();
return;
}
editor.setSelection(nearestRange.from, nearestRange.to);
}
if (shouldRestorePreview) {
menu.onHide(() => {
this.restorePreviewWhenAnnotationModalCloses(view);
});
}
contextMenu(this.app, menu, editor, this, this.settings);
menu.showAtPosition({ x: event.clientX, y: event.clientY });
event.preventDefault();
});
}
onload() {
const init = () => __awaiter(this, void 0, void 0, function* () {
console.log(`Highlightr v${this.manifest.version} loaded`);
addIcons();
yield this.loadSettings();
// Register NotesTab view type first
this.registerView(NOTES_VIEW_TYPE, (leaf) => new NotesTab(leaf, this));
this.app.workspace.onLayoutReady(() => __awaiter(this, void 0, void 0, function* () {
console.log('Initializing Highlightr plugin...');
// Initialize plugin features
this.reloadStyles(this.settings);
createHighlighterIcons(this.settings, this);
this.processMarkTags();
this.attachEventListeners();
// Open and initialize the notes tab
yield this.openNotesTab(false);
// Force update the NotesTab after a short delay to ensure content is loaded
window.setTimeout(() => {
this.triggerNotesTabUpdate();
}, 500);
console.log('Highlightr plugin initialization complete');
}));
this.editorMenuEventRef = this.app.workspace.on("editor-menu", (menu, editor) => {
this.handleHighlighterInContextMenu(menu, editor);
});
this.register(() => {
if (this.editorMenuEventRef) {
this.app.workspace.offref(this.editorMenuEventRef);
this.editorMenuEventRef = null;
}
});
// Register for view changes
this.registerEvent(this.app.workspace.on("active-leaf-change", (leaf) => {
var _a, _b;
const activeMarkdownFilePath = (leaf === null || leaf === void 0 ? void 0 : leaf.view) instanceof obsidian.MarkdownView
? (_b = (_a = leaf.view.file) === null || _a === void 0 ? void 0 : _a.path) !== null && _b !== void 0 ? _b : null
: null;
const markdownFileChanged = !!activeMarkdownFilePath && activeMarkdownFilePath !== this.activeMarkdownFilePath;
if (activeMarkdownFilePath) {
this.activeMarkdownFilePath = activeMarkdownFilePath;
}
this.removeExistingBubbles();
this.processMarkTags();
this.attachEventListeners();
if (markdownFileChanged) {
this.triggerNotesTabUpdate(activeMarkdownFilePath);
}
}));
this.registerEvent(this.app.workspace.on("editor-change", debounce(() => {
var _a;
if (this.isUpdatingEditorContent)
return;
if (Date.now() < this.suppressFullProcessingUntil)
return;
this.processMarkTags();
this.triggerNotesTabUpdate((_a = this.getFocusedMarkdownFilePath()) !== null && _a !== void 0 ? _a : undefined);
}, 120)));
this.registerEvent(this.app.workspace.on("file-open", (file) => __awaiter(this, void 0, void 0, function* () {
const activeMarkdownFilePath = (file === null || file === void 0 ? void 0 : file.extension) === "md"
? file.path
: null;
if (activeMarkdownFilePath) {
this.activeMarkdownFilePath = activeMarkdownFilePath;
}
const runPostOpenPass = () => {
this.processMarkTags();
this.attachEventListeners();
};
this.removeExistingBubbles();
runPostOpenPass();
window.setTimeout(runPostOpenPass, 80);
window.setTimeout(runPostOpenPass, 240);
void this.refreshPreviewAfterFileOpen();
if (activeMarkdownFilePath && (yield this.fileHasHighlights(activeMarkdownFilePath))) {
void this.openNotesTab(this.settings.focusHighlightsAndNotes);
}
this.triggerNotesTabUpdate(activeMarkdownFilePath !== null && activeMarkdownFilePath !== void 0 ? activeMarkdownFilePath : undefined);
if (activeMarkdownFilePath) {
window.setTimeout(() => {
this.triggerNotesTabUpdate(activeMarkdownFilePath);
}, 100);
}
})));
this.addSettingTab(new HighlightrSettingTab(this.app, this));
this.addCommand({
id: "highlighter-plugin-menu",
name: "Open Highlightr",
icon: "highlightr-pen",
editorCallback: (editor) => {
showHighlightrMenuFromCommand(this, editor);
},
});
addEventListener("Highlightr-NewCommand", () => {
this.reloadStyles(this.settings);
this.generateCommands(this.editor);
createHighlighterIcons(this.settings, this);
});
this.generateCommands(this.editor);
this.refresh();
});
void init();
}
reloadStyles(settings) {
const activeDoc = this.getActiveDocument();
const currentSheet = activeDoc.querySelector("style#highlightr-styles");
if (currentSheet) {
currentSheet.remove();
}
createStyles(settings, activeDoc);
}
getActiveHighlighters() {
const ordered = this.settings.highlighterOrder.length > 0
? this.settings.highlighterOrder
: Object.keys(this.settings.highlighters);
return ordered.filter((highlighter) => { var _a; return ((_a = this.settings.highlighterActivity) === null || _a === void 0 ? void 0 : _a[highlighter]) !== false; });
}
generateCommands(editor) {
this.getActiveHighlighters().forEach((highlighterKey) => {
var _a, _b;
const applyCommand = (command, editor) => {
const selectedText = editor.getSelection();
const curserStart = editor.getCursor("from");
const curserEnd = editor.getCursor("to");
const prefix = command.prefix;
const suffix = command.suffix || prefix;
const setCursor = (mode) => {
editor.setCursor(curserStart.line + command.line * mode, curserEnd.ch + cursorPos * mode);
};
const cursorPos = selectedText.length > 0
? prefix.length + suffix.length + 1
: prefix.length;
const preStart = {
line: curserStart.line - command.line,
ch: curserStart.ch - prefix.length,
};
const pre = editor.getRange(preStart, curserStart);
const sufEnd = {
line: curserStart.line + command.line,
ch: curserEnd.ch + suffix.length,
};
const suf = editor.getRange(curserEnd, sufEnd);
const preLast = pre.slice(-1);
const prefixLast = prefix.replace(/^\s+/, "").slice(-1);
if (suf === suffix.replace(/\s+$/, "")) {
if (preLast === prefixLast && selectedText) {
editor.replaceRange(selectedText, preStart, sufEnd);
const changeCursor = (mode) => {
editor.setCursor(curserStart.line + command.line * mode, curserEnd.ch + (cursorPos * mode + 8));
};
return changeCursor(-1);
}
}
editor.replaceSelection(`${prefix}${selectedText}${suffix}`);
return setCursor(1);
};
const colorValue = this.settings.highlighters[highlighterKey];
const className = ((_b = (_a = this.settings.highlighterClasses) === null || _a === void 0 ? void 0 : _a[highlighterKey]) !== null && _b !== void 0 ? _b : createDefaultHighlighterClass(highlighterKey)).toLowerCase();
const commandsMap = {
highlight: {
char: 34,
line: 0,
prefix: this.settings.highlighterMethods === "css-classes"
? ``
: ``,
suffix: "",
},
};
Object.keys(commandsMap).forEach((type) => {
let highlighterpen = getHighlighterPenIconId(highlighterKey, this.settings.highlighters[highlighterKey]);
this.addCommand({
id: highlighterKey,
name: highlighterKey,
icon: highlighterpen,
editorCallback: (editor) => __awaiter(this, void 0, void 0, function* () {
applyCommand(commandsMap[type], editor);
yield wait(10);
editor.focus();
}),
});
});
this.addCommand({
id: "unhighlight",
name: "Remove highlight",
icon: "highlightr-eraser",
editorCallback: (editor) => __awaiter(this, void 0, void 0, function* () {
this.eraseHighlight(editor);
editor.focus();
}),
});
});
}
onunload() {
console.log("Highlightr unloaded");
// Clean up click listener
if (this.clickHandlerBound) {
this.app.workspace.containerEl.removeEventListener('click', this.clickHandlerBound);
}
if (this.readingContextMenuHandlerBound) {
this.app.workspace.containerEl.removeEventListener('contextmenu', this.readingContextMenuHandlerBound, true);
}
}
loadSettings() {
return __awaiter(this, void 0, void 0, function* () {
const savedSettings = yield this.loadData();
this.settings = Object.assign({}, DEFAULT_SETTINGS, savedSettings);
this.settings.highlighterClasses = this.settings.highlighterClasses || {};
this.settings.highlighterActivity = this.settings.highlighterActivity || {};
this.settings.highlighterOrder = this.settings.highlighterOrder || [];
this.settings.conflictScanScope = this.settings.conflictScanScope || "active-file";
this.settings.conflictScanFolder = this.settings.conflictScanFolder || "";
const knownHighlighters = Array.from(new Set([
...Object.keys(this.settings.highlighters),
...this.settings.highlighterOrder,
]));
const legacyStatuses = this.settings.highlighterStatuses;
knownHighlighters.forEach((highlighter) => {
if (!this.settings.highlighters[highlighter]) {
return;
}
const existingClass = this.settings.highlighterClasses[highlighter];
if (!existingClass || !existingClass.trim()) {
this.settings.highlighterClasses[highlighter] = createDefaultHighlighterClass(highlighter);
}
const activity = this.settings.highlighterActivity[highlighter];
if (typeof activity !== "boolean") {
const legacyStatus = legacyStatuses === null || legacyStatuses === void 0 ? void 0 : legacyStatuses[highlighter];
this.settings.highlighterActivity[highlighter] = legacyStatus === "inactive" ? false : true;
}
if (this.settings.highlighterOrder.indexOf(highlighter) === -1) {
this.settings.highlighterOrder.push(highlighter);
}
});
delete this.settings.highlighterStatuses;
});
}
saveSettings() {
return __awaiter(this, void 0, void 0, function* () {
const settingsToSave = Object.assign({}, this.settings);
delete settingsToSave.highlighterStatuses;
yield this.saveData(settingsToSave);
});
}
displayNoteBubble(note, event) {
// Remove any existing bubbles first
this.removeExistingBubbles();
const activeDoc = this.getActiveDocument();
const bubble = activeDoc.createElement("div");
bubble.className = "note-bubble";
bubble.textContent = note;
bubble.style.left = `${event.pageX}px`;
bubble.style.top = `${event.pageY}px`;
activeDoc.body.appendChild(bubble);
// Get the mark element (highlight)
const target = event.target;
const markElement = target.tagName.toLowerCase() === "mark" ?
target :
target.previousElementSibling;
const removeBubble = (e) => {
if (bubble.parentNode) {
activeDoc.body.removeChild(bubble);
markElement.removeEventListener("mouseout", removeBubble);
markElement.removeEventListener("click", removeBubble);
}
};
// Add listeners to mark element instead of bubble
markElement.addEventListener("mouseout", removeBubble);
markElement.addEventListener("click", removeBubble);
}
removeExistingBubbles() {
const activeDoc = this.getActiveDocument();
const existingBubbles = activeDoc.querySelectorAll('.note-bubble');
existingBubbles.forEach(bubble => {
if (bubble.parentNode) {
bubble.parentNode.removeChild(bubble);
}
});
}
// Attach mouse event listener to each container (editor and reading view)
attachEventListeners() {
const workspaceEl = this.app.workspace.containerEl;
// Remove existing listener if present
if (this.clickHandlerBound) {
workspaceEl.removeEventListener('click', this.clickHandlerBound);
}
if (this.readingContextMenuHandlerBound) {
workspaceEl.removeEventListener('contextmenu', this.readingContextMenuHandlerBound, true);
}
// Create new bound handler
this.clickHandlerBound = (e) => {
const target = e.target;
if (target.closest('.highlight-tag, .hltr-inline-label')) {
e.stopPropagation();
e.preventDefault();
// Handle tag click logic here
}
};
this.readingContextMenuHandlerBound = (e) => {
this.showReadingModeContextMenu(e);
};
workspaceEl.addEventListener('click', this.clickHandlerBound);
workspaceEl.addEventListener('contextmenu', this.readingContextMenuHandlerBound, true);
// Handle editing mode
const activeDoc = this.getActiveDocument();
const editorContainers = activeDoc.querySelectorAll('.cm-html-embed');
editorContainers.forEach((editorContainer) => {
this.attachMouseEvents(editorContainer);
});
// Handle reading mode
const readingViews = activeDoc.querySelectorAll('.markdown-preview-view');
readingViews.forEach((readingView) => {
this.attachMouseEvents(readingView);
});
// Clean up any duplicate text nodes
this.processMarkTags();
}
// Define mouse over event handler to display note bubble
attachMouseEvents(container) {
const handleMouseOver = (event) => {
const target = event.target;
if (target.tagName.toLowerCase() === "mark" && target.hasAttribute("data-note")) {
const note = target.getAttribute("data-note");
if (note && event instanceof MouseEvent) {
this.displayNoteBubble(note, event);
}
}
else if (target.classList.contains("note-icon")) {
const prevElement = target.previousElementSibling;
if ((prevElement === null || prevElement === void 0 ? void 0 : prevElement.tagName.toLowerCase()) === "mark" && prevElement.hasAttribute("data-note")) {
const note = prevElement.getAttribute("data-note");
if (note && event instanceof MouseEvent) {
this.displayNoteBubble(note, event);
}
}
}
};
// Clean up and reattach
container.removeEventListener("mouseover", handleMouseOver);
container.addEventListener("mouseover", handleMouseOver);
}
stripInjectedDecorationSpans(content) {
let cleaned = content;
let previous = "";
while (cleaned !== previous) {
previous = cleaned;
cleaned = cleaned
.replace(/]*\bclass="[^"]*\b(?:note-icon|highlight-tag|highlight-tags|hltr-inline-label|hltr-highlight-tags)\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, "");
}
return cleaned
.replace(/]*\bclass="[^"]*\b(?:note-icon|highlight-tag|highlight-tags|hltr-inline-label|hltr-highlight-tags)\b[^"]*"[^>]*>/g, "")
.replace(/([\s\S]*?<\/span>)(?:\s*<\/span>)+/g, "$1")
.replace(/<\/mark>(?:\s*<\/span>)+/g, "")
.replace(/(?:\s*<\/span>\s*)+(?=\s*)+(?=\n|$)/g, "$1");
}
cleanupNotes() {
try {
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
if (!(view === null || view === void 0 ? void 0 : view.editor))
return;
const content = view.editor.getValue();
if (!content)
return;
const cursorPos = view.editor.getCursor();
const activeDoc = this.getActiveDocument();
const noteIconWrapper = activeDoc.createElement('span');
noteIconWrapper.className = 'note-icon';
obsidian.setIcon(noteIconWrapper, 'sticky-note');
const noteIconHtml = noteIconWrapper.outerHTML;
const normalizedContent = this.stripInjectedDecorationSpans(content);
const cleanContent = normalizedContent.replace(/]*)>([\s\S]*?)<\/mark>(?:\s*[\s\S]*?<\/span>)*/g, (match, attrs, inner) => {
const attrsText = (attrs || "").trim();
const noteMatch = attrsText.match(/\bdata-note="([^"]*)"/i);
const hasNote = !!noteMatch && noteMatch[1].trim().length > 0;
const attrPart = attrsText.length > 0 ? ` ${attrsText}` : "";
const rebuiltMark = `${inner}`;
return hasNote ? `${rebuiltMark}${noteIconHtml}` : rebuiltMark;
});
if (content !== cleanContent) {
this.isUpdatingEditorContent = true;
this.withPreservedEditorScroll(() => {
view.editor.setValue(cleanContent);
view.editor.setCursor(cursorPos);
});
this.isUpdatingEditorContent = false;
}
}
catch (error) {
this.isUpdatingEditorContent = false;
console.error('Error in cleanupNotes:', error);
}
}
suppressFullPostProcessing(durationMs = 400) {
this.suppressFullProcessingUntil = Date.now() + durationMs;
}
syncDecorationsNearSelection(editor) {
var _a;
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
if (!(view === null || view === void 0 ? void 0 : view.editor))
return;
const targetEditor = editor !== null && editor !== void 0 ? editor : view.editor;
const cursor = targetEditor.getCursor("from");
const startLine = Math.max(0, cursor.line - 2);
const endLine = Math.min(targetEditor.lastLine(), cursor.line + 2);
const from = { line: startLine, ch: 0 };
const to = { line: endLine, ch: targetEditor.getLine(endLine).length };
const segment = targetEditor.getRange(from, to);
const activeDoc = this.getActiveDocument();
const noteIconWrapper = activeDoc.createElement('span');
noteIconWrapper.className = 'note-icon';
obsidian.setIcon(noteIconWrapper, 'sticky-note');
const noteIconHtml = noteIconWrapper.outerHTML;
const cleaned = this.stripInjectedDecorationSpans(segment)
.replace(/]*\bclass="[^"]*\bnote-icon\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhighlight-tag\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhighlight-tags\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhltr-inline-label\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhltr-highlight-tags\b[^"]*"[^>]*>\s*<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhltr-highlight-tags\b[^"]*"[^>]*>(?:\s*[\s\S]*?<\/span>\s*)*<\/span>/g, '');
const rebuilt = cleaned.replace(/]*)>([\s\S]*?)<\/mark>/g, (match, attributes, innerContent) => {
const normalizedAttributes = (attributes || "").trim();
const attrPart = normalizedAttributes.length > 0 ? ` ${normalizedAttributes}` : "";
const dataTagsMatch = normalizedAttributes.match(/\bdata-tags="([^"]*)"/);
const tags = dataTagsMatch ? dataTagsMatch[1] : "";
const dataNoteMatch = normalizedAttributes.match(/\bdata-note="([^"]*)"/);
const note = dataNoteMatch ? dataNoteMatch[1] : "";
let additionalContent = "";
if (note.trim().length > 0) {
additionalContent += noteIconHtml;
}
if (tags.trim().length > 0) {
const tagArray = tags
.split(',')
.map((tag) => tag.trim())
.filter((tag) => tag.length > 0)
.map((tag) => `#${tag.replace(/^#+/, '').replace(/\s+/g, '-')}`);
if (tagArray.length > 0) {
let tagsMarkup = '';
tagArray.forEach((tag) => {
tagsMarkup += `${tag}`;
});
tagsMarkup += '';
additionalContent += tagsMarkup;
}
}
return `${innerContent}${additionalContent}`;
});
if (segment !== rebuilt) {
this.isUpdatingEditorContent = true;
this.withPreservedEditorScroll(() => {
targetEditor.replaceRange(rebuilt, from, to);
targetEditor.setCursor(cursor);
});
this.isUpdatingEditorContent = false;
}
this.triggerNotesTabUpdate((_a = this.getFocusedMarkdownFilePath()) !== null && _a !== void 0 ? _a : undefined);
}
refreshPreviewAfterFileOpen() {
return __awaiter(this, void 0, void 0, function* () {
if (this.isRefreshingPreviewAfterOpen) {
return;
}
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
if (!view || view.getMode() !== "preview") {
return;
}
this.isRefreshingPreviewAfterOpen = true;
try {
yield this.setMarkdownViewMode(view, "source");
this.processMarkTags();
yield this.setMarkdownViewMode(view, "preview");
this.attachEventListeners();
}
finally {
this.isRefreshingPreviewAfterOpen = false;
}
});
}
processMarkTags() {
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
if (!(view === null || view === void 0 ? void 0 : view.editor))
return;
const content = view.editor.getValue();
if (!content)
return;
const cursorPos = view.editor.getCursor();
const cleanContent = this.stripInjectedDecorationSpans(content)
.replace(/]*\bclass="[^"]*\bnote-icon\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhighlight-tag\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhighlight-tags\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhltr-inline-label\b[^"]*"[^>]*>[\s\S]*?<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhltr-highlight-tags\b[^"]*"[^>]*>\s*<\/span>/g, '')
.replace(/]*\bclass="[^"]*\bhltr-highlight-tags\b[^"]*"[^>]*>(?:\s*[\s\S]*?<\/span>\s*)*<\/span>/g, '');
const updatedContent = cleanContent.replace(/]*)>([\s\S]*?)<\/mark>/g, (match, attributes, innerContent) => {
const normalizedAttributes = (attributes || "").trim();
const attrPart = normalizedAttributes.length > 0 ? ` ${normalizedAttributes}` : "";
const dataTagsMatch = normalizedAttributes.match(/\bdata-tags="([^"]*)"/);
const tags = dataTagsMatch ? dataTagsMatch[1] : "";
const dataNoteMatch = normalizedAttributes.match(/\bdata-note="([^"]*)"/);
const note = dataNoteMatch ? dataNoteMatch[1] : "";
let additionalContent = "";
if (note.trim().length > 0) {
const activeDoc = this.getActiveDocument();
const noteIconWrapper = activeDoc.createElement('span');
noteIconWrapper.className = 'note-icon';
obsidian.setIcon(noteIconWrapper, 'sticky-note');
additionalContent += noteIconWrapper.outerHTML;
}
if (tags.trim().length > 0) {
const tagArray = tags
.split(',')
.map((tag) => tag.trim())
.filter((tag) => tag.length > 0)
.map((tag) => `#${tag.replace(/^#+/, '').replace(/\s+/g, '-')}`);
if (tagArray.length > 0) {
let tagsMarkup = '';
tagArray.forEach((tag) => {
tagsMarkup += `${tag}`;
});
tagsMarkup += '';
additionalContent += tagsMarkup;
}
}
return `${innerContent}${additionalContent}`;
});
if (content !== updatedContent) {
this.isUpdatingEditorContent = true;
this.withPreservedEditorScroll(() => {
view.editor.setValue(updatedContent);
view.editor.setCursor(cursorPos);
});
this.isUpdatingEditorContent = false;
}
}
openNotesTab() {
return __awaiter(this, arguments, void 0, function* (focus = true) {
try {
const run = () => __awaiter(this, void 0, void 0, function* () {
const existingLeaves = this.app.workspace.getLeavesOfType(NOTES_VIEW_TYPE);
let leaf = null;
if (existingLeaves.length > 0) {
leaf = existingLeaves[0];
}
else {
const rightSidebar = this.app.workspace.getRightLeaf(false);
leaf = rightSidebar !== null && rightSidebar !== void 0 ? rightSidebar : this.app.workspace.getLeaf(true);
yield leaf.setViewState({
type: NOTES_VIEW_TYPE,
active: true,
state: {}
});
}
if (leaf) {
if (focus) {
this.app.workspace.revealLeaf(leaf);
const workspace = this.app.workspace;
const rightSplit = workspace.rightSplit;
if ((rightSplit === null || rightSplit === void 0 ? void 0 : rightSplit.collapsed) && typeof rightSplit.expand === "function") {
rightSplit.expand();
}
}
}
});
const workspace = this.app.workspace;
if (workspace.layoutReady) {
yield run();
}
else {
this.app.workspace.onLayoutReady(run);
}
}
catch (error) {
console.error('Error opening notes tab:', error);
}
});
}
fileHasHighlights(filePath) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
const targetFilePath = filePath !== null && filePath !== void 0 ? filePath : this.getFocusedMarkdownFilePath();
if (!targetFilePath)
return false;
const markdownLeaves = this.app.workspace.getLeavesOfType("markdown");
for (const leaf of markdownLeaves) {
const view = leaf.view;
if (view instanceof obsidian.MarkdownView && ((_a = view.file) === null || _a === void 0 ? void 0 : _a.path) === targetFilePath) {
const content = (_b = view.editor) === null || _b === void 0 ? void 0 : _b.getValue();
return content ? / {
const view = leaf.view;
if (view instanceof NotesTab) {
view.forceUpdate(filePath);
}
});
}
catch (error) {
console.error("Error triggering NotesTab update:", error);
}
}
}
module.exports = HighlightrPlugin;
/* nosourcemap */