1+ import { DatabaseCore } from "helpers/Constants" ;
2+ import DBFolderPlugin from "main" ;
3+ import { MarkdownPostProcessorContext } from "obsidian" ;
4+ import DatabaseInfo from "services/DatabaseInfo" ;
5+ import { VaultManagerDB } from "services/FileManagerService" ;
6+ import { DataviewService } from "services/DataviewService" ;
7+ import { obtainColumnsFromFolder , obtainMetadataColumns } from "components/Columns" ;
8+ import { adapterTFilesToRows } from "helpers/VaultManagement" ;
9+ import { DatabaseColumn } from "cdm/DatabaseModel" ;
10+ /**
11+ * Keep info about a note and offer methods to manipulate it
12+ */
13+ export class PreviewDatabaseModeService {
14+ private static instance : PreviewDatabaseModeService ;
15+ private plugin : DBFolderPlugin ;
16+ constructor ( plugin : DBFolderPlugin ) {
17+ this . plugin = plugin ;
18+ if ( ! PreviewDatabaseModeService . instance ) {
19+ PreviewDatabaseModeService . instance = this ;
20+ }
21+ }
22+ hoverEvent = ( e : any ) => {
23+ if ( ! e . linktext ) {
24+ this . plugin . hover . linkText = null ;
25+ return ;
26+ }
27+ this . plugin . hover . linkText = e . linktext ;
28+ this . plugin . hover . sourcePath = e . sourcePath ;
29+ } ;
30+ /**
31+ *
32+ * @param el
33+ * @param ctx
34+ */
35+ markdownPostProcessor = async (
36+ el : HTMLElement ,
37+ ctx : MarkdownPostProcessorContext ,
38+ ) => {
39+ //check to see if we are rendering in editing mode of live preview
40+ //if yes, then there should be no .internal-embed containers
41+ const embeddedItems = el . querySelectorAll ( ".internal-embed" ) ;
42+ if ( embeddedItems . length === 0 ) {
43+ this . tmpObsidianWYSIWYG ( el , ctx ) ;
44+ return ;
45+ }
46+
47+ //If the file being processed is an excalidraw file,
48+ //then I want to hide all embedded items as these will be
49+ //transcluded text element or some other transcluded content inside the Excalidraw file
50+ //in reading mode these elements should be hidden
51+ if ( ctx . frontmatter ?. hasOwnProperty ( DatabaseCore . FRONTMATTER_KEY ) ) {
52+ el . style . display = "none" ;
53+ return ;
54+ }
55+ } ;
56+
57+ tmpObsidianWYSIWYG = async (
58+ el : HTMLElement ,
59+ ctx : MarkdownPostProcessorContext ,
60+ ) => {
61+ if ( ! ctx . frontmatter ) {
62+ return ;
63+ }
64+ if ( ! ctx . frontmatter . hasOwnProperty ( DatabaseCore . FRONTMATTER_KEY ) ) {
65+ return ;
66+ }
67+ //@ts -ignore
68+ if ( ctx . remainingNestLevel < 4 ) {
69+ return ;
70+ }
71+ if ( ! el . querySelector ( ".frontmatter" ) ) {
72+ el . style . display = "none" ;
73+ return ;
74+ }
75+ el . empty ( ) ;
76+ const previewContainer = await this . renderPreview ( el , ctx ) ;
77+ setTimeout ( async ( ) => {
78+ let internalEmbedDiv : HTMLElement = el ;
79+ while (
80+ ! internalEmbedDiv . hasClass ( "internal-embed" ) &&
81+ internalEmbedDiv . parentElement
82+ ) {
83+ internalEmbedDiv = internalEmbedDiv . parentElement ;
84+ }
85+
86+ if ( ! internalEmbedDiv . hasClass ( "internal-embed" ) ) {
87+ el . empty ( ) ;
88+ el . appendChild ( previewContainer ) ;
89+ return ;
90+ }
91+
92+ internalEmbedDiv . empty ( ) ;
93+ const previewTimeoutContainer = await this . renderPreview ( internalEmbedDiv , ctx ) ;
94+ //timer to avoid the image flickering when the user is typing
95+ let timer : NodeJS . Timeout = null ;
96+ const observer = new MutationObserver ( ( m ) => {
97+ if ( ! [ "alt" , "width" , "height" ] . contains ( m [ 0 ] ?. attributeName ) ) {
98+ return ;
99+ }
100+ if ( timer ) {
101+ clearTimeout ( timer ) ;
102+ }
103+ timer = setTimeout ( ( ) => {
104+ timer = null ;
105+ previewTimeoutContainer . empty ( ) ;
106+ } , 500 ) ;
107+ } ) ;
108+ observer . observe ( previewTimeoutContainer , {
109+ attributes : true , //configure it to listen to attribute changes
110+ } ) ;
111+ } , 300 ) ;
112+ } ;
113+
114+ private renderPreview = async (
115+ el : HTMLElement ,
116+ ctx : MarkdownPostProcessorContext ,
117+ ) : Promise < HTMLElement > => {
118+ const dbFile = VaultManagerDB . obtainTfileFromFilePath ( ctx . sourcePath ) ;
119+ const databaseDisk = new DatabaseInfo ( dbFile ) ;
120+ await databaseDisk . initDatabaseconfigYaml (
121+ this . plugin . settings . local_settings
122+ ) ;
123+
124+ const div = createDiv ( ) ;
125+ div . textContent = `${ databaseDisk
126+ . yaml . description } `;
127+ el . appendChild ( div ) ;
128+ let yamlColumns : Record < string , DatabaseColumn > =
129+ databaseDisk . yaml . columns ;
130+ // Complete the columns with the metadata columns
131+ yamlColumns = await obtainMetadataColumns (
132+ yamlColumns ,
133+ databaseDisk . yaml . config
134+ ) ;
135+ // Obtain base information about columns
136+ const columns = await obtainColumnsFromFolder ( yamlColumns ) ;
137+ const rows = await adapterTFilesToRows (
138+ dbFile . parent . path ,
139+ columns ,
140+ databaseDisk . yaml . filters
141+ ) ;
142+ const dataviewCols : string [ ] = columns
143+ . filter ( ( col ) => ! col . skipPersist )
144+ . map ( ( c ) => c . key ) ;
145+ const dataviewMatrixRow : any [ ] [ ] = rows . map ( ( r ) =>
146+ dataviewCols . map ( ( c ) => r [ c ] )
147+ ) ;
148+
149+ DataviewService . getDataviewAPI ( ) . table (
150+ dataviewCols ,
151+ dataviewMatrixRow ,
152+ div ,
153+ null ,
154+ ctx . sourcePath
155+ )
156+ return div ;
157+ }
158+
159+ public static getInstance ( plugin ?: DBFolderPlugin ) : PreviewDatabaseModeService {
160+ if ( ! this . instance ) {
161+ this . instance = new PreviewDatabaseModeService ( plugin ) ;
162+ }
163+ return this . instance ;
164+ }
165+ }
0 commit comments