You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1044 lines
155 KiB
1044 lines
155 KiB
3 years ago
|
/*
|
||
|
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.
|
||
|
***************************************************************************** */
|
||
|
|
||
|
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());
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Filename: multi-column-markdown/src/regionSettings.ts
|
||
|
* Created Date: Tuesday, February 1st 2022, 12:23:53 pm
|
||
|
* Author: Cameron Robinson
|
||
|
*
|
||
|
* Copyright (c) 2022 Cameron Robinson
|
||
|
*/
|
||
|
var BorderOption;
|
||
|
(function (BorderOption) {
|
||
|
BorderOption[BorderOption["enabled"] = 0] = "enabled";
|
||
|
BorderOption[BorderOption["on"] = 1] = "on";
|
||
|
BorderOption[BorderOption["true"] = 2] = "true";
|
||
|
BorderOption[BorderOption["disabled"] = 3] = "disabled";
|
||
|
BorderOption[BorderOption["off"] = 4] = "off";
|
||
|
BorderOption[BorderOption["false"] = 5] = "false";
|
||
|
})(BorderOption || (BorderOption = {}));
|
||
|
var ShadowOption;
|
||
|
(function (ShadowOption) {
|
||
|
ShadowOption[ShadowOption["enabled"] = 0] = "enabled";
|
||
|
ShadowOption[ShadowOption["on"] = 1] = "on";
|
||
|
ShadowOption[ShadowOption["true"] = 2] = "true";
|
||
|
ShadowOption[ShadowOption["disabled"] = 3] = "disabled";
|
||
|
ShadowOption[ShadowOption["off"] = 4] = "off";
|
||
|
ShadowOption[ShadowOption["false"] = 5] = "false";
|
||
|
})(ShadowOption || (ShadowOption = {}));
|
||
|
var ColumnLayout;
|
||
|
(function (ColumnLayout) {
|
||
|
ColumnLayout[ColumnLayout["standard"] = 0] = "standard";
|
||
|
ColumnLayout[ColumnLayout["left"] = 1] = "left";
|
||
|
ColumnLayout[ColumnLayout["first"] = 2] = "first";
|
||
|
ColumnLayout[ColumnLayout["center"] = 3] = "center";
|
||
|
ColumnLayout[ColumnLayout["middle"] = 4] = "middle";
|
||
|
ColumnLayout[ColumnLayout["second"] = 5] = "second";
|
||
|
ColumnLayout[ColumnLayout["right"] = 6] = "right";
|
||
|
ColumnLayout[ColumnLayout["third"] = 7] = "third";
|
||
|
ColumnLayout[ColumnLayout["last"] = 8] = "last";
|
||
|
})(ColumnLayout || (ColumnLayout = {}));
|
||
|
|
||
|
/*
|
||
|
* File: multi-column-markdown/src/MultiColumnParser.ts
|
||
|
* Created Date: Saturday, January 22nd 2022, 6:02:46 pm
|
||
|
* Author: Cameron Robinson
|
||
|
*
|
||
|
* Copyright (c) 2022 Cameron Robinson
|
||
|
*/
|
||
|
const START_REGEX_STRS = ["=== *start-multi-column",
|
||
|
"=== *multi-column-start"];
|
||
|
const START_REGEX_ARR = [];
|
||
|
for (let i = 0; i < START_REGEX_STRS.length; i++) {
|
||
|
START_REGEX_ARR.push(new RegExp(START_REGEX_STRS[i]));
|
||
|
}
|
||
|
function findStartTag(text) {
|
||
|
let found = false;
|
||
|
let startPosition = -1;
|
||
|
for (let i = 0; i < START_REGEX_ARR.length; i++) {
|
||
|
if (START_REGEX_ARR[i].test(text)) {
|
||
|
found = true;
|
||
|
startPosition = text.search(START_REGEX_STRS[i]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return { found, startPosition };
|
||
|
}
|
||
|
function containsStartTag(text) {
|
||
|
return findStartTag(text).found;
|
||
|
}
|
||
|
function isStartTagWithID(text) {
|
||
|
let startTagData = findStartTag(text);
|
||
|
if (startTagData.found === true) {
|
||
|
let key = getStartTagKey(text);
|
||
|
if (key === null || key === "") {
|
||
|
return { isStartTag: true, hasKey: false };
|
||
|
}
|
||
|
return { isStartTag: true, hasKey: true };
|
||
|
}
|
||
|
return { isStartTag: false, hasKey: false };
|
||
|
}
|
||
|
const END_REGEX_STRS = ["=== *end-multi-column",
|
||
|
"=== *multi-column-end"];
|
||
|
const END_REGEX_ARR = [];
|
||
|
for (let i = 0; i < END_REGEX_STRS.length; i++) {
|
||
|
END_REGEX_ARR.push(new RegExp(END_REGEX_STRS[i]));
|
||
|
}
|
||
|
function findEndTag(text) {
|
||
|
let found = false;
|
||
|
let startPosition = -1;
|
||
|
for (let i = 0; i < END_REGEX_ARR.length; i++) {
|
||
|
if (END_REGEX_ARR[i].test(text)) {
|
||
|
found = true;
|
||
|
startPosition = text.search(END_REGEX_STRS[i]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return { found, startPosition };
|
||
|
}
|
||
|
function containsEndTag(text) {
|
||
|
return findEndTag(text).found;
|
||
|
}
|
||
|
const COL_REGEX_STRS = ["=== *column-end *===",
|
||
|
"=== *end-column *===",
|
||
|
"=== *column-break *===",
|
||
|
"=== *break-column *==="];
|
||
|
const COL_REGEX_ARR = [];
|
||
|
for (let i = 0; i < COL_REGEX_STRS.length; i++) {
|
||
|
COL_REGEX_ARR.push(new RegExp(COL_REGEX_STRS[i]));
|
||
|
}
|
||
|
function containsColEndTag(text) {
|
||
|
let found = false;
|
||
|
for (let i = 0; i < COL_REGEX_ARR.length; i++) {
|
||
|
if (COL_REGEX_ARR[i].test(text)) {
|
||
|
found = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return found;
|
||
|
}
|
||
|
const COL_SETTINGS_REGEX_STRS = ["```settings",
|
||
|
"```column-settings",
|
||
|
"```multi-column-settings"];
|
||
|
const COL_SETTINGS_REGEX_ARR = [];
|
||
|
for (let i = 0; i < COL_SETTINGS_REGEX_STRS.length; i++) {
|
||
|
COL_SETTINGS_REGEX_ARR.push(new RegExp(COL_SETTINGS_REGEX_STRS[i]));
|
||
|
}
|
||
|
function containsColSettingsTag(text) {
|
||
|
let found = false;
|
||
|
for (let i = 0; i < COL_SETTINGS_REGEX_ARR.length; i++) {
|
||
|
if (COL_SETTINGS_REGEX_ARR[i].test(text)) {
|
||
|
found = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return found;
|
||
|
}
|
||
|
function parseColumnSettings(settingsStr) {
|
||
|
// Set the minimum number of columnds to 2.
|
||
|
let numberOfColumns = 2;
|
||
|
let columnLayout = ColumnLayout.standard;
|
||
|
let borderDrawn = true;
|
||
|
let shadowDrawn = true;
|
||
|
let settingsLines = settingsStr.split("\n");
|
||
|
for (let i = 0; i < settingsLines.length; i++) {
|
||
|
if (settingsLines[i].toLowerCase().replace(/\s/g, "").contains("numberofcolumns:")) {
|
||
|
let userDefNumberOfCols = parseInt(settingsLines[i].split(":")[1]);
|
||
|
if (Number.isNaN(userDefNumberOfCols) === false) {
|
||
|
if (userDefNumberOfCols === 3) {
|
||
|
numberOfColumns = 3;
|
||
|
}
|
||
|
else if (userDefNumberOfCols === 2) {
|
||
|
numberOfColumns = 2;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
for (let i = 0; i < settingsLines.length; i++) {
|
||
|
if (settingsLines[i].toLowerCase().replace(/\s/g, "").contains("largestcolumn:")) {
|
||
|
let setting = settingsLines[i].split(":")[1].trimStart().trimEnd().toLowerCase();
|
||
|
let userDefLayout = ColumnLayout[setting];
|
||
|
if (userDefLayout !== undefined) {
|
||
|
columnLayout = userDefLayout;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (let i = 0; i < settingsLines.length; i++) {
|
||
|
if (settingsLines[i].toLowerCase().replace(/\s/g, "").contains("border:")) {
|
||
|
let setting = settingsLines[i].split(":")[1].trimStart().trimEnd().toLowerCase();
|
||
|
let isBorderDrawn = BorderOption[setting];
|
||
|
if (isBorderDrawn !== undefined) {
|
||
|
switch (isBorderDrawn) {
|
||
|
case (BorderOption.disabled):
|
||
|
case (BorderOption.off):
|
||
|
case (BorderOption.false):
|
||
|
borderDrawn = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (let i = 0; i < settingsLines.length; i++) {
|
||
|
if (settingsLines[i].toLowerCase().replace(/\s/g, "").contains("shadow:")) {
|
||
|
let setting = settingsLines[i].split(":")[1].trimStart().trimEnd().toLowerCase();
|
||
|
let isShadowDrawn = ShadowOption[setting];
|
||
|
if (isShadowDrawn !== undefined) {
|
||
|
switch (isShadowDrawn) {
|
||
|
case (ShadowOption.disabled):
|
||
|
case (ShadowOption.off):
|
||
|
case (ShadowOption.false):
|
||
|
shadowDrawn = false;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
let settings = { numberOfColumns, columnLayout, drawBorder: borderDrawn, drawShadow: shadowDrawn };
|
||
|
return settings;
|
||
|
}
|
||
|
function countStartTags(text) {
|
||
|
let keys = [];
|
||
|
let startTagData = findStartTag(text);
|
||
|
while (startTagData.found) {
|
||
|
// Slice off everything before the tag
|
||
|
text = text.slice(startTagData.startPosition);
|
||
|
/**
|
||
|
* Get just the start tag line and then set text to everything just
|
||
|
* after the start tag.
|
||
|
*/
|
||
|
let tag = text.split("\n")[0];
|
||
|
text = text.slice(1); // This moves the text 1 character so we dont match the same tag.
|
||
|
// Parse out the key and append to the list.
|
||
|
let key = getStartTagKey(tag);
|
||
|
if (key === null) {
|
||
|
key = "";
|
||
|
}
|
||
|
keys.push(key);
|
||
|
// Search again for another tag before looping.
|
||
|
startTagData = findStartTag(text);
|
||
|
}
|
||
|
return { numberOfTags: keys.length, keys };
|
||
|
}
|
||
|
/**
|
||
|
* This function will filter a set of strings, returning all items starting
|
||
|
* from the closest open start tag through the last item in the set.
|
||
|
*
|
||
|
* The function filters out all end tags to make sure that the start tag we
|
||
|
* find is the proper start tag for the list sent.
|
||
|
* @param linesAboveArray
|
||
|
* @returns
|
||
|
*/
|
||
|
function getStartBlockAboveLine(linesAboveArray) {
|
||
|
// Reduce the array down into a single string so that we can
|
||
|
// easily RegEx over the string and find the indicies we're looking for.
|
||
|
let linesAboveStr = linesAboveArray.reduce((prev, current) => {
|
||
|
return prev + "\n" + current;
|
||
|
}, "");
|
||
|
/*
|
||
|
* First thing we need to do is check if there are any end tags in the
|
||
|
* set of strings (which logically would close start tags and therefore
|
||
|
* the start tag it closes is not what we want). If there are we want to
|
||
|
* slowly narrow down our set of strings until the last end tag is
|
||
|
* removed. This makes it easier to find the closest open start tag
|
||
|
* in the data.
|
||
|
*/
|
||
|
let endTagSerachData = findEndTag(linesAboveStr);
|
||
|
while (endTagSerachData.found === true) {
|
||
|
// Get the index of where the first regex match in the
|
||
|
// string is. then we slice from 0 to index off of the string
|
||
|
// split it by newline, cut off the first line (which actually
|
||
|
// contains the regex) then reduce back down to a single string.
|
||
|
//
|
||
|
// TODO: This could be simplified if we just slice the text after
|
||
|
// the end tag instead of the begining.
|
||
|
let indexOfRegex = endTagSerachData.startPosition;
|
||
|
linesAboveArray = linesAboveStr.slice(indexOfRegex).split("\n").splice(1);
|
||
|
linesAboveStr = linesAboveArray.reduce((prev, current) => {
|
||
|
return prev + "\n" + current;
|
||
|
}, "");
|
||
|
endTagSerachData = findEndTag(linesAboveStr);
|
||
|
}
|
||
|
/**
|
||
|
* Now we have the set of lines after all other end tags. We now
|
||
|
* need to check if there is still a start tag left in the data. If
|
||
|
* there is no start tag then we want to return an empty array and empty
|
||
|
* key.
|
||
|
*/
|
||
|
let startBlockKey = "";
|
||
|
let startTagSearchData = findStartTag(linesAboveStr);
|
||
|
if (startTagSearchData.found === false) {
|
||
|
return null;
|
||
|
}
|
||
|
else {
|
||
|
/**
|
||
|
* Now we know there is at least 1 start key left, however there
|
||
|
* may be multiple start keys if the user is not closing their
|
||
|
* blocks. We currently dont allow recusive splitting so we
|
||
|
* want to get the last key in our remaining set. Same idea as
|
||
|
* above.
|
||
|
*/
|
||
|
while (startTagSearchData.found === true) {
|
||
|
// Get the index of where the first regex match in the
|
||
|
// string is. then we slice from 0 to index off of the string
|
||
|
// split it by newline, cut off the first line (which actually
|
||
|
// contains the regex) then reduce back down to a single string.
|
||
|
//
|
||
|
// TODO: This could be simplified if we just slice the text after
|
||
|
// the end tag instead of the begining.
|
||
|
let startIndex = startTagSearchData.startPosition;
|
||
|
linesAboveArray = linesAboveStr.slice(startIndex).split("\n");
|
||
|
let startTag = linesAboveArray[0];
|
||
|
let key = getStartTagKey(startTag);
|
||
|
if (key !== null) {
|
||
|
startBlockKey = key;
|
||
|
}
|
||
|
linesAboveArray = linesAboveArray.splice(1);
|
||
|
linesAboveStr = linesAboveArray.reduce((prev, current) => {
|
||
|
return prev + "\n" + current;
|
||
|
}, "");
|
||
|
startTagSearchData = findStartTag(linesAboveStr);
|
||
|
}
|
||
|
}
|
||
|
return { startBlockKey, linesAboveArray };
|
||
|
}
|
||
|
function getStartTagKey(startTag) {
|
||
|
let keySplit = startTag.split(":");
|
||
|
if (keySplit.length > 1) {
|
||
|
return keySplit[1].replace(" ", "");
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Filename: multi-column-markdown/src/utilities/utils.ts
|
||
|
* Created Date: Tuesday, January 30th 2022, 4:02:19 pm
|
||
|
* Author: Cameron Robinson
|
||
|
*
|
||
|
* Copyright (c) 2022 Cameron Robinson
|
||
|
*/
|
||
|
function getUID(length = 10) {
|
||
|
if (length > 10) {
|
||
|
length = 10;
|
||
|
}
|
||
|
let UID = Math.random().toString(36).substring(2);
|
||
|
UID = UID.slice(0, length);
|
||
|
return UID;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Filename: multi-column-markdown/src/domObject.ts
|
||
|
* Created Date: Tuesday, February 1st 2022, 12:04:00 pm
|
||
|
* Author: Cameron Robinson
|
||
|
*
|
||
|
* Copyright (c) 2022 Cameron Robinson
|
||
|
*/
|
||
|
var DOMObjectTag;
|
||
|
(function (DOMObjectTag) {
|
||
|
DOMObjectTag[DOMObjectTag["none"] = 0] = "none";
|
||
|
DOMObjectTag[DOMObjectTag["startRegion"] = 1] = "startRegion";
|
||
|
DOMObjectTag[DOMObjectTag["regionSettings"] = 2] = "regionSettings";
|
||
|
DOMObjectTag[DOMObjectTag["columnBreak"] = 3] = "columnBreak";
|
||
|
DOMObjectTag[DOMObjectTag["endRegion"] = 4] = "endRegion";
|
||
|
})(DOMObjectTag || (DOMObjectTag = {}));
|
||
|
class DOMObject {
|
||
|
constructor(nodeKey, element, randomID = getUID(), tag = DOMObjectTag.none) {
|
||
|
this.nodeKey = nodeKey;
|
||
|
this.element = element;
|
||
|
this.UID = randomID;
|
||
|
this.tag = tag;
|
||
|
}
|
||
|
}
|
||
|
class DOMRegionSettingsObject extends DOMObject {
|
||
|
constructor(baseDOMObject, regionSettings) {
|
||
|
super(baseDOMObject.nodeKey, baseDOMObject.element, baseDOMObject.UID, DOMObjectTag.regionSettings);
|
||
|
this.regionSettings = regionSettings;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* File: multi-column-markdown/src/domManager.ts
|
||
|
* Created Date: Saturday, January 30th 2022, 3:16:32 pm
|
||
|
* Author: Cameron Robinson
|
||
|
*
|
||
|
* Copyright (c) 2022 Cameron Robinson
|
||
|
*/
|
||
|
class GlobalDOMManager {
|
||
|
constructor() {
|
||
|
this.managers = new Map();
|
||
|
}
|
||
|
removeFileManagerCallback(key) {
|
||
|
if (this.managers.has(key) === true) {
|
||
|
this.managers.delete(key);
|
||
|
}
|
||
|
}
|
||
|
getFileManager(key) {
|
||
|
let fileManager = null;
|
||
|
if (this.managers.has(key) === true) {
|
||
|
fileManager = this.managers.get(key);
|
||
|
}
|
||
|
else {
|
||
|
fileManager = createFileDOMManager(this, key);
|
||
|
this.managers.set(key, fileManager);
|
||
|
}
|
||
|
return fileManager;
|
||
|
}
|
||
|
}
|
||
|
function createFileDOMManager(parentManager, fileKey) {
|
||
|
let regionMap = new Map();
|
||
|
let hasStartTag = false;
|
||
|
function removeRegion(regionKey) {
|
||
|
let regionManager = regionMap.get(regionKey);
|
||
|
if (regionManager) {
|
||
|
regionManager.displayOriginalElements();
|
||
|
}
|
||
|
regionMap.delete(regionKey);
|
||
|
if (regionMap.size === 0) {
|
||
|
parentManager.removeFileManagerCallback(fileKey);
|
||
|
}
|
||
|
}
|
||
|
function createRegionalManager(regionKey, errorElement, regionElement) {
|
||
|
//TODO: Use the error element whenever there is an error.
|
||
|
let regonalManager = createRegionalDomManager(this, regionKey, regionElement);
|
||
|
regionMap.set(regionKey, regonalManager);
|
||
|
return regonalManager;
|
||
|
}
|
||
|
function getRegionalManager(regionKey) {
|
||
|
let regonalManager = null;
|
||
|
if (regionMap.has(regionKey) === true) {
|
||
|
regonalManager = regionMap.get(regionKey);
|
||
|
}
|
||
|
return regonalManager;
|
||
|
}
|
||
|
function setHasStartTag() {
|
||
|
hasStartTag = true;
|
||
|
}
|
||
|
function getHasStartTag() {
|
||
|
return hasStartTag;
|
||
|
}
|
||
|
function getNumberOfRegions() {
|
||
|
return regionMap.size;
|
||
|
}
|
||
|
function checkKeyExists(checkKey) {
|
||
|
return regionMap.has(checkKey);
|
||
|
}
|
||
|
return { regionMap: regionMap,
|
||
|
hasStartTag: hasStartTag,
|
||
|
createRegionalManager: createRegionalManager,
|
||
|
getRegionalManager: getRegionalManager,
|
||
|
removeRegion: removeRegion,
|
||
|
setHasStartTag: setHasStartTag,
|
||
|
getHasStartTag: getHasStartTag,
|
||
|
getNumberOfRegions: getNumberOfRegions,
|
||
|
checkKeyExists: checkKeyExists
|
||
|
};
|
||
|
}
|
||
|
function createRegionalDomManager(fileManager, regionKey, startRegionElement) {
|
||
|
/**
|
||
|
* We use a list and a map to help keep track of the objects. Requires
|
||
|
* more memory but makes processing things a little cleaner and presumably
|
||
|
* faster.
|
||
|
*
|
||
|
* Use the map to look up object by key and the list is used to track objects
|
||
|
* in the order they are in the document.
|
||
|
*/
|
||
|
let domList = [];
|
||
|
let domObjectMap = new Map();
|
||
|
let regionParent = startRegionElement;
|
||
|
let regionSettings = [];
|
||
|
function addObject(siblingsAbove, obj) {
|
||
|
let addAtIndex = siblingsAbove.children.length;
|
||
|
// console.log("Attempting to add:", obj, `at index: ${addAtIndex}`);
|
||
|
domList.splice(addAtIndex, 0, obj);
|
||
|
domObjectMap.set(obj.UID, obj);
|
||
|
// /**
|
||
|
// * Make a copy of the list to log, only because
|
||
|
// * console log updates its references with updates in memory.
|
||
|
// */
|
||
|
// let x = domList.slice(0);
|
||
|
// console.log(x);
|
||
|
return addAtIndex;
|
||
|
}
|
||
|
function removeObject(objectUID) {
|
||
|
// /**
|
||
|
// * Make a copy of the list to log
|
||
|
// */
|
||
|
// let x = domList.slice(0);
|
||
|
// console.log(x);
|
||
|
// Get the object by key, remove it from the map and then
|
||
|
// from the list.
|
||
|
let obj = domObjectMap.get(objectUID);
|
||
|
domObjectMap.delete(objectUID);
|
||
|
if (domList.contains(obj)) {
|
||
|
domList.remove(obj);
|
||
|
}
|
||
|
// If the object is a settings object we need to remove from the
|
||
|
// settings list.
|
||
|
if (obj.tag === DOMObjectTag.regionSettings) {
|
||
|
let settingsObj = obj;
|
||
|
if (regionSettings.contains(settingsObj)) {
|
||
|
regionSettings.remove(settingsObj);
|
||
|
}
|
||
|
}
|
||
|
if (domList.length === 0) {
|
||
|
fileManager.removeRegion(regionKey);
|
||
|
}
|
||
|
// x = domList.slice(0);
|
||
|
// console.log(x);
|
||
|
}
|
||
|
function updateElementTag(objectUID, newTag) {
|
||
|
let obj = domObjectMap.get(objectUID);
|
||
|
let index = domList.indexOf(obj);
|
||
|
if (index !== -1) {
|
||
|
domList[index].tag = newTag;
|
||
|
}
|
||
|
}
|
||
|
function setElementToSettingsBlock(objectUID, settingsText) {
|
||
|
let obj = domObjectMap.get(objectUID);
|
||
|
let index = domList.indexOf(obj);
|
||
|
if (index !== -1) {
|
||
|
let settings = parseColumnSettings(settingsText);
|
||
|
let regionSettingsObj = new DOMRegionSettingsObject(domList[index], settings);
|
||
|
domObjectMap.set(regionSettingsObj.UID, regionSettingsObj);
|
||
|
domList[index] = regionSettingsObj;
|
||
|
regionSettings.push(regionSettingsObj);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Creates an object containing all necessary information for the region
|
||
|
* to be rendered to the preview pane.
|
||
|
*
|
||
|
* @returns a MultiColumnRenderData object with the root DOM element, settings object, and
|
||
|
* all child objects in the order they should be rendered.
|
||
|
*/
|
||
|
function getRegionRenderData() {
|
||
|
// Set defaults before attempting to get settings.
|
||
|
let settings = { numberOfColumns: 2, columnLayout: ColumnLayout.standard, drawBorder: true, drawShadow: true };
|
||
|
if (regionSettings.length > 0) {
|
||
|
/**
|
||
|
* Since we append settings onto the end of the array we want the last
|
||
|
* item in the array as that would be the most recent settings we parsed.
|
||
|
*/
|
||
|
settings = regionSettings[regionSettings.length - 1].regionSettings;
|
||
|
}
|
||
|
return {
|
||
|
parentRenderElement: regionParent,
|
||
|
parentRenderSettings: settings,
|
||
|
domObjects: domList
|
||
|
};
|
||
|
}
|
||
|
/**
|
||
|
* This fuction is called when a start tag is removed from view meaning
|
||
|
* our parent element storing the multi-column region is removed. It
|
||
|
* removes the CSS class from all of the elements so they will be
|
||
|
* re-rendered in the preview window.
|
||
|
*/
|
||
|
function displayOriginalElements() {
|
||
|
for (let i = 0; i < domList.length; i++) {
|
||
|
domList[i].element.removeClass("multiColumnDataHidden");
|
||
|
}
|
||
|
for (let i = 0; i < regionSettings.length; i++) {
|
||
|
regionSettings[i].element.removeClass("multiColumnDataHidden");
|
||
|
}
|
||
|
}
|
||
|
return { addObject: addObject,
|
||
|
removeObject: removeObject,
|
||
|
updateElementTag: updateElementTag,
|
||
|
setElementToSettingsBlock: setElementToSettingsBlock,
|
||
|
getRegionRenderData: getRegionRenderData,
|
||
|
displayOriginalElements: displayOriginalElements
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* File: multi-column-markdown/src/main.ts
|
||
|
* Created Date: Tuesday, October 5th 2021, 1:09 pm
|
||
|
* Author: Cameron Robinson
|
||
|
*
|
||
|
* Copyright (c) 2022 Cameron Robinson
|
||
|
*/
|
||
|
class MultiColumnMarkdown extends obsidian.Plugin {
|
||
|
constructor() {
|
||
|
// settings: SplitColumnMarkdownSettings;
|
||
|
super(...arguments);
|
||
|
this.globalManager = new GlobalDOMManager();
|
||
|
}
|
||
|
onload() {
|
||
|
return __awaiter(this, void 0, void 0, function* () {
|
||
|
console.log("Loading multi-column markdown");
|
||
|
this.setupMarkdownPostProcessor();
|
||
|
//TODO: Set up this as a modal to set settings automatically
|
||
|
this.addCommand({
|
||
|
id: `insert-multi-column-region`,
|
||
|
name: `Insert Multi-Column Region`,
|
||
|
editorCallback: (editor, view) => {
|
||
|
try {
|
||
|
editor.getDoc().replaceSelection(`
|
||
|
=== multi-column-start: ID_${getUID(4)}
|
||
|
\`\`\`column-settings
|
||
|
Number of Columns: 2
|
||
|
Largest Column: standard
|
||
|
\`\`\`
|
||
|
|
||
|
=== end-column ===
|
||
|
|
||
|
=== multi-column-end
|
||
|
|
||
|
${editor.getDoc().getSelection()}`);
|
||
|
}
|
||
|
catch (e) {
|
||
|
new obsidian.Notice("Encountered an error inserting a multi-column region. Please try again later.");
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
this.addCommand({
|
||
|
id: `add-IDs-To-multi-column-region`,
|
||
|
name: `Fix Missing IDs for Multi-Column Regions`,
|
||
|
editorCallback: (editor, view) => {
|
||
|
try {
|
||
|
/**
|
||
|
* Not sure if there is an easier way to do this.
|
||
|
*
|
||
|
* Get all of the lines of the document split by newlines.
|
||
|
*/
|
||
|
let lines = editor.getRange({ line: 0, ch: 0 }, { line: editor.getDoc().lineCount(), ch: 0 }).split("\n");
|
||
|
/**
|
||
|
* Loop through all of the lines checking if the line is a
|
||
|
* start tag and if so is it missing an ID.
|
||
|
*/
|
||
|
let linesWithoutIDs = [];
|
||
|
let textWithoutIDs = [];
|
||
|
for (let i = 0; i < lines.length; i++) {
|
||
|
let data = isStartTagWithID(lines[i]);
|
||
|
if (data.isStartTag === true && data.hasKey === false) {
|
||
|
linesWithoutIDs.push(i);
|
||
|
textWithoutIDs.push(lines[i]);
|
||
|
}
|
||
|
}
|
||
|
if (linesWithoutIDs.length === 0) {
|
||
|
new obsidian.Notice("Found 0 missing IDs in the current document.");
|
||
|
return;
|
||
|
}
|
||
|
/**
|
||
|
* Now loop through each line that is missing an ID and
|
||
|
* generate a random ID and replace the original text.
|
||
|
*/
|
||
|
for (let i = 0; i < linesWithoutIDs.length; i++) {
|
||
|
let originalText = textWithoutIDs[i];
|
||
|
let text = originalText;
|
||
|
text = text.trimEnd();
|
||
|
if (text.charAt(text.length - 1) === ":") {
|
||
|
text = text.slice(0, text.length - 1);
|
||
|
}
|
||
|
text = `${text}: ID_${getUID(4)}`;
|
||
|
editor.replaceRange(text, { line: linesWithoutIDs[i], ch: 0 }, { line: linesWithoutIDs[i], ch: originalText.length });
|
||
|
}
|
||
|
new obsidian.Notice(`Replaced ${linesWithoutIDs.length} missing ID(s) in the current document.`);
|
||
|
}
|
||
|
catch (e) {
|
||
|
new obsidian.Notice("Encountered an error addign IDs to multi-column regions. Please try again later.");
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
setupMarkdownPostProcessor() {
|
||
|
this.registerMarkdownPostProcessor((el, ctx) => __awaiter(this, void 0, void 0, function* () {
|
||
|
// Get the info for our current context and then check
|
||
|
// if the entire text contains a start tag. If there is
|
||
|
// no start tag in the document we can just return and
|
||
|
// ignore the rest of the parsing.
|
||
|
let info = ctx.getSectionInfo(el);
|
||
|
/**
|
||
|
* We need the context info to properly parse so returning here
|
||
|
* info is null. TODO: Set error in view if this occurs.
|
||
|
*/
|
||
|
if (!info) {
|
||
|
return;
|
||
|
}
|
||
|
const sourcePath = ctx.sourcePath;
|
||
|
let fileDOMManager = this.globalManager.getFileManager(sourcePath);
|
||
|
if (fileDOMManager === null) {
|
||
|
console.log("Found null DOM manager. Could not process multi-column markdown.");
|
||
|
return;
|
||
|
}
|
||
|
/**
|
||
|
* If we encounter a start tag on the document we set the flag to start
|
||
|
* parsing the rest of the document.
|
||
|
*/
|
||
|
if (containsStartTag(el.textContent)) {
|
||
|
fileDOMManager.setHasStartTag();
|
||
|
}
|
||
|
/**
|
||
|
* If the document does not contain any start tags we ignore the
|
||
|
* rest of the parsing. This is only set to true once the first
|
||
|
* start tag element is parsed above.
|
||
|
*/
|
||
|
if (fileDOMManager.getHasStartTag() === false) {
|
||
|
return;
|
||
|
}
|
||
|
/**
|
||
|
* Take the info provided and generate the required variables from
|
||
|
* the line start and end values.
|
||
|
*/
|
||
|
let linesOfElement = info.text.split("\n").splice(info.lineStart, (info.lineEnd + 1 - info.lineStart));
|
||
|
let elementTextSpaced = linesOfElement.reduce((prev, curr) => {
|
||
|
return prev + "\n" + curr;
|
||
|
});
|
||
|
let elementText = linesOfElement.reduce((prev, curr) => {
|
||
|
// TODO: This can probably be removed as it is only used to identify DOMObjects.
|
||
|
return prev + curr;
|
||
|
});
|
||
|
/**
|
||
|
* If the current line is a start tag we want to set up the
|
||
|
* region manager. The regional manager takes care
|
||
|
* of all items between it's start and end tags while the
|
||
|
* file manager we got above above takes care of all regional
|
||
|
* managers in each file.
|
||
|
*/
|
||
|
if (containsStartTag(el.textContent)) {
|
||
|
/**
|
||
|
* Set up the current element to act as the parent for the
|
||
|
* multi-column region.
|
||
|
*/
|
||
|
el.id = `TwoColumnContainer-${getUID()}`;
|
||
|
el.children[0].detach();
|
||
|
el.classList.add("multiColumnContainer");
|
||
|
let renderErrorRegion = el.createDiv({
|
||
|
cls: `multiColumnErrorMessage`,
|
||
|
});
|
||
|
let renderColumnRegion = el.createDiv({
|
||
|
cls: `RenderColRegion`
|
||
|
});
|
||
|
let startBlockData = getStartBlockAboveLine(linesOfElement);
|
||
|
let regionKey = startBlockData.startBlockKey;
|
||
|
if (fileDOMManager.checkKeyExists(regionKey) === true) {
|
||
|
let { numberOfTags, keys } = countStartTags(info.text);
|
||
|
let index = 0;
|
||
|
for (; index < numberOfTags; index++) {
|
||
|
// Because we checked if key exists one of these has to match.
|
||
|
if (keys[index] === regionKey) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (keys[index] === "") {
|
||
|
renderErrorRegion.innerText = "Found multiple regions with empty IDs. Please set a unique ID after each start tag.\nEG: '=== multi-column-start: randomID'\nOr use 'Fix Missing IDs' in the command palette and reload the document.";
|
||
|
}
|
||
|
else {
|
||
|
renderErrorRegion.innerText = "Region ID already exists in document, please set a unique ID.\nEG: '=== multi-column-start: randomID'";
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
let elementMarkdownRenderer = new obsidian.MarkdownRenderChild(el);
|
||
|
fileDOMManager.createRegionalManager(regionKey, renderErrorRegion, renderColumnRegion);
|
||
|
elementMarkdownRenderer.onunload = () => {
|
||
|
if (fileDOMManager) {
|
||
|
fileDOMManager.removeRegion(startBlockData.startBlockKey);
|
||
|
}
|
||
|
};
|
||
|
ctx.addChild(elementMarkdownRenderer);
|
||
|
/**
|
||
|
* Now we have created our regional manager and defined what elements
|
||
|
* need to be rendered into. So we can return without any more processing.
|
||
|
*/
|
||
|
return;
|
||
|
}
|
||
|
/**
|
||
|
* Get a list of all of the lines above our current element.
|
||
|
* We will use this to determine if the element is within a block so
|
||
|
* we can otherwise ignore the element and keep compute time down.
|
||
|
*/
|
||
|
let linesAboveArray = info.text.split("\n").slice(0, info.lineStart);
|
||
|
linesAboveArray.reduce((prev, curr) => {
|
||
|
return prev + "\n" + curr;
|
||
|
}, "");
|
||
|
/**
|
||
|
* A line above us contains a start tag now see if we're within that
|
||
|
* block.
|
||
|
*/
|
||
|
let startBockAbove = getStartBlockAboveLine(linesAboveArray);
|
||
|
if (startBockAbove == null) {
|
||
|
return;
|
||
|
}
|
||
|
/**
|
||
|
* Here we now know we're within a regional block.
|
||
|
*/
|
||
|
// Now we only want to work with the lines within the current region.
|
||
|
linesAboveArray = startBockAbove.linesAboveArray;
|
||
|
let regionalManager = fileDOMManager.getRegionalManager(startBockAbove.startBlockKey);
|
||
|
/**
|
||
|
* If we can not get the start block and this region's dom manager
|
||
|
* we can not continue something has gone wrong.
|
||
|
*/
|
||
|
if (regionalManager === null) {
|
||
|
return;
|
||
|
}
|
||
|
/**
|
||
|
* Now we take the lines above our current element up until the
|
||
|
* start region tag and render that into an HTML element. We will
|
||
|
* use this element to determine where to place our current element.
|
||
|
*/
|
||
|
let siblingsAbove = findSiblingsAboveEl(linesAboveArray, sourcePath);
|
||
|
/**
|
||
|
* Set up our dom object to be added to the manager.
|
||
|
*/
|
||
|
let currentObject = new DOMObject(elementText, el);
|
||
|
/**
|
||
|
* Now we add the object to the manager and then setup the
|
||
|
* callback for when the object is removed from view that will remove
|
||
|
* the item from the manager.
|
||
|
*/
|
||
|
regionalManager.addObject(siblingsAbove, currentObject);
|
||
|
let elementMarkdownRenderer = new obsidian.MarkdownRenderChild(el);
|
||
|
elementMarkdownRenderer.onunload = () => {
|
||
|
if (regionalManager) {
|
||
|
// We can attempt to update the view here after the item is removed
|
||
|
// but need to get the item's parent element before removing object from manager.
|
||
|
let regionRenderData = regionalManager.getRegionRenderData();
|
||
|
regionalManager.removeObject(currentObject.UID);
|
||
|
/**
|
||
|
* Need to check here if element is null as this closure will be called
|
||
|
* repeatedly on file change.
|
||
|
*/
|
||
|
if (regionRenderData.parentRenderElement === null) {
|
||
|
return;
|
||
|
}
|
||
|
this.renderColumnMarkdown(regionRenderData.parentRenderElement, regionRenderData.domObjects, regionRenderData.parentRenderSettings);
|
||
|
}
|
||
|
};
|
||
|
ctx.addChild(elementMarkdownRenderer);
|
||
|
/**
|
||
|
* Now we check if our current element is a special flag so we can
|
||
|
* properly set the element tag within the regional manager.
|
||
|
*/
|
||
|
if (containsEndTag(el.textContent) === true) {
|
||
|
regionalManager.updateElementTag(currentObject.UID, DOMObjectTag.endRegion);
|
||
|
}
|
||
|
else if (containsColEndTag(elementTextSpaced) === true) {
|
||
|
regionalManager.updateElementTag(currentObject.UID, DOMObjectTag.columnBreak);
|
||
|
}
|
||
|
else if (containsColSettingsTag(elementTextSpaced) === true) {
|
||
|
regionalManager.setElementToSettingsBlock(currentObject.UID, elementTextSpaced);
|
||
|
}
|
||
|
/**
|
||
|
* Use our regional manager to get everything needed to render the region.
|
||
|
*/
|
||
|
let parentElementData = regionalManager.getRegionRenderData();
|
||
|
/**
|
||
|
* We want to hide all of the original elements that are now going to be
|
||
|
* rendered within our mutli-column region
|
||
|
*/
|
||
|
el.addClass("multiColumnDataHidden");
|
||
|
this.renderColumnMarkdown(parentElementData.parentRenderElement, parentElementData.domObjects, parentElementData.parentRenderSettings);
|
||
|
return;
|
||
|
}));
|
||
|
}
|
||
|
/**
|
||
|
* This function takes in the data for the multi-column region and sets up the
|
||
|
* user defined number of children with the proper css classes to be rendered properly.
|
||
|
*
|
||
|
* @param parentElement The element that the multi-column region will be rendered under.
|
||
|
* @param regionElements The list of DOM objects that will be coppied under the parent object
|
||
|
* @param settings The settings the user has defined for the region.
|
||
|
*/
|
||
|
renderColumnMarkdown(parentElement, regionElements, settings) {
|
||
|
let multiColumnParent = createDiv({
|
||
|
cls: `multiColumnParent rowC`,
|
||
|
});
|
||
|
if (settings.drawShadow === true) {
|
||
|
multiColumnParent.addClass("multiColumnParentShadow");
|
||
|
}
|
||
|
/**
|
||
|
* Pass our parent div and settings to parser to create the required
|
||
|
* column divs as children of the parent.
|
||
|
*/
|
||
|
let columnContentDivs = getColumnContentDivs(settings, multiColumnParent);
|
||
|
for (let i = 0; i < columnContentDivs.length; i++) {
|
||
|
if (settings.drawBorder === true) {
|
||
|
columnContentDivs[i].addClass("columnBorder");
|
||
|
}
|
||
|
if (settings.drawShadow === true) {
|
||
|
columnContentDivs[i].addClass("columnShadow");
|
||
|
}
|
||
|
}
|
||
|
// Create markdown renderer to parse the passed markdown
|
||
|
// between the tags.
|
||
|
let markdownRenderChild = new obsidian.MarkdownRenderChild(multiColumnParent);
|
||
|
// Remove every other child from the parent so
|
||
|
// we dont end up with multiple sets of data. This should
|
||
|
// really only need to loop once for i = 0 but loop just
|
||
|
// in case.
|
||
|
for (let i = parentElement.children.length - 1; i >= 0; i--) {
|
||
|
parentElement.children[i].detach();
|
||
|
}
|
||
|
parentElement.appendChild(markdownRenderChild.containerEl);
|
||
|
let columnIndex = 0;
|
||
|
for (let i = 0; i < regionElements.length; i++) {
|
||
|
// We want to skip column break tags but only if we have columns
|
||
|
// left to enter data for.
|
||
|
if (regionElements[i].tag === DOMObjectTag.columnBreak &&
|
||
|
(columnIndex + 1) < settings.numberOfColumns) {
|
||
|
columnIndex++;
|
||
|
}
|
||
|
else if (regionElements[i].tag !== DOMObjectTag.startRegion &&
|
||
|
regionElements[i].tag !== DOMObjectTag.endRegion &&
|
||
|
regionElements[i].tag !== DOMObjectTag.regionSettings) {
|
||
|
/**
|
||
|
* Make a deep copy of the element so we can remove the hidden class before
|
||
|
* appending to our column div.
|
||
|
*/
|
||
|
let clonedElement = regionElements[i].element.cloneNode(true);
|
||
|
clonedElement.removeClass("multiColumnDataHidden");
|
||
|
clonedElement.style.display = "block";
|
||
|
columnContentDivs[columnIndex].appendChild(clonedElement);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Sets up the CSS classes and the number of columns based on the passed settings.
|
||
|
* @param settings The user defined settings that determine what CSS is set here.
|
||
|
* @param multiColumnParent The parent object that the column divs will be created under.
|
||
|
* @returns The list of column divs created under the passed parent element.
|
||
|
*/
|
||
|
function getColumnContentDivs(settings, multiColumnParent) {
|
||
|
let columnContentDivs = [];
|
||
|
if (settings.numberOfColumns === 2) {
|
||
|
switch (settings.columnLayout) {
|
||
|
case (ColumnLayout.standard):
|
||
|
case (ColumnLayout.middle):
|
||
|
case (ColumnLayout.center):
|
||
|
case (ColumnLayout.third):
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent twoEqualColumns_Left`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent twoEqualColumns_Right`
|
||
|
}));
|
||
|
break;
|
||
|
case (ColumnLayout.left):
|
||
|
case (ColumnLayout.first):
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent twoColumnsHeavyLeft_Left`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent twoColumnsHeavyLeft_Right`
|
||
|
}));
|
||
|
break;
|
||
|
case (ColumnLayout.right):
|
||
|
case (ColumnLayout.second):
|
||
|
case (ColumnLayout.last):
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent twoColumnsHeavyRight_Left`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent twoColumnsHeavyRight_Right`
|
||
|
}));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else if (settings.numberOfColumns === 3) {
|
||
|
switch (settings.columnLayout) {
|
||
|
case (ColumnLayout.standard):
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threeEqualColumns_Left`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threeEqualColumns_Middle`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threeEqualColumns_Right`
|
||
|
}));
|
||
|
break;
|
||
|
case (ColumnLayout.left):
|
||
|
case (ColumnLayout.first):
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyLeft_Left`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyLeft_Middle`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyLeft_Right`
|
||
|
}));
|
||
|
break;
|
||
|
case (ColumnLayout.middle):
|
||
|
case (ColumnLayout.center):
|
||
|
case (ColumnLayout.second):
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyMiddle_Left`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyMiddle_Middle`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyMiddle_Right`
|
||
|
}));
|
||
|
break;
|
||
|
case (ColumnLayout.right):
|
||
|
case (ColumnLayout.third):
|
||
|
case (ColumnLayout.last):
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyRight_Left`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyRight_Middle`
|
||
|
}));
|
||
|
columnContentDivs.push(multiColumnParent.createDiv({
|
||
|
cls: `columnContent threColumnsHeavyRight_Right`
|
||
|
}));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return columnContentDivs;
|
||
|
}
|
||
|
function findSiblingsAboveEl(linesAbove, sourcePath) {
|
||
|
/**
|
||
|
* We re-render all of the items above our element, until the start tag,
|
||
|
* so we can determine where to place the new item in the manager.
|
||
|
*
|
||
|
* TODO: Can reduce the amount needing to be rendered by only rendering to
|
||
|
* the start tag or a column-break whichever is closer.
|
||
|
*/
|
||
|
let siblingsAbove = createDiv();
|
||
|
let markdownRenderChild = new obsidian.MarkdownRenderChild(siblingsAbove);
|
||
|
obsidian.MarkdownRenderer.renderMarkdown(linesAbove.reduce((prev, current) => {
|
||
|
return prev + "\n" + current;
|
||
|
}, ""), siblingsAbove, sourcePath, markdownRenderChild);
|
||
|
return siblingsAbove;
|
||
|
}
|
||
|
|
||
|
module.exports = MultiColumnMarkdown;
|
||
|
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsInNyYy9yZWdpb25TZXR0aW5ncy50cyIsInNyYy91dGlsaXRpZXMvdGV4dFBhcnNlci50cyIsInNyYy91dGlsaXRpZXMvdXRpbHMudHMiLCJzcmMvZG9tX21hbmFnZXIvZG9tT2JqZWN0LnRzIiwic3JjL2RvbV9tYW5hZ2VyL2RvbU1hbmFnZXIudHMiLCJzcmMvbWFpbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiEgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uXHJcblxyXG5QZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBhbmQvb3IgZGlzdHJpYnV0ZSB0aGlzIHNvZnR3YXJlIGZvciBhbnlcclxucHVycG9zZSB3aXRoIG9yIHdpdGhvdXQgZmVlIGlzIGhlcmVieSBncmFudGVkLlxyXG5cclxuVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiBBTkQgVEhFIEFVVEhPUiBESVNDTEFJTVMgQUxMIFdBUlJBTlRJRVMgV0lUSFxyXG5SRUdBUkQgVE8gVEhJUyBTT0ZUV0FSRSBJTkNMVURJTkcgQUxMIElNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFlcclxuQU5EIEZJVE5FU1MuIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1IgQkUgTElBQkxFIEZPUiBBTlkgU1BFQ0lBTCwgRElSRUNULFxyXG5JTkRJUkVDVCwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIE9SIEFOWSBEQU1BR0VTIFdIQVRTT0VWRVIgUkVTVUxUSU5HIEZST01cclxuTE9TUyBPRiBVU0UsIERBVEEgT1IgUFJPRklUUywgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIE5FR0xJR0VOQ0UgT1JcclxuT1RIRVIgVE9SVElPVVMgQUNUSU9OLCBBUklTSU5HIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFVTRSBPUlxyXG5QRVJGT1JNQU5DRSBPRiBUSElTIFNPRlRXQVJFLlxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAqL1xyXG4vKiBnbG9iYWwgUmVmbGVjdCwgUHJvbWlzZSAqL1xyXG5cclxudmFyIGV4dGVuZFN0YXRpY3MgPSBmdW5jdGlvbihkLCBiKSB7XHJcbiAgICBleHRlbmRTdGF0aWNzID0gT2JqZWN0LnNldFByb3RvdHlwZU9mIHx8XHJcbiAgICAgICAgKHsgX19wcm90b19fOiBbXSB9IGluc3RhbmNlb2YgQXJyYXkgJiYgZnVuY3Rpb24gKGQsIGIpIHsgZC5fX3Byb3RvX18gPSBiOyB9KSB8fFxyXG4gICAgICAgIGZ1bmN0aW9uIChkLCBiKSB7IGZvciAodmFyIHAgaW4gYikgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChiLCBwKSkgZFtwXSA9IGJbcF07IH07XHJcbiAgICByZXR1cm4gZXh0ZW5kU3RhdGljcyhkLCBiKTtcclxufTtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2V4dGVuZHMoZCwgYikge1xyXG4gICAgaWYgKHR5cGVvZiBiICE9PSBcImZ1bmN0aW9uXCIgJiYgYiAhPT0gbnVsbClcclxuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2xhc3MgZXh0ZW5kcyB2YWx1ZSBcIiArIFN0cmluZyhiKSArIFwiIGlzIG5vdCBhIGNvbnN0cnVjdG9yIG9yIG51bGxcIik7XHJcbiAgICBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG4gICAgZnVuY3Rpb24gX18oKSB7IHRoaXMuY29uc3RydWN0b3IgPSBkOyB9XHJcbiAgICBkLnByb3RvdHlwZSA9IGIgPT09IG51bGwgPyBPYmplY3QuY3JlYXRlKGIpIDogKF9fLnByb3RvdHlwZSA9IGIucHJvdG90eXBlLCBuZXcgX18oKSk7XHJcbn1cclxuXHJcbmV4cG9ydCB2YXIgX19hc3NpZ24gPSBmdW5jdGlvbigpIHtcclxuICAgIF9fYXNzaWduID0gT2JqZWN0LmFzc2lnbiB8fCBmdW5jdGlvbiBfX2Fzc2lnbih0KSB7XHJcbiAgICAgICAgZm9yICh2YXIgcywgaSA9IDEsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XHJcbiAgICAgICAgICAgIHMgPSBhcmd1bWVudHNbaV07XHJcbiAgICAgICAgICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSkgdFtwXSA9IHNbcF07XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB0O1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIF9fYXNzaWduLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX3Jlc3QocywgZSkge1xyXG4gICAgdmFyIHQgPSB7fTtcclxuICAgIGZvciAodmFyIHAgaW4gcykgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzLCBwKSAmJiBlLmluZGV4T2YocCkgPCAwKVxyXG4gICAgICAgIHRbcF0gPSBzW3BdO1xyXG4gICAgaWYgKHMgIT0gbnVsbCAmJiB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyA9PT0gXCJmdW5jdGlvblwiKVxyXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBwID0gT2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhzKTsgaSA8IHAubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgaWYgKGUuaW5kZXhPZihwW2ldKSA8IDAgJiYgT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKHMsIHBbaV0pKVxyXG4gICAgICAgICAgICAgICAgdFtwW2ldXSA9IHNbcFtpXV07XHJcbiAgICAgICAgfVxyXG4gICAgcmV0dXJuIHQ7XHJcbn1cclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBfX2RlY29yYXRlKGRlY29yYXRvcnMsIHRhcmdldCwga2V5LCBkZXNjKSB7XHJcbiAgICB2YXIgYyA9IGFyZ3VtZW50cy5sZW5ndGgsIHIgPSBjIDwgMyA/IHRhcmdldCA6IGRlc2MgPT09IG51bGwgPyBkZXNjID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0YXJnZXQsIGtleSkgOiBkZXNjLCBkO1xyXG4gICAgaWYgKHR5cGVvZiBSZWZsZWN0ID09PSBcIm9iamVjdFwiICYmIHR5cGVvZiBSZWZsZWN0LmRlY29yYXRlID09PSBcImZ1bmN0aW9uXCIpIHIgPSBSZWZ
|