Skip to content

Commit 100fb56

Browse files
committed
Updates for Obsidian 1.6+
- Restore view header icon for maximized panes - Don't hotfix Obsidian theme adaptation on 1.6+ (Fix #60) - Drop some code that was only needed for pre-1.0 Obsidian
1 parent 313ef66 commit 100fb56

File tree

6 files changed

+62
-80
lines changed

6 files changed

+62
-80
lines changed

manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "pane-relief",
33
"name": "Pane Relief",
4-
"version": "0.5.6",
4+
"version": "0.5.7",
55
"minAppVersion": "1.5.8",
66
"description": "Per-tab history, hotkeys for pane/tab movement, navigation, sliding workspace, and more",
77
"author": "PJ Eby",

src/History.ts

Lines changed: 8 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import {HistoryState, Notice, requireApiVersion, TAbstractFile, WorkspaceLeaf} from 'obsidian';
2-
import {around} from "monkey-around";
3-
import {LayoutStorage, Service, windowEvent} from "@ophidian/core";
1+
import { HistoryState, Notice, TAbstractFile, WorkspaceLeaf } from 'obsidian';
2+
import { around } from "monkey-around";
3+
import { LayoutStorage, Service } from "@ophidian/core";
44
import { leafName } from './pane-relief';
55
import { formatState } from './Navigator';
66

77
const HIST_ATTR = "pane-relief:history-v1";
88
const SERIAL_PROP = "pane-relief:history-v1";
9-
export const hasTabHistory = requireApiVersion("0.16.3");
109

1110
declare module "obsidian" {
1211
interface Workspace {
@@ -162,7 +161,6 @@ export class History {
162161

163162
pos: number
164163
stack: HistoryEntry[]
165-
hadTabs = hasTabHistory;
166164

167165
constructor(public leaf?: WorkspaceLeaf, {pos, stack}: SerializableHistory = {pos:0, stack:[]}) {
168166
if (leaf) leaf[HIST_ATTR] = this; // prevent recursive lookups
@@ -173,7 +171,7 @@ export class History {
173171

174172
saveToNative(): this {
175173
const nativeHistory = this.leaf?.history;
176-
if (!nativeHistory || !hasTabHistory) return this;
174+
if (!nativeHistory) return this;
177175
const stack = this.stack.map(entry => entry.asNative);
178176
nativeHistory.deserialize({
179177
backHistory: stack.slice(this.pos+1).reverse(),
@@ -184,7 +182,7 @@ export class History {
184182

185183
loadFromNative(): this {
186184
const history = this.leaf?.history;
187-
if (!history || !hasTabHistory) return this;
185+
if (!history) return this;
188186
const stack: typeof history.backHistory = [].concat(
189187
history.forwardHistory.slice().filter(s => s),
190188
{state: {}, eState: {}},
@@ -232,7 +230,7 @@ export class History {
232230
// prevent wraparound
233231
const newPos = Math.max(0, Math.min(this.pos - by, this.stack.length - 1));
234232
if (force || newPos !== this.pos) {
235-
if (this.leaf.history && hasTabHistory) {
233+
if (this.leaf.history) {
236234
this.pos = newPos;
237235
this.leaf.history.go(by);
238236
} else this.goto(newPos);
@@ -280,7 +278,7 @@ export class HistoryManager extends Service {
280278
}
281279
}));
282280

283-
if (hasTabHistory) {
281+
if (true) {
284282
// Forward native tab history events to our own implementation
285283
this.register(around(WorkspaceLeaf.prototype, {
286284
trigger(old) { return function trigger(name, ...data) {
@@ -294,65 +292,7 @@ export class HistoryManager extends Service {
294292
}));
295293

296294
// Incorporate any prior history state (e.g. on plugin update)
297-
if (app.workspace.layoutReady) app.workspace.iterateAllLeaves(leaf => { History.forLeaf(leaf); })
298-
299-
// Skip most actual history replacement if native history is tab-based
300-
return;
295+
app.workspace.onLayoutReady(() => app.workspace.iterateAllLeaves(leaf => { leaf.trigger("history-change") }))
301296
}
302-
303-
// Monkeypatch: check for popstate events (to suppress them)
304-
this.register(around(WorkspaceLeaf.prototype, {
305-
setViewState(old) { return function setViewState(vs, es){
306-
if (vs.popstate && window.event?.type === "popstate") {
307-
return Promise.resolve();
308-
}
309-
return old.call(this, vs, es);
310-
}}
311-
}));
312-
313-
this.register(around(app.workspace, {
314-
// Monkeypatch: keep Obsidian from pushing history in setActiveLeaf
315-
setActiveLeaf(old) { return function setActiveLeaf(leaf, ...etc: any[]) {
316-
const unsub = around(this, {
317-
recordHistory(old) { return function (leaf: WorkspaceLeaf, _push: boolean, ...args: any[]) {
318-
// Always update state in place
319-
return old.call(this, leaf, false, ...args);
320-
}; }
321-
});
322-
try {
323-
return old.call(this, leaf, ...etc);
324-
} finally {
325-
unsub();
326-
}
327-
}},
328-
}));
329-
330-
function isSyntheticHistoryEvent(button: number) {
331-
return !!windowEvent((_, event) => {
332-
if (event.type === "mousedown" && (event as MouseEvent).button === button) {
333-
event.preventDefault();
334-
event.stopImmediatePropagation();
335-
return true;
336-
}
337-
});
338-
}
339-
340-
// Proxy the window history with a wrapper that delegates to the active leaf's History object,
341-
const realHistory = window.history;
342-
this.register(() => (window as any).history = realHistory);
343-
Object.defineProperty(window, "history", { enumerable: true, configurable: true, writable: true, value: {
344-
get state() { return History.current().state; },
345-
get length() { return History.current().length; },
346-
347-
back() { if (!isSyntheticHistoryEvent(3)) this.go(-1); },
348-
forward() { if (!isSyntheticHistoryEvent(4)) this.go( 1); },
349-
go(by: number) { History.current().go(by); },
350-
351-
replaceState(state: PushState, title: string, url: string){ History.current().replaceState(state, title, url); },
352-
pushState(state: PushState, title: string, url: string) { History.current().pushState(state, title, url); },
353-
354-
get scrollRestoration() { return realHistory.scrollRestoration; },
355-
set scrollRestoration(val) { realHistory.scrollRestoration = val; },
356-
}});
357297
}
358298
}

src/Navigator.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Menu, Keymap, Component, WorkspaceLeaf, TFile, MenuItem, requireApiVersion, WorkspaceTabs, debounce} from 'obsidian';
2-
import {domLeaves, hasTabHistory, History, HistoryEntry} from "./History";
2+
import {domLeaves, History, HistoryEntry} from "./History";
33
import {PerWindowComponent} from "@ophidian/core";
44
import {around} from 'monkey-around';
55

@@ -40,7 +40,7 @@ declare module "obsidian" {
4040
}
4141

4242
const adaptTheme = debounce(() => {
43-
if (app.vault.getConfig("theme") === "system") app.adaptToSystemTheme();
43+
if (app.vault.getConfig("theme") === "system") app.adaptToSystemTheme?.();
4444
}, 200, true);
4545

4646
interface FileInfo {
@@ -152,7 +152,9 @@ export class Navigation extends PerWindowComponent {
152152
return false;
153153
}
154154

155-
this.registerDomEvent(this.win.matchMedia("(prefers-color-scheme: dark)") as any, "change", adaptTheme);
155+
// Workaround for https://forum.obsidian.md/t/detached-window-doesnt-change-color-scheme-automatically/42642/10
156+
// (which was fixed in Obsidian 1.6)
157+
requireApiVersion("1.6.0") || this.registerDomEvent(this.win.matchMedia("(prefers-color-scheme: dark)") as any, "change", adaptTheme);
156158

157159
app.workspace.onLayoutReady(() => {
158160
this.addChild(this.back = new Navigator(this, "back", -1));
@@ -196,7 +198,7 @@ export class Navigation extends PerWindowComponent {
196198
if (back) this.back.updateDisplay(history, back);
197199

198200
// Add labels for 0.16.3 Tab headers
199-
if (hasTabHistory) {
201+
if (true) {
200202
const actions = leaf.containerEl.find(".view-header > .view-header-nav-buttons");
201203
const fwd = actions?.find('button:last-child');
202204
const back = actions?.find('button:first-child');
@@ -343,7 +345,7 @@ export class Navigator extends Component {
343345
i.setIcon(info.icon).setTitle(prefix + info.title).onClick(e => {
344346
// Check for ctrl/cmd/middle button and split leaf + copy history
345347
if (Keymap.isModEvent(e)) {
346-
if (hasTabHistory && history.leaf) {
348+
if (history.leaf) {
347349
// Use the new duplication API because native history doesn't store current state
348350
app.workspace.duplicateLeaf(history.leaf, Keymap.isModEvent(e)).then(leaf => {
349351
History.forLeaf(leaf).go((idx+1) * dir, true);

src/maximizing.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Service, toggleClass } from "@ophidian/core";
22
import { around } from "monkey-around";
3-
import { debounce, requireApiVersion, WorkspaceLeaf, WorkspaceTabs } from "obsidian";
3+
import { debounce, requireApiVersion, WorkspaceLeaf, WorkspaceTabs, ItemView, setIcon, setTooltip, View } from "obsidian";
44
import { isMain } from "./focus-lock";
55

66
declare module "obsidian" {
@@ -73,6 +73,23 @@ export class Maximizer extends Service {
7373
}
7474
}));
7575
})
76+
77+
// Restore pre-1.6 view header icons so you can drag maximized views
78+
this.register(around(ItemView.prototype, {
79+
load(old) {
80+
return function(this: View) {
81+
if (!this.iconEl) {
82+
const iconEl = this.iconEl = this.headerEl.createDiv("clickable-icon view-header-icon")
83+
this.headerEl.prepend(iconEl)
84+
iconEl.draggable = true
85+
iconEl.addEventListener("dragstart", e => { this.app.workspace.onDragLeaf(e, this.leaf) })
86+
setIcon(iconEl, this.getIcon())
87+
setTooltip(iconEl, "Drag to rearrange")
88+
}
89+
return old.call(this)
90+
}
91+
}
92+
}))
7693
}
7794

7895
onunload() {
@@ -169,4 +186,15 @@ export class Maximizer extends Service {
169186
return el?.matchParent(".workspace, .hover-popover > .popover-content > .workspace-split");
170187
}
171188

172-
}
189+
}
190+
191+
declare module "obsidian" {
192+
interface Workspace {
193+
onDragLeaf(event: MouseEvent, leaf: WorkspaceLeaf): void;
194+
}
195+
interface View {
196+
iconEl: HTMLElement;
197+
headerEl: HTMLElement;
198+
}
199+
export function setTooltip(el: HTMLElement, tooltip: string, options?: TooltipOptions): void;
200+
}

src/styles.scss

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,19 @@ body > .popover.hover-popover .workspace-split.should-maximize
131131
}
132132
}
133133

134+
/* Restore 1.5.x view header icons (for maximized views) */
135+
.view-header .view-header-icon {
136+
display: none;
137+
padding: var(--size-2-2);
138+
margin-right: var(--size-2-3);
139+
color: var(--text-muted);
140+
align-self: center;
141+
cursor: grab;
142+
}
143+
.view-header .view-header-icon:active {
144+
cursor: grabbing;
145+
}
146+
134147
#pr-maximize-sb-toggle {
135148
display: none;
136149
position: fixed;
@@ -288,7 +301,7 @@ body.pane-relief-pane-numbering {
288301
/* Number panes in their headers */
289302
.workspace-split .workspace-leaf .view-header-icon { min-width: fit-content; display: inherit; }
290303
.workspace-split .workspace-leaf .view-header-icon::before,
291-
.workspace-split .workspace-leaf .view-header-left .view-header-nav-buttons::before
304+
.workspace-split .workspace-leaf .view-header-left:first-child .view-header-nav-buttons::before
292305
{
293306
content: "";
294307
display: inline-flex;
@@ -297,7 +310,7 @@ body.pane-relief-pane-numbering {
297310
bottom: var(--pr-pane-number-bottom);
298311
}
299312
.workspace-split .workspace-leaf.has-pane-relief-label .view-header-icon::before,
300-
.workspace-split .workspace-leaf.has-pane-relief-label .view-header-left .view-header-nav-buttons::before
313+
.workspace-split .workspace-leaf.has-pane-relief-label .view-header-left:first-child .view-header-nav-buttons::before
301314
{
302315
counter-reset: pane-number var(--pane-relief-label);
303316
content: counter(pane-number);

versions.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
2-
"0.5.6": "1.5.8",
3-
"0.5.5": "1.5.8",
2+
"0.5.7": "1.5.8",
43
"0.5.2": "1.3.5",
54
"0.5.1": "1.2.8",
65
"0.4.2": "0.15.9",

0 commit comments

Comments
 (0)