retold-content-system 1.0.12 → 1.0.13

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.
@@ -2781,18 +2781,45 @@ let tmpCached=tmpBrowseProvider.getChildFolders(pPath);if(!tmpCached){if(typeof
2781
2781
  * Get the current location from state.
2782
2782
  *
2783
2783
  * @returns {string} The current location path
2784
- */getCurrentLocation(){let tmpStateAddresses=this.options.StateAddresses||{};let tmpAddress=tmpStateAddresses.CurrentLocation||'AppData.PictFileBrowser.CurrentLocation';return this.pict.manifest.getValueByHash({AppData:this.pict.AppData,Pict:this.pict},tmpAddress)||'';}}module.exports=PictViewFileBrowserBrowseTree;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":88}],72:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={"ViewIdentifier":"Pict-FileBrowser-ListDetail","DefaultRenderable":"ListDetail-Container","DefaultDestinationAddress":"#Pict-FileBrowser-ListPane","AutoRender":false,"Templates":[{"Hash":"FileBrowser-ListDetail-Container-Template","Template":/*html*/"\n<div class=\"pict-fb-detail\" id=\"Pict-FileBrowser-DetailList\">\n\t<div class=\"pict-fb-breadcrumb\" id=\"Pict-FileBrowser-Breadcrumb\"></div>\n\t<div class=\"pict-fb-detail-header\">\n\t\t<div class=\"pict-fb-detail-header-cell pict-fb-detail-col-name\" onclick=\"pict.views['{~D:Record.ViewHash~}'].sortBy('Name')\">Name</div>\n\t\t<div class=\"pict-fb-detail-header-cell pict-fb-detail-col-size\" onclick=\"pict.views['{~D:Record.ViewHash~}'].sortBy('Size')\">Size</div>\n\t\t<div class=\"pict-fb-detail-header-cell pict-fb-detail-col-modified\" onclick=\"pict.views['{~D:Record.ViewHash~}'].sortBy('Modified')\">Modified</div>\n\t</div>\n\t<div id=\"Pict-FileBrowser-DetailRows\"></div>\n</div>\n"},{"Hash":"FileBrowser-ListDetail-Row-Template","Template":/*html*/"\n<div class=\"pict-fb-detail-row{~D:Record.SelectedClass~}\" data-index=\"{~D:Record.Index~}\" onclick=\"{~D:Record.ClickHandler~}\" ondblclick=\"{~D:Record.DblClickHandler~}\">\n\t<span class=\"pict-fb-detail-icon\">{~D:Record.Icon~}</span>\n\t<span class=\"pict-fb-detail-name\">{~D:Record.Name~}</span>\n\t<span class=\"pict-fb-detail-size\">{~D:Record.SizeFormatted~}</span>\n\t<span class=\"pict-fb-detail-modified\">{~D:Record.ModifiedFormatted~}</span>\n</div>\n"},{"Hash":"FileBrowser-ListDetail-Empty-Template","Template":/*html*/"<div class=\"pict-fb-empty\">{~D:Record.Message~}</div>"},{"Hash":"FileBrowser-Breadcrumb-Segment-Template","Template":/*html*/"<span class=\"pict-fb-breadcrumb-segment\" onclick=\"{~D:Record.ClickHandler~}\">{~D:Record.Label~}</span>"},{"Hash":"FileBrowser-Breadcrumb-Separator-Template","Template":/*html*/"<span class=\"pict-fb-breadcrumb-separator\">/</span>"},{"Hash":"FileBrowser-Breadcrumb-Current-Template","Template":/*html*/"<span class=\"pict-fb-breadcrumb-current\">{~D:Record.Label~}</span>"}],"Renderables":[{"RenderableHash":"ListDetail-Container","TemplateHash":"FileBrowser-ListDetail-Container-Template","DestinationAddress":"#Pict-FileBrowser-ListPane","RenderMethod":"replace"}]};/**
2784
+ */getCurrentLocation(){let tmpStateAddresses=this.options.StateAddresses||{};let tmpAddress=tmpStateAddresses.CurrentLocation||'AppData.PictFileBrowser.CurrentLocation';return this.pict.manifest.getValueByHash({AppData:this.pict.AppData,Pict:this.pict},tmpAddress)||'';}}module.exports=PictViewFileBrowserBrowseTree;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":88}],72:[function(require,module,exports){const libPictView=require('pict-view');// Chunked rendering constants for folders with very large file counts
2785
+ // we render rows in chunks via requestAnimationFrame so the main thread
2786
+ // stays responsive instead of freezing on one massive assignContent call.
2787
+ const _CHUNKED_RENDER_THRESHOLD=500;const _CHUNK_FIRST_SIZE=200;const _CHUNK_SUBSEQUENT_SIZE=400;const _ViewConfiguration={"ViewIdentifier":"Pict-FileBrowser-ListDetail","DefaultRenderable":"ListDetail-Container","DefaultDestinationAddress":"#Pict-FileBrowser-ListPane","AutoRender":false,"Templates":[{"Hash":"FileBrowser-ListDetail-Container-Template","Template":/*html*/"\n<div class=\"pict-fb-detail\" id=\"Pict-FileBrowser-DetailList\">\n\t<div class=\"pict-fb-breadcrumb\" id=\"Pict-FileBrowser-Breadcrumb\"></div>\n\t<div class=\"pict-fb-detail-header\">\n\t\t<div class=\"pict-fb-detail-header-cell pict-fb-detail-col-name\" onclick=\"pict.views['{~D:Record.ViewHash~}'].sortBy('Name')\">Name</div>\n\t\t<div class=\"pict-fb-detail-header-cell pict-fb-detail-col-size\" onclick=\"pict.views['{~D:Record.ViewHash~}'].sortBy('Size')\">Size</div>\n\t\t<div class=\"pict-fb-detail-header-cell pict-fb-detail-col-modified\" onclick=\"pict.views['{~D:Record.ViewHash~}'].sortBy('Modified')\">Modified</div>\n\t</div>\n\t<div id=\"Pict-FileBrowser-DetailRows\"></div>\n</div>\n"},{"Hash":"FileBrowser-ListDetail-Row-Template","Template":/*html*/"\n<div class=\"pict-fb-detail-row{~D:Record.SelectedClass~}\" data-index=\"{~D:Record.Index~}\" onclick=\"{~D:Record.ClickHandler~}\" ondblclick=\"{~D:Record.DblClickHandler~}\">\n\t<span class=\"pict-fb-detail-icon\">{~D:Record.Icon~}</span>\n\t<span class=\"pict-fb-detail-name\">{~D:Record.Name~}</span>\n\t<span class=\"pict-fb-detail-size\">{~D:Record.SizeFormatted~}</span>\n\t<span class=\"pict-fb-detail-modified\">{~D:Record.ModifiedFormatted~}</span>\n</div>\n"},{"Hash":"FileBrowser-ListDetail-Empty-Template","Template":/*html*/"<div class=\"pict-fb-empty\">{~D:Record.Message~}</div>"},{"Hash":"FileBrowser-Breadcrumb-Segment-Template","Template":/*html*/"<span class=\"pict-fb-breadcrumb-segment\" onclick=\"{~D:Record.ClickHandler~}\">{~D:Record.Label~}</span>"},{"Hash":"FileBrowser-Breadcrumb-Separator-Template","Template":/*html*/"<span class=\"pict-fb-breadcrumb-separator\">/</span>"},{"Hash":"FileBrowser-Breadcrumb-Current-Template","Template":/*html*/"<span class=\"pict-fb-breadcrumb-current\">{~D:Record.Label~}</span>"}],"Renderables":[{"RenderableHash":"ListDetail-Container","TemplateHash":"FileBrowser-ListDetail-Container-Template","DestinationAddress":"#Pict-FileBrowser-ListPane","RenderMethod":"replace"}]};/**
2785
2788
  * Listing view that shows files in a detailed table with columns for
2786
2789
  * name, size, and modified date.
2787
2790
  *
2788
2791
  * Supports sorting by column header click and single-click selection
2789
2792
  * with double-click to open folders.
2790
- */class PictViewFileBrowserListDetail extends libPictView{constructor(pFable,pOptions,pServiceHash){let tmpOptions=Object.assign({},_ViewConfiguration,pOptions);super(pFable,tmpOptions,pServiceHash);this._cachedFileList=[];}/**
2793
+ */class PictViewFileBrowserListDetail extends libPictView{constructor(pFable,pOptions,pServiceHash){let tmpOptions=Object.assign({},_ViewConfiguration,pOptions);super(pFable,tmpOptions,pServiceHash);this._cachedFileList=[];// Chunked render state
2794
+ this._activeRebuildFrame=null;this._activeRebuildToken=0;}/**
2795
+ * Cancel any in-flight chunked rebuild so it does not overlap with a
2796
+ * fresh navigation.
2797
+ */_cancelActiveRebuild(){if(this._activeRebuildFrame!==null&&typeof cancelAnimationFrame==='function'){cancelAnimationFrame(this._activeRebuildFrame);this._activeRebuildFrame=null;}this._activeRebuildToken++;}/**
2791
2798
  * After rendering the container shell, populate the rows.
2792
2799
  */onAfterRender(pRenderable){// Render the container with the view hash
2793
2800
  let tmpContainerHTML=this.pict.parseTemplateByHash('FileBrowser-ListDetail-Container-Template',{ViewHash:this.Hash});this.pict.ContentAssignment.assignContent('#Pict-FileBrowser-ListPane',tmpContainerHTML);this.rebuildList();this.rebuildBreadcrumb();this.pict.CSSMap.injectCSS();return super.onAfterRender(pRenderable);}/**
2794
2801
  * Rebuild the file list rows.
2795
- */rebuildList(){let tmpListProvider=this.pict.providers['Pict-FileBrowser-List'];if(!tmpListProvider){return;}let tmpFileList=tmpListProvider.getSortedFileList();this._cachedFileList=tmpFileList;let tmpSelectedFile=tmpListProvider.getSelectedFile();if(tmpFileList.length===0){let tmpEmptyHTML=this.pict.parseTemplateByHash('FileBrowser-ListDetail-Empty-Template',{Message:'This folder is empty'});this.pict.ContentAssignment.assignContent('#Pict-FileBrowser-DetailRows',tmpEmptyHTML);return;}let tmpHTML='';for(let i=0;i<tmpFileList.length;i++){let tmpEntry=tmpFileList[i];let tmpIsSelected=tmpSelectedFile&&tmpSelectedFile.Name===tmpEntry.Name&&tmpSelectedFile.Path===tmpEntry.Path;let tmpRecord={Index:i,Name:tmpEntry.Name,Icon:tmpListProvider.getEntryIcon(tmpEntry),SizeFormatted:tmpEntry.Type==='folder'?'--':tmpListProvider.formatFileSize(tmpEntry.Size),ModifiedFormatted:tmpListProvider.formatDate(tmpEntry.Modified),SelectedClass:tmpIsSelected?' selected':'',ClickHandler:"pict.views['"+this.Hash+"'].selectEntry("+i+")",DblClickHandler:"pict.views['"+this.Hash+"'].openEntry("+i+")"};tmpHTML+=this.pict.parseTemplateByHash('FileBrowser-ListDetail-Row-Template',tmpRecord);}this.pict.ContentAssignment.assignContent('#Pict-FileBrowser-DetailRows',tmpHTML);}/**
2802
+ *
2803
+ * For folders with more than _CHUNKED_RENDER_THRESHOLD items, the render
2804
+ * is split into chunks scheduled via requestAnimationFrame so the main
2805
+ * thread stays responsive. Smaller folders use the synchronous fast path.
2806
+ */rebuildList(){// Cancel any in-flight chunked rebuild from a previous folder
2807
+ this._cancelActiveRebuild();let tmpListProvider=this.pict.providers['Pict-FileBrowser-List'];if(!tmpListProvider){return;}let tmpFileList=tmpListProvider.getSortedFileList();this._cachedFileList=tmpFileList;let tmpSelectedFile=tmpListProvider.getSelectedFile();if(tmpFileList.length===0){let tmpEmptyHTML=this.pict.parseTemplateByHash('FileBrowser-ListDetail-Empty-Template',{Message:'This folder is empty'});this.pict.ContentAssignment.assignContent('#Pict-FileBrowser-DetailRows',tmpEmptyHTML);return;}// SMALL FOLDER FAST PATH — keep the existing synchronous behavior
2808
+ // for normal-sized folders so there's no perceptible change.
2809
+ if(tmpFileList.length<=_CHUNKED_RENDER_THRESHOLD){let tmpHTML='';for(let i=0;i<tmpFileList.length;i++){tmpHTML+=this._buildRowHTML(tmpFileList[i],i,tmpSelectedFile);}this.pict.ContentAssignment.assignContent('#Pict-FileBrowser-DetailRows',tmpHTML);return;}// LARGE FOLDER CHUNKED PATH — paint a loading row immediately, then
2810
+ // fill rows in chunks via requestAnimationFrame.
2811
+ let tmpLoadingHTML='<div class="retold-remote-filebrowser-loading-row">'+'Loading '+tmpFileList.length.toLocaleString()+' items\u2026'+'</div>';this.pict.ContentAssignment.assignContent('#Pict-FileBrowser-DetailRows',tmpLoadingHTML);this._rebuildListChunked(tmpFileList,tmpSelectedFile);}/**
2812
+ * Build the HTML for a single row. Extracted so both the fast path
2813
+ * and the chunked path can share it.
2814
+ */_buildRowHTML(pEntry,pIndex,pSelectedFile){let tmpListProvider=this.pict.providers['Pict-FileBrowser-List'];let tmpIsSelected=pSelectedFile&&pSelectedFile.Name===pEntry.Name&&pSelectedFile.Path===pEntry.Path;let tmpRecord={Index:pIndex,Name:pEntry.Name,Icon:tmpListProvider.getEntryIcon(pEntry),SizeFormatted:pEntry.Type==='folder'?'--':tmpListProvider.formatFileSize(pEntry.Size),ModifiedFormatted:tmpListProvider.formatDate(pEntry.Modified),SelectedClass:tmpIsSelected?' selected':'',ClickHandler:"pict.views['"+this.Hash+"'].selectEntry("+pIndex+")",DblClickHandler:"pict.views['"+this.Hash+"'].openEntry("+pIndex+")"};return this.pict.parseTemplateByHash('FileBrowser-ListDetail-Row-Template',tmpRecord);}/**
2815
+ * Render the file list into chunks via requestAnimationFrame.
2816
+ * After the first chunk replaces the loading row, each subsequent
2817
+ * chunk is appended to the rows container.
2818
+ */_rebuildListChunked(pFileList,pSelectedFile){let tmpSelf=this;let tmpToken=++this._activeRebuildToken;let tmpTotal=pFileList.length;let tmpOffset=0;let _renderNextChunk2=function _renderNextChunk(){if(tmpToken!==tmpSelf._activeRebuildToken){return;}let tmpRowsContainer=document.getElementById('Pict-FileBrowser-DetailRows');if(!tmpRowsContainer){return;}let tmpChunkSize=tmpOffset===0?_CHUNK_FIRST_SIZE:_CHUNK_SUBSEQUENT_SIZE;let tmpEnd=Math.min(tmpOffset+tmpChunkSize,tmpTotal);let tmpChunkHTML='';for(let i=tmpOffset;i<tmpEnd;i++){tmpChunkHTML+=tmpSelf._buildRowHTML(pFileList[i],i,pSelectedFile);}if(tmpOffset===0){// Replace the loading row on the first chunk
2819
+ tmpRowsContainer.innerHTML=tmpChunkHTML;}else{// Append subsequent chunks
2820
+ tmpRowsContainer.insertAdjacentHTML('beforeend',tmpChunkHTML);}tmpOffset=tmpEnd;if(tmpOffset<tmpTotal){tmpSelf._activeRebuildFrame=requestAnimationFrame(_renderNextChunk2);}else{tmpSelf._activeRebuildFrame=null;}};if(typeof requestAnimationFrame==='function'){this._activeRebuildFrame=requestAnimationFrame(_renderNextChunk2);}else{// No rAF (shouldn't happen in a browser, but be safe) — fall back
2821
+ // to synchronous render
2822
+ _renderNextChunk2();while(tmpOffset<tmpTotal){_renderNextChunk2();}}}/**
2796
2823
  * Rebuild the breadcrumb navigation bar.
2797
2824
  */rebuildBreadcrumb(){let tmpCurrentLocation=this.getCurrentLocation();let tmpHTML='';// Root segment — use SVG home icon if provider is available
2798
2825
  let tmpIconProvider=this.pict.providers['Pict-FileBrowser-Icons'];let tmpHomeLabel=tmpIconProvider?tmpIconProvider.getIcon('home',16):'\uD83C\uDFE0';tmpHTML+=this.pict.parseTemplateByHash('FileBrowser-Breadcrumb-Segment-Template',{Label:tmpHomeLabel,ClickHandler:"pict.views['"+this.Hash+"'].navigateToPath('')"});if(tmpCurrentLocation){let tmpParts=tmpCurrentLocation.split('/');let tmpAccumulatedPath='';for(let i=0;i<tmpParts.length;i++){tmpAccumulatedPath=tmpAccumulatedPath?tmpAccumulatedPath+'/'+tmpParts[i]:tmpParts[i];tmpHTML+=this.pict.parseTemplateByHash('FileBrowser-Breadcrumb-Separator-Template',{});if(i===tmpParts.length-1){// Last segment — not clickable
@@ -3770,13 +3797,29 @@ this.pict.ContentAssignment.projectContent(pRenderable.RenderMethod,pRenderable.
3770
3797
  *
3771
3798
  * @param {Renderable} pRenderable - The renderable that was rendered.
3772
3799
  */onAfterRender(pRenderable){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterRender:"));}if(pRenderable&&pRenderable.RootRenderableViewHash===this.Hash){const tmpTransactionQueue=this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash)||[];for(const tmpEvent of tmpTransactionQueue){const tmpView=this.pict.views[tmpEvent.Data.ViewHash];if(!tmpView){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterRender: Could not find view for transaction hash ").concat(pRenderable.TransactionHash," and ViewHash ").concat(tmpEvent.Data.ViewHash,"."));continue;}tmpView.onAfterProject();// Execute the developer-overridable post-render behavior
3773
- tmpView.onAfterRender(tmpEvent.Data.Renderable);}}return true;}/**
3800
+ tmpView.onAfterRender(tmpEvent.Data.Renderable);}// Queue is drained and nested child renders have each cleaned up
3801
+ // their own transactions; remove this root render's entry from
3802
+ // the tracking map so it does not leak.
3803
+ this.pict.TransactionTracking.unregisterTransaction(pRenderable.TransactionHash);}return true;}/**
3774
3804
  * Lifecycle hook that triggers after the view is rendered (async flow).
3775
3805
  *
3776
3806
  * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3777
3807
  * @param {Renderable} pRenderable - The renderable that was rendered.
3778
- */onAfterRenderAsync(fCallback,pRenderable){this.onAfterRender(pRenderable);const tmpAnticipate=this.fable.newAnticipate();if(pRenderable&&pRenderable.RootRenderableViewHash===this.Hash){const queue=this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash)||[];for(const event of queue){/** @type {PictView} */const tmpView=this.pict.views[event.Data.ViewHash];if(!tmpView){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterRenderAsync: Could not find view for transaction hash ").concat(pRenderable.TransactionHash," and ViewHash ").concat(event.Data.ViewHash,"."));continue;}tmpAnticipate.anticipate(tmpView.onAfterProjectAsync.bind(tmpView));tmpAnticipate.anticipate(fNext=>{tmpView.onAfterRenderAsync(fNext,event.Data.Renderable);});// Execute the developer-overridable post-render behavior
3779
- }}return tmpAnticipate.wait(fCallback);}/**
3808
+ */onAfterRenderAsync(fCallback,pRenderable){// NOTE: this.onAfterRender(pRenderable) will itself clear the
3809
+ // transaction queue and unregister the transaction if this view is
3810
+ // the root renderable - see onAfterRender above. So by the time the
3811
+ // loop below runs, the queue is already empty and there is nothing
3812
+ // to drain. Keeping the async queue walk here defensively in case
3813
+ // future subclasses override onAfterRender in ways that skip the
3814
+ // drain, but the common path is now "sync drain, async no-op".
3815
+ this.onAfterRender(pRenderable);const tmpAnticipate=this.fable.newAnticipate();const tmpIsRootRenderable=pRenderable&&pRenderable.RootRenderableViewHash===this.Hash;if(tmpIsRootRenderable){const queue=this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash)||[];for(const event of queue){/** @type {PictView} */const tmpView=this.pict.views[event.Data.ViewHash];if(!tmpView){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterRenderAsync: Could not find view for transaction hash ").concat(pRenderable.TransactionHash," and ViewHash ").concat(event.Data.ViewHash,"."));continue;}tmpAnticipate.anticipate(tmpView.onAfterProjectAsync.bind(tmpView));tmpAnticipate.anticipate(fNext=>{tmpView.onAfterRenderAsync(fNext,event.Data.Renderable);});// Execute the developer-overridable post-render behavior
3816
+ }}return tmpAnticipate.wait(pError=>{// Nested virtual-assignment children have now settled their own
3817
+ // onAfterRenderAsync chains (and unregistered their own
3818
+ // transactions along the way). Ensure this root render's entry
3819
+ // is also gone - unregisterTransaction is a no-op if the sync
3820
+ // onAfterRender above already removed it, so this is safe to
3821
+ // call unconditionally on the root path.
3822
+ if(tmpIsRootRenderable&&pRenderable&&pRenderable.TransactionHash){this.pict.TransactionTracking.unregisterTransaction(pRenderable.TransactionHash);}return fCallback(pError);});}/**
3780
3823
  * Lifecycle hook that triggers after the view is projected into the DOM.
3781
3824
  *
3782
3825
  * @param {Renderable} pRenderable - The renderable that was projected.