/ *
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 1 st 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 22 nd 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 getEndBlockBelow ( linesBelow ) {
// 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 linesBelowStr = linesBelow . reduce ( ( prev , current ) => {
return prev + "\n" + current ;
} , "" ) ;
let endTagSerachData = findEndTag ( linesBelowStr ) ;
let startTagSearchData = findStartTag ( linesBelowStr ) ;
let sliceEndIndex = - 1 ; // If neither start or end found we return the entire array.
if ( endTagSerachData . found === true && startTagSearchData . found === false ) {
sliceEndIndex = endTagSerachData . startPosition ;
}
else if ( endTagSerachData . found === false && startTagSearchData . found === true ) {
sliceEndIndex = startTagSearchData . startPosition ;
}
else if ( endTagSerachData . found === true && startTagSearchData . found === true ) {
sliceEndIndex = endTagSerachData . startPosition ;
if ( startTagSearchData . startPosition < endTagSerachData . startPosition ) {
/ * *
* If we found a start tag before an end tag we want to use the start tag
* our current block is not properly ended and we use the next start tag
* as our limit
* /
sliceEndIndex = startTagSearchData . startPosition ;
}
}
return linesBelow . slice ( 0 , sliceEndIndex ) ;
}
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 30 th 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 ;
}
var ElementRenderType ;
( function ( ElementRenderType ) {
ElementRenderType [ ElementRenderType [ "undefined" ] = 0 ] = "undefined" ;
ElementRenderType [ ElementRenderType [ "normalRender" ] = 1 ] = "normalRender" ;
ElementRenderType [ ElementRenderType [ "specialRender" ] = 2 ] = "specialRender" ;
} ) ( ElementRenderType || ( ElementRenderType = { } ) ) ;
function getElementRenderType ( element ) {
/ * *
* Look for specific kinds of elements by their CSS class names here . These
* are going to be brittle links as they rely on other plugin definitions but
* as this is only adding in extra compatability to the plugins defined here
* it should be ok .
*
* These may be classes on one of the simple elements ( such as a paragraph )
* that we search for below so need to look for these first .
* /
if ( hasDiceRoller ( element ) === true ) {
return ElementRenderType . specialRender ;
}
if ( hasAdmonition ( element ) === true ) {
return ElementRenderType . normalRender ;
}
/ * *
* If we didnt find a special element we want to check for simple elements
* such as paragraphs or lists . In the current implementation we only set up
* the special case for "specialRender" elements so this * should * be saving
* some rendering time by setting these tags properly .
* /
if ( hasParagraph ( element ) ||
hasHeader ( element ) ||
hasList ( element ) ) {
return ElementRenderType . normalRender ;
}
// If still nothing found we return other as the default response if nothing else found.
return ElementRenderType . specialRender ;
}
function hasParagraph ( element ) {
return element . innerHTML . startsWith ( "<p" ) ;
}
function hasHeader ( element ) {
if ( element . innerHTML . startsWith ( "<h1" ) ||
element . innerHTML . startsWith ( "<h2" ) ||
element . innerHTML . startsWith ( "<h3" ) ||
element . innerHTML . startsWith ( "<h4" ) ||
element . innerHTML . startsWith ( "<h5" ) ) {
return true ;
}
return false ;
}
function hasList ( element ) {
if ( element . innerHTML . startsWith ( "<ul" ) ||
element . innerHTML . startsWith ( "<ol" ) ) {
return true ;
}
return false ;
}
function hasDiceRoller ( element ) {
return element . getElementsByClassName ( "dice-roller" ) . length !== 0 ;
}
function hasAdmonition ( element ) {
return element . getElementsByClassName ( "admonition" ) . length !== 0 ;
}
/ *
* Filename : multi - column - markdown / src / domObject . ts
* Created Date : Tuesday , February 1 st 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 ( element , randomID = getUID ( ) , tag = DOMObjectTag . none ) {
this . elementType = ElementRenderType . undefined ;
this . elementContainer = null ;
this . nodeKey = element . innerText . trim ( ) ;
this . element = element ;
this . UID = randomID ;
this . tag = tag ;
this . usingOriginalElement = false ;
}
setMainDOMElement ( domElement ) {
this . element = domElement ;
this . usingOriginalElement = true ;
}
}
class DOMRegionSettingsObject extends DOMObject {
constructor ( baseDOMObject , regionSettings ) {
super ( baseDOMObject . element , baseDOMObject . UID , DOMObjectTag . regionSettings ) ;
this . regionSettings = regionSettings ;
}
}
/ *
* File : multi - column - markdown / src / utilities / cssDefinitions . ts
* Created Date : Wednesday , February 16 th 2022 , 11 : 09 : 06 am
* Author : Cameron Robinson
*
* Copyright ( c ) 2022 Cameron Robinson
* /
var MultiColumnLayoutCSS ;
( function ( MultiColumnLayoutCSS ) {
MultiColumnLayoutCSS [ "RegionRootContainerDiv" ] = "multiColumnContainer" ;
MultiColumnLayoutCSS [ "RegionErrorContainerDiv" ] = "multiColumnErrorContainer" ;
MultiColumnLayoutCSS [ "RegionContentContainerDiv" ] = "RenderColRegion" ;
MultiColumnLayoutCSS [ "RegionColumnContainerDiv" ] = "multiColumnParent" ;
MultiColumnLayoutCSS [ "RegionColumnContent" ] = "columnContent" ;
MultiColumnLayoutCSS [ "ColumnDualElementContainer" ] = "MultiColumn_ElementContainer" ;
MultiColumnLayoutCSS [ "OriginalElementType" ] = "MultiColumn_OriginalElement" ;
MultiColumnLayoutCSS [ "ClonedElementType" ] = "MultiColumn_ClonedElement" ;
} ) ( MultiColumnLayoutCSS || ( MultiColumnLayoutCSS = { } ) ) ;
var MultiColumnStyleCSS ;
( function ( MultiColumnStyleCSS ) {
MultiColumnStyleCSS [ "RegionErrorMessage" ] = "multiColumnErrorMessage" ;
MultiColumnStyleCSS [ "RegionSettings" ] = "multiColumnSettings" ;
MultiColumnStyleCSS [ "RegionContent" ] = "multiColumnContent" ;
MultiColumnStyleCSS [ "RegionEndTag" ] = "multiColumnRegionEndTag" ;
MultiColumnStyleCSS [ "ColumnEndTag" ] = "multiColumnBreak" ;
MultiColumnStyleCSS [ "RegionShadow" ] = "multiColumnParentShadow" ;
MultiColumnStyleCSS [ "ColumnShadow" ] = "columnShadow" ;
MultiColumnStyleCSS [ "ColumnBorder" ] = "columnBorder" ;
} ) ( MultiColumnStyleCSS || ( MultiColumnStyleCSS = { } ) ) ;
/ *
* File : multi - column - markdown / src / domManager . ts
* Created Date : Saturday , January 30 th 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 ;
}
getAllFileManagers ( ) {
return Array . from ( this . managers . values ( ) ) ;
}
}
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 , rootElement , errorElement , renderRegionElement ) {
//TODO: Use the error element whenever there is an error.
let regonalManager = createRegionalDomManager ( this , regionKey , rootElement , renderRegionElement ) ;
regionMap . set ( regionKey , regonalManager ) ;
return regonalManager ;
}
function getRegionalManager ( regionKey ) {
let regonalManager = null ;
if ( regionMap . has ( regionKey ) === true ) {
regonalManager = regionMap . get ( regionKey ) ;
}
return regonalManager ;
}
function getAllRegionalManagers ( ) {
return Array . from ( regionMap . values ( ) ) ;
}
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 ,
getAllRegionalManagers : getAllRegionalManagers ,
removeRegion : removeRegion ,
setHasStartTag : setHasStartTag ,
getHasStartTag : getHasStartTag ,
getNumberOfRegions : getNumberOfRegions ,
checkKeyExists : checkKeyExists
} ;
}
function createRegionalDomManager ( fileManager , regionKey , rootElement , renderRegionElement ) {
/ * *
* 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 = renderRegionElement ;
let regionSettings = [ ] ;
function addObject ( siblingsAbove , siblingsBelow , obj ) {
let prevObj = siblingsAbove . children [ siblingsAbove . children . length - 1 ] ;
let nextObj = siblingsBelow . children [ 0 ] ;
let addAtIndex = siblingsAbove . children . length ;
if ( prevObj !== undefined ) {
for ( let i = domList . length - 1 ; i >= 0 ; i -- ) {
if ( domList [ i ] . nodeKey === prevObj . innerText ) {
addAtIndex = i + 1 ;
break ;
}
}
}
let nextElIndex = addAtIndex ;
if ( nextObj !== undefined ) {
for ( let i = addAtIndex ; i < domList . length ; i ++ ) {
if ( domList [ i ] . nodeKey === nextObj . innerText . trim ( ) ) {
nextElIndex = i ;
break ;
}
}
}
// console.log(" Prev: ", siblingsAbove.children[siblingsAbove.children.length - 1], "Adding: ", obj.element, " Next: ", siblingsBelow.children[0], "Overwriting:", domList.slice(addAtIndex, nextElIndex));
domList . splice ( addAtIndex , nextElIndex - addAtIndex , 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 ( obj === undefined ) {
return ;
}
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 ++ ) {
if ( domList [ i ] . element ) {
domList [ i ] . element . removeClasses ( [ MultiColumnStyleCSS . RegionEndTag ,
MultiColumnStyleCSS . ColumnEndTag ,
MultiColumnStyleCSS . RegionSettings ,
MultiColumnStyleCSS . RegionContent ] ) ;
if ( domList [ i ] . element . parentElement ) {
domList [ i ] . element . parentElement . removeChild ( domList [ i ] . element ) ;
}
}
}
for ( let i = 0 ; i < regionSettings . length ; i ++ ) {
if ( regionSettings [ i ] . element ) {
regionSettings [ i ] . element . removeClasses ( [ MultiColumnStyleCSS . RegionEndTag ,
MultiColumnStyleCSS . ColumnEndTag ,
MultiColumnStyleCSS . RegionSettings ,
MultiColumnStyleCSS . RegionContent ] ) ;
if ( regionSettings [ i ] . element . parentElement ) {
regionSettings [ i ] . element . parentElement . removeChild ( regionSettings [ i ] . element ) ;
}
}
}
}
function getRootRegionElement ( ) {
return rootElement ;
}
return { addObject : addObject ,
removeObject : removeObject ,
updateElementTag : updateElementTag ,
setElementToSettingsBlock : setElementToSettingsBlock ,
getRegionRenderData : getRegionRenderData ,
displayOriginalElements : displayOriginalElements ,
getRootRegionElement : getRootRegionElement
} ;
}
/ *
* File : multi - column - markdown / src / main . ts
* Created Date : Tuesday , October 5 th 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." ) ;
}
}
} ) ;
this . registerInterval ( window . setInterval ( ( ) => {
this . UpdateOpenFilePreviews ( ) ;
} , 2000 ) ) ;
} ) ;
}
UpdateOpenFilePreviews ( ) {
let fileManagers = this . globalManager . getAllFileManagers ( ) ;
fileManagers . forEach ( element => {
let regionalManagers = element . getAllRegionalManagers ( ) ;
regionalManagers . forEach ( regionManager => {
let parentElementData = regionManager . getRegionRenderData ( ) ;
this . updateRenderedMarkdown ( parentElementData . domObjects ) ;
} ) ;
} ) ;
}
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 docLines = info . text . split ( "\n" ) ;
let linesAboveArray = docLines . slice ( 0 , info . lineStart ) ;
let linesOfElement = docLines . slice ( info . lineStart , info . lineEnd + 1 ) ;
let linesBelowArray = docLines . slice ( info . lineEnd + 1 ) ;
/ * *
* 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 .
* /
let elementTextSpaced = linesOfElement . reduce ( ( prev , curr ) => {
return prev + "\n" + curr ;
} ) ;
if ( containsStartTag ( el . textContent ) ) {
/ * *
* Set up the current element to act as the parent for the
* multi - column region .
* /
el . children [ 0 ] . detach ( ) ;
el . classList . add ( MultiColumnLayoutCSS . RegionRootContainerDiv ) ;
let renderErrorRegion = el . createDiv ( {
cls : ` ${ MultiColumnLayoutCSS . RegionErrorContainerDiv } , ${ MultiColumnStyleCSS . RegionErrorMessage } ` ,
} ) ;
let renderColumnRegion = el . createDiv ( {
cls : MultiColumnLayoutCSS . RegionContentContainerDiv
} ) ;
let startBlockData = getStartBlockAboveLine ( linesOfElement ) ;
let regionKey = startBlockData . startBlockKey ;
if ( fileDOMManager . checkKeyExists ( regionKey ) === true ) {
let { numberOfTags , keys } = countStartTags ( info . text ) ;
let numMatches = 0 ;
for ( let i = 0 ; i < numberOfTags ; i ++ ) {
// Because we checked if key exists one of these has to match.
if ( keys [ i ] === regionKey ) {
numMatches ++ ;
}
}
// We only want to display an error if there are more than 2 of the same id across
// the whole document. This prevents erros when obsidian reloads the whole document
// and there are two of the same key in the map.
if ( numMatches >= 2 ) {
if ( regionKey === "" ) {
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 ;
}
}
el . id = ` MultiColumnID: ${ regionKey } ` ;
let elementMarkdownRenderer = new obsidian . MarkdownRenderChild ( el ) ;
fileDOMManager . createRegionalManager ( regionKey , el , 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 ;
}
/ * *
* Check if any of the lines above us contain a start block , and if
* so get the lines from our current element to the start block .
* /
let startBockAbove = getStartBlockAboveLine ( linesAboveArray ) ;
if ( startBockAbove === null ) {
return ;
}
/ * *
* We now know we ' re within a multi - column region , so we update our
* list of lines above to just be the items within this region .
* /
linesAboveArray = startBockAbove . linesAboveArray ;
/ * *
* We use the start block ' s key to get our regional manager . If this
* lookup fails we can not continue processing this element .
* /
let regionalManager = fileDOMManager . getRegionalManager ( startBockAbove . startBlockKey ) ;
if ( regionalManager === null ) {
return ;
}
/ * *
* To make sure we ' re placing the item in the right location ( and
* overwrite elements that are now gone ) we now want all of the
* lines after this element up to the end tag .
* /
linesBelowArray = getEndBlockBelow ( linesBelowArray ) ;
/ * *
* 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 these elements to determine where to place our current element .
* /
let siblingsAbove = renderMarkdownFromLines ( linesAboveArray , sourcePath ) ;
let siblingsBelow = renderMarkdownFromLines ( linesBelowArray , sourcePath ) ;
/ * *
* Set up our dom object to be added to the manager .
* /
let currentObject = new DOMObject ( el ) ;
el . id = currentObject . UID ;
/ * *
* 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 , siblingsBelow , 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 ) {
el . addClass ( MultiColumnStyleCSS . RegionEndTag ) ;
regionalManager . updateElementTag ( currentObject . UID , DOMObjectTag . endRegion ) ;
}
else if ( containsColEndTag ( elementTextSpaced ) === true ) {
el . addClass ( MultiColumnStyleCSS . ColumnEndTag ) ;
regionalManager . updateElementTag ( currentObject . UID , DOMObjectTag . columnBreak ) ;
}
else if ( containsColSettingsTag ( elementTextSpaced ) === true ) {
el . addClass ( MultiColumnStyleCSS . RegionSettings ) ;
regionalManager . setElementToSettingsBlock ( currentObject . UID , elementTextSpaced ) ;
}
else {
el . addClass ( MultiColumnStyleCSS . RegionContent ) ;
}
/ * *
* Use our regional manager to get everything needed to render the region .
* /
let parentElementData = regionalManager . getRegionRenderData ( ) ;
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 : MultiColumnLayoutCSS . RegionColumnContainerDiv ,
} ) ;
if ( settings . drawShadow === true ) {
multiColumnParent . addClass ( MultiColumnStyleCSS . RegionShadow ) ;
}
/ * *
* 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 ( MultiColumnStyleCSS . ColumnBorder ) ;
}
if ( settings . drawShadow === true ) {
columnContentDivs [ i ] . addClass ( MultiColumnStyleCSS . 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 ++ ) {
if ( regionElements [ i ] . tag !== DOMObjectTag . startRegion ||
regionElements [ i ] . tag !== DOMObjectTag . regionSettings ||
regionElements [ i ] . tag !== DOMObjectTag . endRegion ||
regionElements [ i ] . tag !== DOMObjectTag . columnBreak ) {
// We store the elements in a wrapper container until we determine
let element = createDiv ( {
cls : MultiColumnLayoutCSS . ColumnDualElementContainer ,
} ) ;
regionElements [ i ] . elementContainer = element ;
// Otherwise we just make a copy of the original element to display.
element . appendChild ( regionElements [ i ] . element . cloneNode ( true ) ) ;
if ( element !== null ) {
columnContentDivs [ columnIndex ] . appendChild ( element ) ;
}
/ * *
* If the tag is a column break we update the column index after
* appending the item to the column div . This keeps the main DOM
* cleaner by removing other items and placing them all within
* a region container .
* /
if ( regionElements [ i ] . tag === DOMObjectTag . columnBreak &&
( columnIndex + 1 ) < settings . numberOfColumns ) {
columnIndex ++ ;
}
}
}
}
setUpDualRender ( domElement ) {
/ * *
* If our element is of "specialRender" type it * may * need to be rendered
* using the original element rather than a copy . For example , an element
* may have an onClick event that would not get coppied to the clone .
*
* If we just moved these elements into the region it would get
* moved back out into the original location in the DOM by obsidian
* when scrolling or when the file is updated . On the next refresh it
* would be moved back but that can lead to a region jumping
* around as the item is moved in and out .
*
* Here we set up the div to contain the element and create
* a visual only clone of it . The clone will only be visible
* when the original is not in the multi - column region so it
* saves us from the visual noise of the region jumping around .
* /
// Remove the old elements before we set up the dual rendered elements.
let containerElement = domElement . elementContainer ;
let renderElement = domElement . element ;
for ( let i = containerElement . children . length - 1 ; i >= 0 ; i -- ) {
containerElement . children [ i ] . detach ( ) ;
}
containerElement . appendChild ( renderElement ) ;
renderElement . addClass ( MultiColumnLayoutCSS . OriginalElementType ) ;
let clonedNode = renderElement . cloneNode ( true ) ;
clonedNode . addClass ( MultiColumnLayoutCSS . ClonedElementType ) ;
clonedNode . removeClasses ( [ MultiColumnStyleCSS . RegionContent , MultiColumnLayoutCSS . OriginalElementType ] ) ;
containerElement . appendChild ( clonedNode ) ;
}
updateRenderedMarkdown ( regionElements ) {
/ * *
* Go through every node of the region looking for the "specialRender" type
* which are the elements that may need to be rendered using the original
* element rather than a copy .
* /
for ( let i = 0 ; i < regionElements . length ; i ++ ) {
/ * *
* Here we check every item again to see if they need to be updated .
* This could be made slightly more efficient if we can truly determine
* wether an item is a normal render item , however it seems like it
* may take a bit of extra time in order for the classes we check for
* to be added to the elements .
* /
let elementType = regionElements [ i ] . elementType ;
// If the element is not currently a special render element we check again
// as the original element may have been updated.
if ( elementType !== ElementRenderType . specialRender ) {
// If the new result returns as a special renderer we update so
// this wont run again for this item.
elementType = getElementRenderType ( regionElements [ i ] . element ) ;
}
if ( elementType === ElementRenderType . specialRender ) {
regionElements [ i ] . elementType = elementType ;
this . setUpDualRender ( regionElements [ i ] ) ;
}
}
}
}
/ * *
* 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 renderMarkdownFromLines ( mdLines , 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 siblings = createDiv ( ) ;
let markdownRenderChild = new obsidian . MarkdownRenderChild ( siblings ) ;
obsidian . MarkdownRenderer . renderMarkdown ( mdLines . reduce ( ( prev , current ) => {
return prev + "\n" + current ;
} , "" ) , siblings , sourcePath , markdownRenderChild ) ;
return siblings ;
}
module . exports = MultiColumnMarkdown ;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsInNyYy9yZWdpb25TZXR0aW5ncy50cyIsInNyYy91dGlsaXRpZXMvdGV4dFBhcnNlci50cyIsInNyYy91dGlsaXRpZXMvdXRpbHMudHMiLCJzcmMvdXRpbGl0aWVzL2VsZW1lbnRSZW5kZXJUeXBlUGFyc2VyLnRzIiwic3JjL2RvbV9tYW5hZ2VyL2RvbU9iamVjdC50cyIsInNyYy91dGlsaXRpZXMvY3NzRGVmaW5pdGlvbnMudHMiLCJzcmMvZG9tX21hbmFnZXIvZG9tTWFuYWdlci50cyIsInNyYy9tYWluLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qISAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi5cclxuXHJcblBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGFuZC9vciBkaXN0cmlidXRlIHRoaXMgc29mdHdhcmUgZm9yIGFueVxyXG5wdXJwb3NlIHdpdGggb3Igd2l0aG91dCBmZWUgaXMgaGVyZWJ5IGdyYW50ZWQuXHJcblxyXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiIEFORCBUSEUgQVVUSE9SIERJU0NMQUlNUyBBTEwgV0FSUkFOVElFUyBXSVRIXHJcblJFR0FSRCBUTyBUSElTIFNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWVxyXG5BTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsXHJcbklORElSRUNULCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTVxyXG5MT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUlxyXG5PVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SXHJcblBFUkZPUk1BTkNFIE9GIFRISVMgU09GVFdBUkUuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGIsIHApKSBkW3BdID0gYltwXTsgfTtcclxuICAgIHJldHVybiBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBpZiAodHlwZW9mIGIgIT09IFwiZnVuY3Rpb25cIiAmJiBiICE9PSBudWxsKVxyXG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDbGFzcyBleHRlbmRzIHZhbHVlIFwiICsgU3RyaW5nKGIpICsgXCIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbFwiKTtcclxuICAgIGV4dGVuZFN0YXRpY3MoZCwgYik7XHJcbiAgICBmdW5jdGlvbiBfXygpIHsgdGhpcy5jb25zdHJ1Y3RvciA9IGQ7IH1cclxuICAgIGQucHJvdG90eXBlID0gYiA9PT0gbnVsbCA/IE9iamVjdC5jcmVhdGUoYikgOiAoX18ucHJvdG90eXBlID0gYi5wcm90b3R5cGUsIG5ldyBfXygpKTtcclxufVxyXG5cclxuZXhwb3J0IHZhciBfX2Fzc2lnbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uIF9fYXNzaWduKHQpIHtcclxuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcclxuICAgICAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKSB0W3BdID0gc1twXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gX19hc3NpZ24uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVzdChzLCBlKSB7XHJcbiAgICB2YXIgdCA9IHt9O1xyXG4gICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApICYmIGUuaW5kZXhPZihwKSA8IDApXHJcbiAgICAgICAgdFtwXSA9IHNbcF07XHJcbiAgICBpZiAocyAhPSBudWxsICYmIHR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzID09PSBcImZ1bmN0aW9uXCIpXHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIHAgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHMpOyBpIDwgcC5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMCAmJiBPYmplY3QucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlLmNhbGwocywgcFtpXSkpXHJcbiAgICAgICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgICAgICB9XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9