Skip to content
This repository has been archived by the owner on Oct 17, 2022. It is now read-only.

Commit

Permalink
Fix #37
Browse files Browse the repository at this point in the history
  • Loading branch information
mgmeyers committed Jul 15, 2022
1 parent 1e6a3f6 commit 624eee8
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 249 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "obsidian-embedded-note-titles",
"name": "Embedded Note Titles",
"version": "1.2.10",
"version": "1.3.0",
"minAppVersion": "0.15.0",
"description": "Inserts the note file name as an H1 heading above each note.",
"author": "mgmeyers",
Expand Down
214 changes: 13 additions & 201 deletions src/HeadingsManager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { App, MarkdownView, WorkspaceLeaf, debounce } from "obsidian";
import { App, MarkdownView, WorkspaceLeaf } from "obsidian";

import { Settings } from "./settings";
import { getMatchedCSSRules } from "./getMatchedCSSRules";
Expand Down Expand Up @@ -101,199 +101,6 @@ function applyRefStyles(heading: HTMLElement, ref: RefSizing | null) {
}
}

export class LegacyCodemirrorHeadingsManager {
headings: {
[id: string]: {
leaf: WorkspaceLeaf;
resizeWatcher?: ResizeObserver;
};
} = {};

codeMirrorSizerRef: RefSizing | null = null;
codeMirrorSizerInvalid: boolean = true;

getSettings: () => Settings;

constructor(getSettings: () => Settings) {
this.getSettings = getSettings;
}

getCodeMirrorSizerStyles() {
const sizerEl = document.getElementsByClassName("CodeMirror-sizer");
const lineEl = document.getElementsByClassName("CodeMirror-line");

if (sizerEl.length && lineEl.length) {
const sizer = sizerEl[0] as HTMLElement;

const { marginLeft, paddingRight, borderRightWidth } = sizer.style;

// If codemirror hasn't applied styles to the div yet, let's consider it
// invalid so we can check it again later
if (marginLeft !== "0px" && paddingRight !== "0px") {
this.codeMirrorSizerInvalid = false;
}

const inline: RefSizing = {
marginLeft,
marginRight: borderRightWidth,
paddingRight,
};

const sizerRef = getRefSizing(sizer);

const line = lineEl[0] as HTMLElement;
const lineRef = getRefSizing(line);

// Combine inline styles with CSS styles
this.codeMirrorSizerRef = {
...inline,
...sizerRef,
};

if (lineRef.paddingLeft) {
this.codeMirrorSizerRef.paddingLeft = this.codeMirrorSizerRef
.paddingLeft
? `calc(${this.codeMirrorSizerRef.paddingLeft} + ${lineRef.paddingLeft})`
: lineRef.paddingLeft;
}

if (lineRef.paddingRight) {
this.codeMirrorSizerRef.paddingRight = this.codeMirrorSizerRef
.paddingRight
? `calc(${this.codeMirrorSizerRef.paddingRight} + ${lineRef.paddingRight})`
: lineRef.paddingRight;
}
}
}

// Once the codemirror heading styles have been validated, loop through and update everything
updateCodeMirrorHeadings() {
Object.keys(this.headings).forEach((id) => {
const h1Edit = document.getElementById(`${id}-edit`);
applyRefStyles(h1Edit, this.codeMirrorSizerRef);
});
}

// Clean up headings once a pane has been closed or the plugin has been disabled
removeHeading(id: string) {
if (!this.headings[id]) return;

const h1Edit = document.getElementById(`${id}-edit`);

if (h1Edit) h1Edit.remove();

this.headings[id].resizeWatcher?.disconnect();

delete this.headings[id].resizeWatcher;
delete this.headings[id];
}

createHeading(id: string, leaf: WorkspaceLeaf) {
// CodeMirror adds margin and padding only after the editor is visible
if (
this.codeMirrorSizerInvalid &&
leaf.getViewState().state?.mode === "source"
) {
this.getCodeMirrorSizerStyles();

if (!this.codeMirrorSizerInvalid) {
this.updateCodeMirrorHeadings();
}
}

if (this.headings[id]) return;

const title = getTitleForView(
leaf.view.app,
this.getSettings(),
leaf.view as MarkdownView
);

const viewContent =
leaf.view.containerEl.getElementsByClassName("CodeMirror-scroll");

const lines =
leaf.view.containerEl.getElementsByClassName("CodeMirror-lines");

if (!this.codeMirrorSizerRef) {
this.getCodeMirrorSizerStyles();
}

if (viewContent.length) {
// Create the codemirror heading
const editEl = viewContent[0] as HTMLDivElement;
const h1Edit = document.createElement("h1");

applyRefStyles(h1Edit, this.codeMirrorSizerRef);

h1Edit.setText(title);
h1Edit.id = `${id}-edit`;
h1Edit.classList.add("embedded-note-title", "embedded-note-title__edit");

if (title === "") {
h1Edit.classList.add("embedded-note-title__hidden");
}

editEl.prepend(h1Edit);

const onResize = debounce(
(entries: any) => {
if (lines.length) {
const linesEl = lines[0] as HTMLDivElement;
const height = Math.ceil(entries[0].borderBoxSize[0].blockSize);

linesEl.style.paddingTop = `${height}px`;
h1Edit.style.marginBottom = `-${height}px`;
}
},
20,
true
);

// We need to push the content down when the pane resizes so the heading
// doesn't cover the content
const resizeWatcher = new (window as any).ResizeObserver(onResize);

resizeWatcher.observe(h1Edit);

this.headings[id] = { leaf, resizeWatcher };
}
}

// Generate a unique ID for a leaf
getLeafId(leaf: WorkspaceLeaf) {
return "title-" + Math.random().toString(36).substr(2, 9);
}

// Iterate through all leafs and generate headings if needed
createHeadings(app: App) {
const seen: { [k: string]: boolean } = {};

app.workspace.getLeavesOfType("markdown").forEach((leaf) => {
const id = this.getLeafId(leaf);

if (id) {
this.createHeading(id, leaf);
seen[id] = true;
}
});

Object.keys(this.headings).forEach((id) => {
if (!seen[id]) {
this.removeHeading(id);
}
});
}

cleanup() {
this.codeMirrorSizerRef = null;

Object.keys(this.headings).forEach((id) => {
this.removeHeading(id);
});
}
}

export class PreviewHeadingsManager {
headings: {
[id: string]: {
Expand All @@ -308,8 +115,8 @@ export class PreviewHeadingsManager {
this.getSettings = getSettings;
}

getPreviewSizerStyles() {
const el = document.getElementsByClassName("markdown-preview-sizer");
getPreviewSizerStyles(doc: Document) {
const el = doc.getElementsByClassName("markdown-preview-sizer");

if (el.length) {
this.previewSizerRef = getRefSizing(el[0] as HTMLElement);
Expand All @@ -320,7 +127,8 @@ export class PreviewHeadingsManager {
removeHeading(id: string) {
if (!this.headings[id]) return;

const h1Preview = document.getElementById(`${id}-preview`);
const doc = this.headings[id].leaf.view.containerEl.ownerDocument;
const h1Preview = doc.getElementById(`${id}-preview`);

if (h1Preview) h1Preview.remove();

Expand All @@ -330,6 +138,8 @@ export class PreviewHeadingsManager {
createHeading(id: string, leaf: WorkspaceLeaf) {
if (this.headings[id]) return;

const doc = leaf.view.containerEl.ownerDocument;

const title = getTitleForView(
leaf.view.app,
this.getSettings(),
Expand All @@ -341,21 +151,23 @@ export class PreviewHeadingsManager {
);

if (!this.previewSizerRef) {
this.getPreviewSizerStyles();
this.getPreviewSizerStyles(doc);
}

let previewEl: HTMLDivElement;

for (let i = 0, len = previewContent.length; i < len; i++) {
if (previewContent[i].parentElement.parentElement.hasClass("view-content")) {
if (
previewContent[i].parentElement.parentElement.hasClass("view-content")
) {
previewEl = previewContent[i] as HTMLDivElement;
break;
}
}

if (previewEl) {
// Create the preview heading
const h1Preview = document.createElement("h1");
const h1Preview = doc.createElement("h1");

applyRefStyles(h1Preview, this.previewSizerRef);

Expand All @@ -378,7 +190,7 @@ export class PreviewHeadingsManager {

// Generate a unique ID for a leaf
getLeafId(leaf: WorkspaceLeaf) {
return "title-" + Math.random().toString(36).substr(2, 9);
return "title-" + Math.random().toString(36).substring(2, 9);
}

// Iterate through all leafs and generate headings if needed
Expand Down
38 changes: 18 additions & 20 deletions src/getMatchedCSSRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,12 @@ function toArray(list: any) {
}

// handles extraction of `cssRules` as an `Array` from a stylesheet or something that behaves the same
function getSheetRules(stylesheet: CSSStyleSheet) {
var sheet_media = stylesheet.media && stylesheet.media.mediaText;
function getSheetRules(win: Window, stylesheet: CSSStyleSheet) {
const sheet_media = stylesheet.media && stylesheet.media.mediaText;
// if this sheet is disabled skip it
if (stylesheet.disabled) return [];
// if this sheet's media is specified and doesn't match the viewport then skip it
if (
sheet_media &&
sheet_media.length &&
!window.matchMedia(sheet_media).matches
)
if (sheet_media && sheet_media.length && !win.matchMedia(sheet_media).matches)
return [];
// get the style rules of this sheet
try {
Expand All @@ -32,16 +28,17 @@ function getSheetRules(stylesheet: CSSStyleSheet) {
}

function _find(string: string, re: RegExp) {
var matches = string.match(re);
const matches = string.match(re);
return matches ? matches.length : 0;
}

// calculates the specificity of a given `selector`
function calculateScore(selector: string) {
var score = [0, 0, 0],
parts = selector.split(" "),
part,
match;
const score = [0, 0, 0];
const parts = selector.split(" ");
let part;
let match;

//TODO: clean the ':not' part since the last ELEMENT_RE will pick it up
while (((part = parts.shift()), typeof part == "string")) {
// find all pseudo-elements
Expand Down Expand Up @@ -77,10 +74,10 @@ function calculateScore(selector: string) {

// returns the heights possible specificity score an element can get from a give rule's selectorText
function getSpecificityScore(element: HTMLElement, selectorText: string) {
var selectors = selectorText.split(","),
selector,
score,
result = 0;
const selectors = selectorText.split(",");
let selector;
let score;
let result = 0;

while ((selector = selectors.shift())) {
if (element.matches(selector)) {
Expand Down Expand Up @@ -111,7 +108,8 @@ function sortBySpecificity(element: HTMLElement, rules: CSSStyleRule[]) {
}

export function getMatchedCSSRules(element: HTMLElement): CSSStyleRule[] {
let styleSheets = toArray(window.document.styleSheets);
const win = element.ownerDocument.defaultView;
let styleSheets = toArray(element.ownerDocument.styleSheets);
let sheet;
let rules;
let rule;
Expand All @@ -121,20 +119,20 @@ export function getMatchedCSSRules(element: HTMLElement): CSSStyleRule[] {
// we iterate them from the beginning to follow proper cascade order
while ((sheet = styleSheets.shift())) {
// get the style rules of this sheet
rules = getSheetRules(sheet);
rules = getSheetRules(win, sheet);
// loop the rules in order of appearance
while ((rule = rules.shift())) {
// if this is an @import rule
if (rule.styleSheet) {
// insert the imported stylesheet's rules at the beginning of this stylesheet's rules
rules = getSheetRules(rule.styleSheet).concat(rules);
rules = getSheetRules(win, rule.styleSheet).concat(rules);
// and skip this rule
continue;
}
// if there's no stylesheet attribute BUT there IS a media attribute it's a media rule
else if (rule.media) {
// insert the contained rules of this media rule to the beginning of this stylesheet's rules
rules = getSheetRules(rule).concat(rules);
rules = getSheetRules(win, rule).concat(rules);
// and skip it
continue;
}
Expand Down
Loading

0 comments on commit 624eee8

Please sign in to comment.