arcane-os 0.42.2 → 0.44.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.
@@ -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
- returnFocus=document.activeElement instanceof HTMLElement
296
- ?document.activeElement
297
- :null;
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
  });