arcane-os 0.42.2 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +1 -1
- package/docs/reference/runtime-components.md +63 -10
- package/docs/reference/runtime-modules.md +64 -0
- package/package.json +1 -1
- package/runtime/arcane/components/data-view.html +136 -51
- package/runtime/arcane/components/file-manager.html +214 -32
- package/runtime/arcane/components/markdown-editor.html +70 -0
- package/runtime/arcane/components/modal.html +8 -4
- package/runtime/arcane/modules/PrintView.js +625 -0
|
@@ -469,8 +469,15 @@
|
|
|
469
469
|
directory=>directory.trim()
|
|
470
470
|
).filter(Boolean);
|
|
471
471
|
const fileEntityPromise=import('../entities/File.js');
|
|
472
|
+
const printModulePromise=import('../modules/PrintView.js');
|
|
473
|
+
void printModulePromise.catch(function reportPrintModuleFailure(error){
|
|
474
|
+
arcaneLogging.error('Unable to load rendered printing:',error);
|
|
475
|
+
});
|
|
472
476
|
|
|
473
477
|
let activePreview=null;
|
|
478
|
+
let presentationController = new AbortController();
|
|
479
|
+
let uploadPresentationController = null;
|
|
480
|
+
let closingTask = null;
|
|
474
481
|
let markdownModulePromise=null;
|
|
475
482
|
let uploadDirectory='';
|
|
476
483
|
let initialized=false;
|
|
@@ -497,6 +504,8 @@
|
|
|
497
504
|
host.setDirectoryFilter=setDirectoryFilter;
|
|
498
505
|
host.select=select;
|
|
499
506
|
host.clearSelection=clearSelection;
|
|
507
|
+
host.close = closeFileManager;
|
|
508
|
+
host.printPreview=printPreview;
|
|
500
509
|
host.destroy=destroy;
|
|
501
510
|
|
|
502
511
|
Object.defineProperty(
|
|
@@ -1457,22 +1466,20 @@
|
|
|
1457
1466
|
}
|
|
1458
1467
|
}
|
|
1459
1468
|
|
|
1460
|
-
async function openDirectory(directory=''){
|
|
1461
|
-
if(
|
|
1469
|
+
async function openDirectory(directory = '', signal = presentationController.signal) {
|
|
1470
|
+
if (closingTask && !await closingTask) {
|
|
1471
|
+
return false;
|
|
1472
|
+
}
|
|
1473
|
+
if(destroyed||signal.aborted||!isVisibleDirectory(directory)){
|
|
1462
1474
|
return false;
|
|
1463
1475
|
}
|
|
1464
1476
|
const generation=++directoryOpenGeneration;
|
|
1465
|
-
const modal=await
|
|
1477
|
+
const modal = await waitForModal(
|
|
1466
1478
|
directoryModal,
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
property:'ready',
|
|
1470
|
-
event:'modal-ready',
|
|
1471
|
-
signal:lifecycleController.signal
|
|
1472
|
-
},
|
|
1473
|
-
{signal:lifecycleController.signal}
|
|
1479
|
+
['populate', 'open'],
|
|
1480
|
+
signal
|
|
1474
1481
|
);
|
|
1475
|
-
if(destroyed||generation!==directoryOpenGeneration||!isVisibleDirectory(directory)){
|
|
1482
|
+
if(!modal||destroyed||generation!==directoryOpenGeneration||!isVisibleDirectory(directory)){
|
|
1476
1483
|
return false;
|
|
1477
1484
|
}
|
|
1478
1485
|
const keys=await dbopfs.getAllKeys(directory);
|
|
@@ -1534,7 +1541,11 @@
|
|
|
1534
1541
|
}
|
|
1535
1542
|
|
|
1536
1543
|
async function openFile(directory='',fileName=''){
|
|
1537
|
-
|
|
1544
|
+
const signal = presentationController.signal;
|
|
1545
|
+
if (closingTask && !await closingTask) {
|
|
1546
|
+
return false;
|
|
1547
|
+
}
|
|
1548
|
+
if(destroyed||signal.aborted){
|
|
1538
1549
|
return false;
|
|
1539
1550
|
}
|
|
1540
1551
|
releasePreview(activePreview,'file-preview-replaced');
|
|
@@ -1543,7 +1554,12 @@
|
|
|
1543
1554
|
controller:new AbortController(),
|
|
1544
1555
|
generation,
|
|
1545
1556
|
urls:new Set(),
|
|
1546
|
-
media:new Set()
|
|
1557
|
+
media:new Set(),
|
|
1558
|
+
title:`${directory}/${fileName}`,
|
|
1559
|
+
rendered:null,
|
|
1560
|
+
printPreparation:null,
|
|
1561
|
+
printRetains:0,
|
|
1562
|
+
released:false
|
|
1547
1563
|
};
|
|
1548
1564
|
activePreview=preview;
|
|
1549
1565
|
let modal;
|
|
@@ -1577,8 +1593,20 @@
|
|
|
1577
1593
|
const deleteButton=document.createElement('button');
|
|
1578
1594
|
const deleteIcon=document.createElement('img');
|
|
1579
1595
|
const status=document.createElement('p');
|
|
1596
|
+
const printButton=document.createElement('button');
|
|
1580
1597
|
|
|
1581
1598
|
heading.innerText=`${directory}/${fileName}`;
|
|
1599
|
+
printButton.type='button';
|
|
1600
|
+
printButton.textContent='Print';
|
|
1601
|
+
printButton.disabled=true;
|
|
1602
|
+
preview.printButton=printButton;
|
|
1603
|
+
preview.printStatus=status;
|
|
1604
|
+
preview.container=content;
|
|
1605
|
+
printButton.addEventListener('click',function printOpenPreview(){
|
|
1606
|
+
void printPreview().catch(function reportPrintRejection(error){
|
|
1607
|
+
reportPreviewPrintFailure(error,preview);
|
|
1608
|
+
});
|
|
1609
|
+
},{signal:preview.controller.signal});
|
|
1582
1610
|
actions.className='file-view-actions';
|
|
1583
1611
|
deleteButton.type='button';
|
|
1584
1612
|
deleteButton.className='file-view-delete';
|
|
@@ -1598,7 +1626,7 @@
|
|
|
1598
1626
|
};
|
|
1599
1627
|
status.innerText='Opening file...';
|
|
1600
1628
|
status.setAttribute('role','status');
|
|
1601
|
-
actions.append(deleteButton);
|
|
1629
|
+
actions.append(printButton,deleteButton);
|
|
1602
1630
|
content.append(
|
|
1603
1631
|
styles,
|
|
1604
1632
|
heading,
|
|
@@ -1631,6 +1659,10 @@
|
|
|
1631
1659
|
}
|
|
1632
1660
|
status.remove();
|
|
1633
1661
|
content.append(rendered);
|
|
1662
|
+
preview.rendered=rendered;
|
|
1663
|
+
void preparePreviewPrint(preview).catch(function reportPrintPreparation(error){
|
|
1664
|
+
reportPreviewPrintFailure(error,preview);
|
|
1665
|
+
});
|
|
1634
1666
|
return true;
|
|
1635
1667
|
}catch(error){
|
|
1636
1668
|
if(isCurrentPreview(preview)){
|
|
@@ -1643,6 +1675,69 @@
|
|
|
1643
1675
|
}
|
|
1644
1676
|
}
|
|
1645
1677
|
|
|
1678
|
+
function preparePreviewPrint(preview){
|
|
1679
|
+
if(!preview.printPreparation){
|
|
1680
|
+
preview.printPreparation=printModulePromise.then(function registerPreviewPrint({createPrintView}){
|
|
1681
|
+
if(!isCurrentPreview(preview)||!preview.rendered){
|
|
1682
|
+
return null;
|
|
1683
|
+
}
|
|
1684
|
+
const view=createPrintView({
|
|
1685
|
+
host,
|
|
1686
|
+
content:()=>preview.rendered,
|
|
1687
|
+
title:()=>preview.title,
|
|
1688
|
+
active:()=>isCurrentPreview(preview)&&fileModal.opened===true,
|
|
1689
|
+
priority:1,
|
|
1690
|
+
signal:preview.controller.signal,
|
|
1691
|
+
retain:()=>retainPreviewPrintResources(preview),
|
|
1692
|
+
onError:error=>reportPreviewPrintFailure(error,preview)
|
|
1693
|
+
});
|
|
1694
|
+
preview.printButton.disabled=false;
|
|
1695
|
+
return view;
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
return preview.printPreparation;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
async function printPreview(){
|
|
1702
|
+
const preview=activePreview;
|
|
1703
|
+
if(!preview?.rendered||!isCurrentPreview(preview)||fileModal.opened!==true){
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
const view=await preparePreviewPrint(preview);
|
|
1707
|
+
return view&&isCurrentPreview(preview)?view.print():false;
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
function reportPreviewPrintFailure(error,preview){
|
|
1711
|
+
arcaneLogging.error('Unable to print file preview:',error);
|
|
1712
|
+
if(isCurrentPreview(preview)){
|
|
1713
|
+
preview.printStatus.textContent='Unable to open print preview. Please try again.';
|
|
1714
|
+
preview.printStatus.setAttribute('role','alert');
|
|
1715
|
+
preview.container.append(preview.printStatus);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
function retainPreviewPrintResources(preview){
|
|
1720
|
+
preview.printRetains+=1;
|
|
1721
|
+
let retained=true;
|
|
1722
|
+
return function releasePrintedPreviewResources(){
|
|
1723
|
+
if(!retained){
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
retained=false;
|
|
1727
|
+
preview.printRetains-=1;
|
|
1728
|
+
if(preview.released&&preview.printRetains===0){
|
|
1729
|
+
releasePreviewURLs(preview);
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
function releasePreviewURLs(preview){
|
|
1735
|
+
for(const url of preview.urls){
|
|
1736
|
+
URL.revokeObjectURL(url);
|
|
1737
|
+
}
|
|
1738
|
+
preview.urls.clear();
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1646
1741
|
function configureFileModal(modal){
|
|
1647
1742
|
const appearance=getComputedStyle(host);
|
|
1648
1743
|
for(const property of ['--modal-width','--modal-max-height','--modal-padding']){
|
|
@@ -1660,9 +1755,10 @@
|
|
|
1660
1755
|
}
|
|
1661
1756
|
|
|
1662
1757
|
function releasePreview(preview,reason){
|
|
1663
|
-
if(!preview){
|
|
1758
|
+
if(!preview||preview.released){
|
|
1664
1759
|
return;
|
|
1665
1760
|
}
|
|
1761
|
+
preview.released=true;
|
|
1666
1762
|
preview.controller.abort(reason);
|
|
1667
1763
|
for(const element of preview.media){
|
|
1668
1764
|
if(element.localName==='audio'){
|
|
@@ -1676,11 +1772,10 @@
|
|
|
1676
1772
|
element.load();
|
|
1677
1773
|
}
|
|
1678
1774
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
1775
|
+
if(preview.printRetains===0){
|
|
1776
|
+
releasePreviewURLs(preview);
|
|
1681
1777
|
}
|
|
1682
1778
|
preview.media.clear();
|
|
1683
|
-
preview.urls.clear();
|
|
1684
1779
|
if(activePreview===preview){
|
|
1685
1780
|
activePreview=null;
|
|
1686
1781
|
}
|
|
@@ -2091,8 +2186,12 @@
|
|
|
2091
2186
|
|
|
2092
2187
|
openButton.addEventListener(
|
|
2093
2188
|
'click',
|
|
2094
|
-
async()
|
|
2189
|
+
async function openSelectedFile() {
|
|
2190
|
+
const signal = presentationController.signal;
|
|
2095
2191
|
await select(entry.path,{entry:entry});
|
|
2192
|
+
if (destroyed || signal.aborted) {
|
|
2193
|
+
return;
|
|
2194
|
+
}
|
|
2096
2195
|
const detail={path:entry.path,entry:entry,trigger:'click'};
|
|
2097
2196
|
const operationId=nextOperationId('open');
|
|
2098
2197
|
const openAllowed=emit('file-manager-open',detail,true,operationId);
|
|
@@ -2130,21 +2229,21 @@
|
|
|
2130
2229
|
}
|
|
2131
2230
|
|
|
2132
2231
|
async function confirmDelete(directory='',fileName='',closeFile=false){
|
|
2133
|
-
|
|
2232
|
+
const signal = presentationController.signal;
|
|
2233
|
+
if (closingTask && !await closingTask) {
|
|
2234
|
+
return false;
|
|
2235
|
+
}
|
|
2236
|
+
if(destroyed||signal.aborted||!directory||!fileName){
|
|
2134
2237
|
return false;
|
|
2135
2238
|
}
|
|
2136
2239
|
const generation=++deleteGeneration;
|
|
2137
2240
|
|
|
2138
|
-
const modal=await
|
|
2241
|
+
const modal = await waitForModal(
|
|
2139
2242
|
deleteModal,
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
property:'ready',
|
|
2143
|
-
event:'modal-ready',
|
|
2144
|
-
signal:lifecycleController.signal
|
|
2145
|
-
}
|
|
2243
|
+
['populate', 'open', 'close'],
|
|
2244
|
+
signal
|
|
2146
2245
|
);
|
|
2147
|
-
if(destroyed||generation!==deleteGeneration){
|
|
2246
|
+
if(!modal||destroyed||generation!==deleteGeneration){
|
|
2148
2247
|
return false;
|
|
2149
2248
|
}
|
|
2150
2249
|
const content=document.createElement('section');
|
|
@@ -2168,12 +2267,19 @@
|
|
|
2168
2267
|
deleteButton.addEventListener(
|
|
2169
2268
|
'click',
|
|
2170
2269
|
async function deleteSelectedFile(){
|
|
2270
|
+
if (destroyed || signal.aborted || generation !== deleteGeneration) {
|
|
2271
|
+
return;
|
|
2272
|
+
}
|
|
2171
2273
|
cancelButton.disabled=true;
|
|
2172
2274
|
deleteButton.disabled=true;
|
|
2173
2275
|
|
|
2174
2276
|
try{
|
|
2175
2277
|
await dbopfs.delete(directory,fileName);
|
|
2176
|
-
if(destroyed
|
|
2278
|
+
if(destroyed){
|
|
2279
|
+
return;
|
|
2280
|
+
}
|
|
2281
|
+
if (generation !== deleteGeneration) {
|
|
2282
|
+
await loadAll();
|
|
2177
2283
|
return;
|
|
2178
2284
|
}
|
|
2179
2285
|
await modal.close(undefined,true);
|
|
@@ -2201,7 +2307,9 @@
|
|
|
2201
2307
|
message.innerText=`Unable to delete ${fileName}.`;
|
|
2202
2308
|
cancelButton.disabled=false;
|
|
2203
2309
|
deleteButton.disabled=false;
|
|
2204
|
-
|
|
2310
|
+
}
|
|
2311
|
+
if (!destroyed) {
|
|
2312
|
+
arcaneLogging.error('Unable to delete file:', error);
|
|
2205
2313
|
}
|
|
2206
2314
|
}
|
|
2207
2315
|
},
|
|
@@ -2230,6 +2338,7 @@
|
|
|
2230
2338
|
}
|
|
2231
2339
|
|
|
2232
2340
|
uploadDirectory=directory;
|
|
2341
|
+
uploadPresentationController = presentationController;
|
|
2233
2342
|
fileUpload.click();
|
|
2234
2343
|
}
|
|
2235
2344
|
|
|
@@ -2239,6 +2348,8 @@
|
|
|
2239
2348
|
}
|
|
2240
2349
|
const files=Array.from(fileUpload.files||[]);
|
|
2241
2350
|
const directory=uploadDirectory;
|
|
2351
|
+
const presentation = uploadPresentationController || presentationController;
|
|
2352
|
+
uploadPresentationController = null;
|
|
2242
2353
|
fileUpload.value='';
|
|
2243
2354
|
|
|
2244
2355
|
if(!files.length||!directory){
|
|
@@ -2269,8 +2380,8 @@
|
|
|
2269
2380
|
return false;
|
|
2270
2381
|
}
|
|
2271
2382
|
|
|
2272
|
-
if(layout==='grid'){
|
|
2273
|
-
await openDirectory(directory);
|
|
2383
|
+
if(layout==='grid' && !presentation.signal.aborted){
|
|
2384
|
+
await openDirectory(directory, presentation.signal);
|
|
2274
2385
|
}
|
|
2275
2386
|
|
|
2276
2387
|
const failed=results.find(
|
|
@@ -2309,6 +2420,76 @@
|
|
|
2309
2420
|
}
|
|
2310
2421
|
}
|
|
2311
2422
|
|
|
2423
|
+
async function waitForModal(modal, methods, signal) {
|
|
2424
|
+
try {
|
|
2425
|
+
return await waitForComponent(
|
|
2426
|
+
modal,
|
|
2427
|
+
{
|
|
2428
|
+
methods,
|
|
2429
|
+
property: 'ready',
|
|
2430
|
+
event: 'modal-ready',
|
|
2431
|
+
signal
|
|
2432
|
+
}
|
|
2433
|
+
);
|
|
2434
|
+
} catch (error) {
|
|
2435
|
+
if (signal.aborted) {
|
|
2436
|
+
return null;
|
|
2437
|
+
}
|
|
2438
|
+
throw error;
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
async function closeFileManager() {
|
|
2443
|
+
if (destroyed) {
|
|
2444
|
+
return false;
|
|
2445
|
+
}
|
|
2446
|
+
presentationController.abort('file-manager-closed');
|
|
2447
|
+
presentationController = new AbortController();
|
|
2448
|
+
treeOpenGeneration += 1;
|
|
2449
|
+
directoryOpenGeneration += 1;
|
|
2450
|
+
deleteGeneration += 1;
|
|
2451
|
+
selectionGeneration += 1;
|
|
2452
|
+
// Cancel unfinished opens now; a settled preview remains usable until
|
|
2453
|
+
// its modal actually closes, including when a child refuses to close.
|
|
2454
|
+
if (!activePreview?.rendered) {
|
|
2455
|
+
fileOpenGeneration += 1;
|
|
2456
|
+
releasePreview(activePreview, 'file-manager-closed');
|
|
2457
|
+
}
|
|
2458
|
+
if (closingTask) {
|
|
2459
|
+
return closingTask;
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
closingTask = Promise.resolve().then(closeOwnedDialogs);
|
|
2463
|
+
try {
|
|
2464
|
+
return await closingTask;
|
|
2465
|
+
} finally {
|
|
2466
|
+
closingTask = null;
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
async function closeOwnedDialogs() {
|
|
2471
|
+
try {
|
|
2472
|
+
for (const modal of [deleteModal, fileModal, directoryModal]) {
|
|
2473
|
+
if (destroyed) {
|
|
2474
|
+
return false;
|
|
2475
|
+
}
|
|
2476
|
+
if (is.function(modal.close)) {
|
|
2477
|
+
const closed = await modal.close();
|
|
2478
|
+
if (closed === false) {
|
|
2479
|
+
return false;
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
if (modal.opened === true) {
|
|
2483
|
+
return false;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
return !destroyed;
|
|
2487
|
+
} catch (error) {
|
|
2488
|
+
arcaneLogging.error('Unable to close file manager:', error);
|
|
2489
|
+
return false;
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2312
2493
|
function destroy(){
|
|
2313
2494
|
if(destroyed){
|
|
2314
2495
|
return false;
|
|
@@ -2317,6 +2498,7 @@
|
|
|
2317
2498
|
initialized=false;
|
|
2318
2499
|
host.ready=false;
|
|
2319
2500
|
lifecycleController.abort('file-manager-destroyed');
|
|
2501
|
+
presentationController.abort('file-manager-destroyed');
|
|
2320
2502
|
treeLoadSequence+=1;
|
|
2321
2503
|
gridLoadSequence+=1;
|
|
2322
2504
|
providerGeneration+=1;
|
|
@@ -118,6 +118,7 @@
|
|
|
118
118
|
<textarea id="entryMarkdown" class="entry-markdown" part="input"></textarea>
|
|
119
119
|
<section class="actions" part="actions">
|
|
120
120
|
<span id="status" class="status" part="status" aria-live="polite"></span>
|
|
121
|
+
<button id="print" part="print-action" type="button">Print</button>
|
|
121
122
|
<button id="save" part="save-action" type="button" disabled></button>
|
|
122
123
|
</section>
|
|
123
124
|
</section>
|
|
@@ -143,6 +144,7 @@
|
|
|
143
144
|
const toolbar=host.shadowRoot.querySelector('#toolbar');
|
|
144
145
|
const textarea=host.shadowRoot.querySelector('#entryMarkdown');
|
|
145
146
|
const saveButton=host.shadowRoot.querySelector('#save');
|
|
147
|
+
const printButton=host.shadowRoot.querySelector('#print');
|
|
146
148
|
const status=host.shadowRoot.querySelector('#status');
|
|
147
149
|
|
|
148
150
|
let previewFrame=0;
|
|
@@ -152,6 +154,23 @@
|
|
|
152
154
|
let saveController=null;
|
|
153
155
|
let destroyed=false;
|
|
154
156
|
let options=normalizeMarkdownOptions(optionsFromDataset());
|
|
157
|
+
// Printing loads independently of editor readiness and owns no saved state.
|
|
158
|
+
const printViewPromise=import('../modules/PrintView.js').then(
|
|
159
|
+
function prepareEditorPrint({createPrintView}){
|
|
160
|
+
if(destroyed){
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
return createPrintView({
|
|
164
|
+
host,
|
|
165
|
+
content:renderedPrintContent,
|
|
166
|
+
title:()=>titleInput.value,
|
|
167
|
+
active:()=>!destroyed&&host.isConnected&&host.getClientRects().length>0,
|
|
168
|
+
signal:lifecycleController.signal,
|
|
169
|
+
onError:reportPrintFailure
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
void printViewPromise.catch(reportPrintFailure);
|
|
155
174
|
|
|
156
175
|
function emit(type,detail={},publicDetail={},operationId=null){
|
|
157
176
|
if(destroyed){
|
|
@@ -166,6 +185,8 @@
|
|
|
166
185
|
host.destroy=destroy;
|
|
167
186
|
host.focus=()=>{if(destroyed)return false;textarea.focus();return true;};
|
|
168
187
|
host.saveEntry=saveEntry;
|
|
188
|
+
host.print=print;
|
|
189
|
+
host.insertMarkdown=insertMarkdown;
|
|
169
190
|
|
|
170
191
|
Object.defineProperties(
|
|
171
192
|
host,
|
|
@@ -184,6 +205,7 @@
|
|
|
184
205
|
titleInput.addEventListener('input',contentChanged,{signal:lifecycleController.signal});
|
|
185
206
|
toolbar.addEventListener('click',formatMarkdown,{signal:lifecycleController.signal});
|
|
186
207
|
saveButton.addEventListener('click',saveEntry,{signal:lifecycleController.signal});
|
|
208
|
+
printButton.addEventListener('click',printFromControl,{signal:lifecycleController.signal});
|
|
187
209
|
for(const type of ['wheel','pointerdown','touchstart','keydown']){
|
|
188
210
|
preview.addEventListener(type,retainPreviewReadingPosition,{signal:lifecycleController.signal,passive:true});
|
|
189
211
|
}
|
|
@@ -488,6 +510,24 @@
|
|
|
488
510
|
contentChanged();
|
|
489
511
|
}
|
|
490
512
|
|
|
513
|
+
function insertMarkdown(markdown){
|
|
514
|
+
if(destroyed||options.readOnly){
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
if(!is.string(markdown)){
|
|
518
|
+
throw new TypeError('Markdown insertion requires a string.');
|
|
519
|
+
}
|
|
520
|
+
const sourceView=captureSourceView();
|
|
521
|
+
textarea.setRangeText(markdown,sourceView.selectionStart,sourceView.selectionEnd,'end');
|
|
522
|
+
sourceView.selectionStart+=markdown.length;
|
|
523
|
+
sourceView.selectionEnd=sourceView.selectionStart;
|
|
524
|
+
sourceView.selectionDirection='none';
|
|
525
|
+
textarea.focus({preventScroll:true});
|
|
526
|
+
restoreSourceView(sourceView);
|
|
527
|
+
contentChanged();
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
|
|
491
531
|
async function saveEntry(){
|
|
492
532
|
if(destroyed||options.readOnly||!options.showSave){
|
|
493
533
|
return false;
|
|
@@ -548,6 +588,36 @@
|
|
|
548
588
|
return resetEditor(true);
|
|
549
589
|
}
|
|
550
590
|
|
|
591
|
+
function renderedPrintContent(){
|
|
592
|
+
return preview;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async function print(){
|
|
596
|
+
if(destroyed){
|
|
597
|
+
return false;
|
|
598
|
+
}
|
|
599
|
+
const printView=await printViewPromise;
|
|
600
|
+
if(destroyed||!printView){
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
if(previewFrame){
|
|
604
|
+
updatePreview(false);
|
|
605
|
+
}
|
|
606
|
+
return printView.print();
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function printFromControl(){
|
|
610
|
+
void print().catch(reportPrintFailure);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function reportPrintFailure(error){
|
|
614
|
+
if(destroyed||lifecycleController.signal.aborted){
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
arcaneLogging.error('Unable to print rendered Markdown:',error);
|
|
618
|
+
status.innerText='Unable to open print preview. Please try again.';
|
|
619
|
+
}
|
|
620
|
+
|
|
551
621
|
function resetEditor(supersede){
|
|
552
622
|
if(destroyed){
|
|
553
623
|
return false;
|
|
@@ -292,9 +292,13 @@
|
|
|
292
292
|
modalStack.push(host);
|
|
293
293
|
|
|
294
294
|
if(!wasOpen){
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
295
|
+
let focusedElement = document.activeElement;
|
|
296
|
+
while (focusedElement?.shadowRoot?.activeElement) {
|
|
297
|
+
focusedElement = focusedElement.shadowRoot.activeElement;
|
|
298
|
+
}
|
|
299
|
+
returnFocus = focusedElement instanceof HTMLElement
|
|
300
|
+
? focusedElement
|
|
301
|
+
: null;
|
|
298
302
|
dialog.showModal();
|
|
299
303
|
queueMicrotask(focusOpenedModal);
|
|
300
304
|
emit('modal-opened',{}, {opened:true});
|
|
@@ -326,7 +330,7 @@
|
|
|
326
330
|
const target=returnFocus;
|
|
327
331
|
returnFocus=null;
|
|
328
332
|
queueMicrotask(function restoreModalReturnFocus(){
|
|
329
|
-
if(target?.isConnected){
|
|
333
|
+
if(target?.isConnected && !dialog.open){
|
|
330
334
|
target.focus({preventScroll:true});
|
|
331
335
|
}
|
|
332
336
|
});
|