meadow-integration 1.0.20 → 1.0.23

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.
Files changed (30) hide show
  1. package/example-applications/mapping-demo/.quackage.json +10 -0
  2. package/example-applications/mapping-demo/README.md +99 -0
  3. package/example-applications/mapping-demo/data/books-sample.csv +21 -0
  4. package/example-applications/mapping-demo/generate-build-config.js +44 -0
  5. package/example-applications/mapping-demo/mappings/books-to-book.json +14 -0
  6. package/example-applications/mapping-demo/package.json +14 -0
  7. package/example-applications/mapping-demo/server.js +814 -0
  8. package/example-applications/mapping-demo/source/MappingDemoApp.js +52 -0
  9. package/example-applications/mapping-demo/source/views/MappingDemoEditorView.js +186 -0
  10. package/example-applications/mapping-demo/web/index.html +892 -0
  11. package/example-applications/mapping-demo/web/mapping-demo-editor.js +3195 -0
  12. package/example-applications/mapping-demo/web/mapping-demo-editor.js.map +1 -0
  13. package/example-applications/mapping-demo/web/mapping-demo-editor.min.js +2 -0
  14. package/example-applications/mapping-demo/web/mapping-demo-editor.min.js.map +1 -0
  15. package/example-applications/mapping-demo/web/pict.min.js +12 -0
  16. package/package.json +8 -4
  17. package/source/Meadow-Integration-Browser.js +31 -0
  18. package/source/Meadow-Integration.js +16 -1
  19. package/source/services/certainty/Service-CertaintyAccumulator.js +402 -0
  20. package/source/services/clone/Meadow-Service-Sync-Entity-Initial.js +16 -3
  21. package/source/services/clone/Meadow-Service-Sync-Entity-Ongoing.js +15 -2
  22. package/source/services/clone/Meadow-Service-Sync.js +21 -0
  23. package/source/views/MappingEditor-SchemaUtils.js +71 -0
  24. package/source/views/PictView-MeadowMappingEditor.js +1299 -0
  25. package/source/views/flow-cards/FlowCard-MappingSource.js +50 -0
  26. package/source/views/flow-cards/FlowCard-MappingTarget.js +49 -0
  27. package/source/views/flow-cards/FlowCard-SolverExpression.js +78 -0
  28. package/source/views/flow-cards/FlowCard-TemplateExpression.js +77 -0
  29. package/test/Meadow-Integration-BisectionSync_test.js +1601 -0
  30. package/test/Meadow-Integration-CloneDeleteSync_test.js +809 -0
@@ -0,0 +1,3195 @@
1
+ "use strict";function _regenerator(){/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */var e,t,r="function"==typeof Symbol?Symbol:{},n=r.iterator||"@@iterator",o=r.toStringTag||"@@toStringTag";function i(r,n,o,i){var c=n&&n.prototype instanceof Generator?n:Generator,u=Object.create(c.prototype);return _regeneratorDefine2(u,"_invoke",function(r,n,o){var i,c,u,f=0,p=o||[],y=!1,G={p:0,n:0,v:e,a:d,f:d.bind(e,4),d:function d(t,r){return i=t,c=0,u=e,G.n=r,a;}};function d(r,n){for(c=r,u=n,t=0;!y&&f&&!o&&t<p.length;t++){var o,i=p[t],d=G.p,l=i[2];r>3?(o=l===n)&&(u=i[(c=i[4])?5:(c=3,3)],i[4]=i[5]=e):i[0]<=d&&((o=r<2&&d<i[1])?(c=0,G.v=n,G.n=i[1]):d<l&&(o=r<3||i[0]>n||n>l)&&(i[4]=r,i[5]=n,G.n=l,c=0));}if(o||r>1)return a;throw y=!0,n;}return function(o,p,l){if(f>1)throw TypeError("Generator is already running");for(y&&1===p&&d(p,l),c=p,u=l;(t=c<2?e:u)||!y;){i||(c?c<3?(c>1&&(G.n=-1),d(c,u)):G.n=u:G.v=u);try{if(f=2,i){if(c||(o="next"),t=i[o]){if(!(t=t.call(i,u)))throw TypeError("iterator result is not an object");if(!t.done)return t;u=t.value,c<2&&(c=0);}else 1===c&&(t=i["return"])&&t.call(i),c<2&&(u=TypeError("The iterator does not provide a '"+o+"' method"),c=1);i=e;}else if((t=(y=G.n<0)?u:r.call(n,G))!==a)break;}catch(t){i=e,c=1,u=t;}finally{f=1;}}return{value:t,done:y};};}(r,o,i),!0),u;}var a={};function Generator(){}function GeneratorFunction(){}function GeneratorFunctionPrototype(){}t=Object.getPrototypeOf;var c=[][n]?t(t([][n]())):(_regeneratorDefine2(t={},n,function(){return this;}),t),u=GeneratorFunctionPrototype.prototype=Generator.prototype=Object.create(c);function f(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,GeneratorFunctionPrototype):(e.__proto__=GeneratorFunctionPrototype,_regeneratorDefine2(e,o,"GeneratorFunction")),e.prototype=Object.create(u),e;}return GeneratorFunction.prototype=GeneratorFunctionPrototype,_regeneratorDefine2(u,"constructor",GeneratorFunctionPrototype),_regeneratorDefine2(GeneratorFunctionPrototype,"constructor",GeneratorFunction),GeneratorFunction.displayName="GeneratorFunction",_regeneratorDefine2(GeneratorFunctionPrototype,o,"GeneratorFunction"),_regeneratorDefine2(u),_regeneratorDefine2(u,o,"Generator"),_regeneratorDefine2(u,n,function(){return this;}),_regeneratorDefine2(u,"toString",function(){return"[object Generator]";}),(_regenerator=function _regenerator(){return{w:i,m:f};})();}function _regeneratorDefine2(e,r,n,t){var i=Object.defineProperty;try{i({},"",{});}catch(e){i=0;}_regeneratorDefine2=function _regeneratorDefine(e,r,n,t){function o(r,n){_regeneratorDefine2(e,r,function(e){return this._invoke(r,n,e);});}r?i?i(e,r,{value:n,enumerable:!t,configurable:!t,writable:!t}):e[r]=n:(o("next",0),o("throw",1),o("return",2));},_regeneratorDefine2(e,r,n,t);}function asyncGeneratorStep(n,t,e,r,o,a,c){try{var i=n[a](c),u=i.value;}catch(n){return void e(n);}i.done?t(u):Promise.resolve(u).then(r,o);}function _asyncToGenerator(n){return function(){var t=this,e=arguments;return new Promise(function(r,o){var a=n.apply(t,e);function _next(n){asyncGeneratorStep(a,r,o,_next,_throw,"next",n);}function _throw(n){asyncGeneratorStep(a,r,o,_next,_throw,"throw",n);}_next(void 0);});};}function _createForOfIteratorHelper(r,e){var t="undefined"!=typeof Symbol&&r[Symbol.iterator]||r["@@iterator"];if(!t){if(Array.isArray(r)||(t=_unsupportedIterableToArray(r))||e&&r&&"number"==typeof r.length){t&&(r=t);var _n=0,F=function F(){};return{s:F,n:function n(){return _n>=r.length?{done:!0}:{done:!1,value:r[_n++]};},e:function e(r){throw r;},f:F};}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}var o,a=!0,u=!1;return{s:function s(){t=t.call(r);},n:function n(){var r=t.next();return a=r.done,r;},e:function e(r){u=!0,o=r;},f:function f(){try{a||null==t["return"]||t["return"]();}finally{if(u)throw o;}}};}function _unsupportedIterableToArray(r,a){if(r){if("string"==typeof r)return _arrayLikeToArray(r,a);var t={}.toString.call(r).slice(8,-1);return"Object"===t&&r.constructor&&(t=r.constructor.name),"Map"===t||"Set"===t?Array.from(r):"Arguments"===t||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)?_arrayLikeToArray(r,a):void 0;}}function _arrayLikeToArray(r,a){(null==a||a>r.length)&&(a=r.length);for(var e=0,n=Array(a);e<a;e++)n[e]=r[e];return n;}function _defineProperty(e,r,t){return(r=_toPropertyKey(r))in e?Object.defineProperty(e,r,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[r]=t,e;}function _classCallCheck(a,n){if(!(a instanceof n))throw new TypeError("Cannot call a class as a function");}function _defineProperties(e,r){for(var t=0;t<r.length;t++){var o=r[t];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,_toPropertyKey(o.key),o);}}function _createClass(e,r,t){return r&&_defineProperties(e.prototype,r),t&&_defineProperties(e,t),Object.defineProperty(e,"prototype",{writable:!1}),e;}function _toPropertyKey(t){var i=_toPrimitive(t,"string");return"symbol"==_typeof(i)?i:i+"";}function _toPrimitive(t,r){if("object"!=_typeof(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var i=e.call(t,r||"default");if("object"!=_typeof(i))return i;throw new TypeError("@@toPrimitive must return a primitive value.");}return("string"===r?String:Number)(t);}function _callSuper(t,o,e){return o=_getPrototypeOf(o),_possibleConstructorReturn(t,_isNativeReflectConstruct()?Reflect.construct(o,e||[],_getPrototypeOf(t).constructor):o.apply(t,e));}function _possibleConstructorReturn(t,e){if(e&&("object"==_typeof(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return _assertThisInitialized(t);}function _assertThisInitialized(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e;}function _isNativeReflectConstruct(){try{var t=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}));}catch(t){}return(_isNativeReflectConstruct=function _isNativeReflectConstruct(){return!!t;})();}function _superPropGet(t,o,e,r){var p=_get(_getPrototypeOf(1&r?t.prototype:t),o,e);return 2&r&&"function"==typeof p?function(t){return p.apply(e,t);}:p;}function _get(){return _get="undefined"!=typeof Reflect&&Reflect.get?Reflect.get.bind():function(e,t,r){var p=_superPropBase(e,t);if(p){var n=Object.getOwnPropertyDescriptor(p,t);return n.get?n.get.call(arguments.length<3?e:r):n.value;}},_get.apply(null,arguments);}function _superPropBase(t,o){for(;!{}.hasOwnProperty.call(t,o)&&null!==(t=_getPrototypeOf(t)););return t;}function _getPrototypeOf(t){return _getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t);},_getPrototypeOf(t);}function _inherits(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&_setPrototypeOf(t,e);}function _setPrototypeOf(t,e){return _setPrototypeOf=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t;},_setPrototypeOf(t,e);}function _typeof(o){"@babel/helpers - typeof";return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(o){return typeof o;}:function(o){return o&&"function"==typeof Symbol&&o.constructor===Symbol&&o!==Symbol.prototype?"symbol":typeof o;},_typeof(o);}(function(f){if((typeof exports==="undefined"?"undefined":_typeof(exports))==="object"&&typeof module!=="undefined"){module.exports=f();}else if(typeof define==="function"&&define.amd){define([],f);}else{var g;if(typeof window!=="undefined"){g=window;}else if(typeof global!=="undefined"){g=global;}else if(typeof self!=="undefined"){g=self;}else{g=this;}g.MappingDemoApplication=f();}})(function(){var define,module,exports;return function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a;}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r);},p,p.exports,r,e,n,t);}return n[i].exports;}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o;}return r;}()({1:[function(require,module,exports){'use strict';var libPictApplication=require('pict-application');var libMappingDemoEditorView=require('./views/MappingDemoEditorView.js');/**
2
+ * MappingDemoApplication
3
+ *
4
+ * Minimal pict application that hosts the MappingDemoEditorView.
5
+ * Loaded client-side by Pict.safeLoadPictApplication(MappingDemoApplication, 2).
6
+ *
7
+ * After initialization it exposes window.openMappingEditor() so the static
8
+ * HTML pipeline UI can activate the visual editor from a plain onclick handler.
9
+ */var MappingDemoApplication=/*#__PURE__*/function(_libPictApplication){function MappingDemoApplication(pFable,pOptions,pServiceHash){var _this;_classCallCheck(this,MappingDemoApplication);_this=_callSuper(this,MappingDemoApplication,[pFable,pOptions,pServiceHash]);_this.pict.addView('MappingDemoEditor',libMappingDemoEditorView.default_configuration,libMappingDemoEditorView);return _this;}_inherits(MappingDemoApplication,_libPictApplication);return _createClass(MappingDemoApplication,[{key:"onAfterInitializeAsync",value:function onAfterInitializeAsync(fCallback){// Expose a global hook so the outer HTML can open the editor
10
+ window.openMappingEditor=function(){var tmpPlaceholder=document.getElementById('mapping-editor-placeholder');if(tmpPlaceholder){tmpPlaceholder.style.display='none';}window._Pict.views['MappingDemoEditor'].editMappings(1,'Book');};return _superPropGet(MappingDemoApplication,"onAfterInitializeAsync",this,3)([fCallback]);}}]);}(libPictApplication);module.exports=MappingDemoApplication;module.exports.default_configuration={Name:'MappingDemoApp',Hash:'MappingDemo',AutoSolveAfterInitialize:true};},{"./views/MappingDemoEditorView.js":2,"pict-application":6}],2:[function(require,module,exports){'use strict';// Path: mapping-demo/source/views/ → ../../../../source/views/PictView-MeadowMappingEditor.js
11
+ var libMeadowMappingEditorView=require('../../../../source/views/PictView-MeadowMappingEditor.js');// ── View configuration ────────────────────────────────────────────────────────
12
+ // Same template HTML as the generic base editor, but with 'MappingDemoEditor'
13
+ // in all onclick handlers so pict resolves this registered view name.
14
+ // DOM IDs stay as MeadowMap-* so inherited JS methods work without changes.
15
+ var _ViewConfiguration={ViewIdentifier:'MappingDemoEditor',DefaultRenderable:'MappingDemoEditor-Content',DefaultDestinationAddress:'#MeadowMap-Editor-Container',AutoRender:false,CSS:libMeadowMappingEditorView.default_configuration.CSS,Templates:[{Hash:'MappingDemoEditor-Template',Template:/*html*/"\n<div>\n\t<div id=\"MeadowMap-Editor\" class=\"meadow-mapping-editor\">\n\t\t<div class=\"meadow-mapping-header\">\n\t\t\t<button class=\"meadow-mapping-btn meadow-mapping-btn-secondary meadow-mapping-btn-small\" onclick=\"{~P~}.views['MappingDemoEditor'].closeMappingEditor()\">&larr; Back</button>\n\t\t\t<h3 id=\"MeadowMap-Title\">Mapping Editor</h3>\n\t\t\t<div class=\"meadow-schema-mode-tabs\">\n\t\t\t\t<button class=\"meadow-schema-mode-tab active\" id=\"MeadowMap-Mode-Flow\" onclick=\"{~P~}.views['MappingDemoEditor'].switchMapMode('flow')\">Visual Mapper</button>\n\t\t\t\t<button class=\"meadow-schema-mode-tab\" id=\"MeadowMap-Mode-JSON\" onclick=\"{~P~}.views['MappingDemoEditor'].switchMapMode('json')\">JSON Config</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div id=\"MeadowMap-List-Wrap\">\n\t\t\t<div style=\"display:flex; align-items:center; justify-content:space-between; margin-bottom:0.75em;\">\n\t\t\t\t<div class=\"meadow-section-title\" style=\"margin:0;\">Existing Mappings</div>\n\t\t\t\t<button class=\"meadow-mapping-btn meadow-mapping-btn-primary meadow-mapping-btn-small\" onclick=\"{~P~}.views['MappingDemoEditor'].newMapping()\">+ New Mapping</button>\n\t\t\t</div>\n\t\t\t<div id=\"MeadowMap-List\"></div>\n\t\t</div>\n\n\t\t<div id=\"MeadowMap-Detail\" style=\"display:none;\">\n\t\t\t<div style=\"display:flex; gap:0.5em; align-items:center; margin-bottom:0.75em;\">\n\t\t\t\t<label style=\"font-size:0.78em; font-weight:600;\">Mapping Name</label>\n\t\t\t\t<input type=\"text\" id=\"MeadowMap-Name\" placeholder=\"Mapping name\" style=\"flex:1; padding:0.3em 0.5em; font-size:0.85em; border:1px solid var(--border); border-radius:4px; background:var(--bg-card); color:var(--text);\">\n\t\t\t</div>\n\n\t\t\t<div style=\"display:flex; gap:0.5em; align-items:center; margin-bottom:0.75em;\">\n\t\t\t\t<label style=\"font-size:0.78em; font-weight:600;\">Source</label>\n\t\t\t\t<select id=\"MeadowMap-Source\" style=\"flex:1; padding:0.3em 0.5em; font-size:0.85em; border:1px solid var(--border); border-radius:4px;\"></select>\n\t\t\t\t<button class=\"meadow-mapping-btn meadow-mapping-btn-secondary meadow-mapping-btn-small\" onclick=\"{~P~}.views['MappingDemoEditor'].discoverSourceFields()\">Discover Fields</button>\n\t\t\t</div>\n\n\t\t\t<div id=\"MeadowMap-Flow-Wrap\">\n\t\t\t\t<div id=\"MeadowMap-Flow-Container\" class=\"meadow-flow-container\"></div>\n\t\t\t</div>\n\n\t\t\t<div id=\"MeadowMap-JSON-Wrap\" style=\"display:none;\">\n\t\t\t\t<textarea class=\"meadow-mapping-json-editor\" id=\"MeadowMap-JSON\" placeholder='{\"Entity\":\"Book\",\"GUIDTemplate\":\"{~D:Record.id~}\",\"Mappings\":{},\"Solvers\":[],\"ManyfestAddresses\":false}'></textarea>\n\t\t\t</div>\n\n\t\t\t<div style=\"margin-top:0.75em;\">\n\t\t\t\t<div style=\"font-size:0.72em; font-weight:600; text-transform:uppercase; letter-spacing:0.5px; color:var(--text-dim); margin-bottom:0.35em;\">Target Stores</div>\n\t\t\t\t<div id=\"MeadowMap-Stores\" class=\"meadow-mapping-store-checklist\"></div>\n\t\t\t</div>\n\n\t\t\t<div style=\"margin-top:0.75em; display:flex; gap:0.5em; flex-wrap:wrap; align-items:center;\">\n\t\t\t\t<button class=\"meadow-mapping-btn meadow-mapping-btn-primary\" onclick=\"{~P~}.views['MappingDemoEditor'].saveMapping()\">Save Mapping</button>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n"}],Renderables:[{RenderableHash:'MappingDemoEditor-Content',TemplateHash:'MappingDemoEditor-Template',ContentDestinationAddress:'#MeadowMap-Editor-Container',RenderMethod:'replace'}]};/**
16
+ * MappingDemoEditorView
17
+ *
18
+ * Extends MeadowMappingEditorView and wires the _do* data methods to the
19
+ * mapping-demo server's REST API endpoints. All visual/canvas/serialization
20
+ * logic lives in the base class; this subclass only supplies data access.
21
+ */var MappingDemoEditorView=/*#__PURE__*/function(_libMeadowMappingEdit){function MappingDemoEditorView(pFable,pOptions,pServiceHash){_classCallCheck(this,MappingDemoEditorView);return _callSuper(this,MappingDemoEditorView,[pFable,pOptions,pServiceHash]);}// ── Data methods ─────────────────────────────────────────────────────────
22
+ _inherits(MappingDemoEditorView,_libMeadowMappingEdit);return _createClass(MappingDemoEditorView,[{key:"_doLoadMappings",value:function _doLoadMappings(pContextID){return fetch('/1.0/Demo/VisualMapping').then(function(r){return r.json();});}},{key:"_doLoadSources",value:function _doLoadSources(){return fetch('/1.0/Demo/Sources').then(function(r){return r.json();});}},{key:"_doLoadStores",value:function _doLoadStores(pContextID){return Promise.resolve({Stores:[]});}},{key:"_doLoadTargetSchema",value:function _doLoadTargetSchema(pContextID){return fetch('/1.0/Demo/TargetSchema').then(function(r){return r.json();});}},{key:"_doLoadMapping",value:function _doLoadMapping(pMappingID){return fetch('/1.0/Demo/VisualMapping/'+pMappingID).then(function(r){return r.json();});}},{key:"_doDeleteMapping",value:function _doDeleteMapping(pMappingID){return fetch('/1.0/Demo/VisualMapping/'+pMappingID,{method:'DELETE'}).then(function(r){return r.json();});}},{key:"_doDiscoverSourceFields",value:function _doDiscoverSourceFields(pContextID,pSourceID,pRecordLimit){return fetch('/1.0/Demo/SourceSchema').then(function(r){return r.json();});}},{key:"_doCreateMapping",value:function _doCreateMapping(pContextID,pData){return fetch('/1.0/Demo/VisualMapping',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(pData)}).then(function(r){return r.json();});}},{key:"_doUpdateMapping",value:function _doUpdateMapping(pMappingID,pData){return fetch('/1.0/Demo/VisualMapping/'+pMappingID,{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(pData)}).then(function(r){return r.json();});}},{key:"_onClose",value:function _onClose(){// Hide the editor and restore the step placeholder
23
+ var tmpEditor=document.getElementById('MeadowMap-Editor');if(tmpEditor){tmpEditor.classList.remove('active');}var tmpPlaceholder=document.getElementById('mapping-editor-placeholder');if(tmpPlaceholder){tmpPlaceholder.style.display='';}// Dispatch an event so the outer UI can mark this step done
24
+ document.dispatchEvent(new CustomEvent('mapping-editor-closed'));}}]);}(libMeadowMappingEditorView);module.exports=MappingDemoEditorView;module.exports.default_configuration=_ViewConfiguration;},{"../../../../source/views/PictView-MeadowMappingEditor.js":47}],3:[function(require,module,exports){module.exports={"name":"fable-serviceproviderbase","version":"3.0.19","description":"Simple base classes for fable services.","main":"source/Fable-ServiceProviderBase.js","scripts":{"start":"node source/Fable-ServiceProviderBase.js","test":"npx quack test","tests":"npx quack test -g","coverage":"npx quack coverage","build":"npx quack build","types":"tsc -p ./tsconfig.build.json","check":"tsc -p . --noEmit"},"types":"types/source/Fable-ServiceProviderBase.d.ts","mocha":{"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"repository":{"type":"git","url":"https://github.com/stevenvelozo/fable-serviceproviderbase.git"},"keywords":["entity","behavior"],"author":"Steven Velozo <steven@velozo.com> (http://velozo.com/)","license":"MIT","bugs":{"url":"https://github.com/stevenvelozo/fable-serviceproviderbase/issues"},"homepage":"https://github.com/stevenvelozo/fable-serviceproviderbase","devDependencies":{"@types/mocha":"^10.0.10","fable":"^3.1.62","quackage":"^1.0.58","typescript":"^5.9.3"}};},{}],4:[function(require,module,exports){/**
25
+ * Fable Service Base
26
+ * @author <steven@velozo.com>
27
+ */var libPackage=require('../package.json');var FableServiceProviderBase=/*#__PURE__*/function(){/**
28
+ * The constructor can be used in two ways:
29
+ * 1) With a fable, options object and service hash (the options object and service hash are optional)a
30
+ * 2) With an object or nothing as the first parameter, where it will be treated as the options object
31
+ *
32
+ * @param {import('fable')|Record<string, any>} [pFable] - (optional) The fable instance, or the options object if there is no fable
33
+ * @param {Record<string, any>|string} [pOptions] - (optional) The options object, or the service hash if there is no fable
34
+ * @param {string} [pServiceHash] - (optional) The service hash to identify this service instance
35
+ */function FableServiceProviderBase(pFable,pOptions,pServiceHash){_classCallCheck(this,FableServiceProviderBase);/** @type {import('fable')} */this.fable;/** @type {string} */this.UUID;/** @type {Record<string, any>} */this.options;/** @type {Record<string, any>} */this.services;/** @type {Record<string, any>} */this.servicesMap;// Check if a fable was passed in; connect it if so
36
+ if(_typeof(pFable)==='object'&&pFable.isFable){this.connectFable(pFable);}else{this.fable=false;}// Initialize the services map if it wasn't passed in
37
+ /** @type {Record<string, any>} */this._PackageFableServiceProvider=libPackage;// initialize options and UUID based on whether the fable was passed in or not.
38
+ if(this.fable){this.UUID=pFable.getUUID();this.options=_typeof(pOptions)==='object'?pOptions:{};}else{// With no fable, check to see if there was an object passed into either of the first two
39
+ // Parameters, and if so, treat it as the options object
40
+ this.options=_typeof(pFable)==='object'&&!pFable.isFable?pFable:_typeof(pOptions)==='object'?pOptions:{};this.UUID="CORE-SVC-".concat(Math.floor(Math.random()*(99999-10000)+10000));}// It's expected that the deriving class will set this
41
+ this.serviceType="Unknown-".concat(this.UUID);// The service hash is used to identify the specific instantiation of the service in the services map
42
+ this.Hash=typeof pServiceHash==='string'?pServiceHash:!this.fable&&typeof pOptions==='string'?pOptions:"".concat(this.UUID);}/**
43
+ * @param {import('fable')} pFable
44
+ */return _createClass(FableServiceProviderBase,[{key:"connectFable",value:function connectFable(pFable){if(_typeof(pFable)!=='object'||!pFable.isFable){var tmpErrorMessage="Fable Service Provider Base: Cannot connect to Fable, invalid Fable object passed in. The pFable parameter was a [".concat(_typeof(pFable),"].}");console.log(tmpErrorMessage);return new Error(tmpErrorMessage);}if(!this.fable){this.fable=pFable;}if(!this.log){this.log=this.fable.Logging;}if(!this.services){this.services=this.fable.services;}if(!this.servicesMap){this.servicesMap=this.fable.servicesMap;}return true;}}]);}();_defineProperty(FableServiceProviderBase,"isFableService",true);module.exports=FableServiceProviderBase;// This is left here in case we want to go back to having different code/base class for "core" services
45
+ module.exports.CoreServiceProviderBase=FableServiceProviderBase;},{"../package.json":3}],5:[function(require,module,exports){module.exports={"name":"pict-application","version":"1.0.33","description":"Application base class for a pict view-based application","main":"source/Pict-Application.js","scripts":{"test":"npx quack test","start":"node source/Pict-Application.js","coverage":"npx quack coverage","build":"npx quack build","docker-dev-build":"docker build ./ -f Dockerfile_LUXURYCode -t pict-application-image:local","docker-dev-run":"docker run -it -d --name pict-application-dev -p 30001:8080 -p 38086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/pict-application\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" pict-application-image:local","docker-dev-shell":"docker exec -it pict-application-dev /bin/bash","tests":"npx quack test -g","lint":"eslint source/**","types":"tsc -p ."},"types":"types/source/Pict-Application.d.ts","repository":{"type":"git","url":"git+https://github.com/stevenvelozo/pict-application.git"},"author":"steven velozo <steven@velozo.com>","license":"MIT","bugs":{"url":"https://github.com/stevenvelozo/pict-application/issues"},"homepage":"https://github.com/stevenvelozo/pict-application#readme","devDependencies":{"@eslint/js":"^9.28.0","browser-env":"^3.3.0","eslint":"^9.28.0","pict":"^1.0.348","pict-provider":"^1.0.10","pict-view":"^1.0.66","quackage":"^1.0.58","typescript":"^5.9.3"},"mocha":{"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"dependencies":{"fable-serviceproviderbase":"^3.0.19"}};},{}],6:[function(require,module,exports){var libFableServiceBase=require('fable-serviceproviderbase');var libPackage=require('../package.json');var defaultPictSettings={Name:'DefaultPictApplication',// The main "viewport" is the view that is used to host our application
46
+ MainViewportViewIdentifier:'Default-View',MainViewportRenderableHash:false,MainViewportDestinationAddress:false,MainViewportDefaultDataAddress:false,// Whether or not we should automatically render the main viewport and other autorender views after we initialize the pict application
47
+ AutoSolveAfterInitialize:true,AutoRenderMainViewportViewAfterInitialize:true,AutoRenderViewsAfterInitialize:false,AutoLoginAfterInitialize:false,AutoLoadDataAfterLogin:false,ConfigurationOnlyViews:[],Manifests:{},// The prefix to prepend on all template destination hashes
48
+ IdentifierAddressPrefix:'PICT-'};/**
49
+ * Base class for pict applications.
50
+ */var PictApplication=/*#__PURE__*/function(_libFableServiceBase){/**
51
+ * @param {import('fable')} pFable
52
+ * @param {Record<string, any>} [pOptions]
53
+ * @param {string} [pServiceHash]
54
+ */function PictApplication(pFable,pOptions,pServiceHash){var _this2;_classCallCheck(this,PictApplication);var tmpCarryOverConfiguration=_typeof(pFable.settings.PictApplicationConfiguration)==='object'?pFable.settings.PictApplicationConfiguration:{};var tmpOptions=Object.assign({},JSON.parse(JSON.stringify(defaultPictSettings)),tmpCarryOverConfiguration,pOptions);_this2=_callSuper(this,PictApplication,[pFable,tmpOptions,pServiceHash]);/** @type {any} */_this2.options;/** @type {any} */_this2.log;/** @type {import('pict') & import('fable')} */_this2.fable;/** @type {string} */_this2.UUID;/** @type {string} */_this2.Hash;/**
55
+ * @type {{ [key: string]: any }}
56
+ */_this2.servicesMap;_this2.serviceType='PictApplication';/** @type {Record<string, any>} */_this2._Package=libPackage;// Convenience and consistency naming
57
+ _this2.pict=_this2.fable;// Wire in the essential Pict state
58
+ /** @type {Record<string, any>} */_this2.AppData=_this2.fable.AppData;/** @type {Record<string, any>} */_this2.Bundle=_this2.fable.Bundle;/** @type {number} */_this2.initializeTimestamp;/** @type {number} */_this2.lastSolvedTimestamp;/** @type {number} */_this2.lastLoginTimestamp;/** @type {number} */_this2.lastMarshalFromViewsTimestamp;/** @type {number} */_this2.lastMarshalToViewsTimestamp;/** @type {number} */_this2.lastAutoRenderTimestamp;/** @type {number} */_this2.lastLoadDataTimestamp;// Load all the manifests for the application
59
+ var tmpManifestKeys=Object.keys(_this2.options.Manifests);if(tmpManifestKeys.length>0){for(var i=0;i<tmpManifestKeys.length;i++){// Load each manifest
60
+ var tmpManifestKey=tmpManifestKeys[i];_this2.fable.instantiateServiceProvider('Manifest',_this2.options.Manifests[tmpManifestKey],tmpManifestKey);}}return _this2;}/* -------------------------------------------------------------------------- *//* Code Section: Solve All Views *//* -------------------------------------------------------------------------- *//**
61
+ * @return {boolean}
62
+ */_inherits(PictApplication,_libFableServiceBase);return _createClass(PictApplication,[{key:"onPreSolve",value:function onPreSolve(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onPreSolve:"));}return true;}/**
63
+ * @param {(error?: Error) => void} fCallback
64
+ */},{key:"onPreSolveAsync",value:function onPreSolveAsync(fCallback){this.onPreSolve();return fCallback();}/**
65
+ * @return {boolean}
66
+ */},{key:"onBeforeSolve",value:function onBeforeSolve(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onBeforeSolve:"));}return true;}/**
67
+ * @param {(error?: Error) => void} fCallback
68
+ */},{key:"onBeforeSolveAsync",value:function onBeforeSolveAsync(fCallback){this.onBeforeSolve();return fCallback();}/**
69
+ * @return {boolean}
70
+ */},{key:"onSolve",value:function onSolve(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onSolve:"));}return true;}/**
71
+ * @param {(error?: Error) => void} fCallback
72
+ */},{key:"onSolveAsync",value:function onSolveAsync(fCallback){this.onSolve();return fCallback();}/**
73
+ * @return {boolean}
74
+ */},{key:"solve",value:function solve(){if(this.pict.LogNoisiness>2){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," executing solve() function..."));}// Walk through any loaded providers and solve them as well.
75
+ var tmpLoadedProviders=Object.keys(this.pict.providers);var tmpProvidersToSolve=[];for(var i=0;i<tmpLoadedProviders.length;i++){var tmpProvider=this.pict.providers[tmpLoadedProviders[i]];if(tmpProvider.options.AutoSolveWithApp){tmpProvidersToSolve.push(tmpProvider);}}// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
76
+ tmpProvidersToSolve.sort(function(a,b){return a.options.AutoSolveOrdinal-b.options.AutoSolveOrdinal;});for(var _i=0;_i<tmpProvidersToSolve.length;_i++){tmpProvidersToSolve[_i].solve(tmpProvidersToSolve[_i]);}this.onBeforeSolve();// Now walk through any loaded views and initialize them as well.
77
+ var tmpLoadedViews=Object.keys(this.pict.views);var tmpViewsToSolve=[];for(var _i2=0;_i2<tmpLoadedViews.length;_i2++){var tmpView=this.pict.views[tmpLoadedViews[_i2]];if(tmpView.options.AutoInitialize){tmpViewsToSolve.push(tmpView);}}// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
78
+ tmpViewsToSolve.sort(function(a,b){return a.options.AutoInitializeOrdinal-b.options.AutoInitializeOrdinal;});for(var _i3=0;_i3<tmpViewsToSolve.length;_i3++){tmpViewsToSolve[_i3].solve();}this.onSolve();this.onAfterSolve();this.lastSolvedTimestamp=this.fable.log.getTimeStamp();return true;}/**
79
+ * @param {(error?: Error) => void} fCallback
80
+ */},{key:"solveAsync",value:function solveAsync(fCallback){var _this3=this;var tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');tmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));// Allow the callback to be passed in as the last parameter no matter what
81
+ var tmpCallback=typeof fCallback==='function'?fCallback:false;if(!tmpCallback){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this3.log.error("PictApp [".concat(_this3.UUID,"]::[").concat(_this3.Hash,"] ").concat(_this3.options.Name," solveAsync Auto Callback Error: ").concat(pError),pError);}};}// Walk through any loaded providers and solve them as well.
82
+ var tmpLoadedProviders=Object.keys(this.pict.providers);var tmpProvidersToSolve=[];for(var i=0;i<tmpLoadedProviders.length;i++){var tmpProvider=this.pict.providers[tmpLoadedProviders[i]];if(tmpProvider.options.AutoSolveWithApp){tmpProvidersToSolve.push(tmpProvider);}}// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
83
+ tmpProvidersToSolve.sort(function(a,b){return a.options.AutoSolveOrdinal-b.options.AutoSolveOrdinal;});for(var _i4=0;_i4<tmpProvidersToSolve.length;_i4++){tmpAnticipate.anticipate(tmpProvidersToSolve[_i4].solveAsync.bind(tmpProvidersToSolve[_i4]));}// Walk through any loaded views and solve them as well.
84
+ var tmpLoadedViews=Object.keys(this.pict.views);var tmpViewsToSolve=[];for(var _i5=0;_i5<tmpLoadedViews.length;_i5++){var tmpView=this.pict.views[tmpLoadedViews[_i5]];if(tmpView.options.AutoSolveWithApp){tmpViewsToSolve.push(tmpView);}}// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
85
+ tmpViewsToSolve.sort(function(a,b){return a.options.AutoSolveOrdinal-b.options.AutoSolveOrdinal;});for(var _i6=0;_i6<tmpViewsToSolve.length;_i6++){tmpAnticipate.anticipate(tmpViewsToSolve[_i6].solveAsync.bind(tmpViewsToSolve[_i6]));}tmpAnticipate.anticipate(this.onSolveAsync.bind(this));tmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));tmpAnticipate.wait(function(pError){if(_this3.pict.LogNoisiness>2){_this3.log.trace("PictApp [".concat(_this3.UUID,"]::[").concat(_this3.Hash,"] ").concat(_this3.options.Name," solveAsync() complete."));}_this3.lastSolvedTimestamp=_this3.fable.log.getTimeStamp();return tmpCallback(pError);});}/**
86
+ * @return {boolean}
87
+ */},{key:"onAfterSolve",value:function onAfterSolve(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onAfterSolve:"));}return true;}/**
88
+ * @param {(error?: Error) => void} fCallback
89
+ */},{key:"onAfterSolveAsync",value:function onAfterSolveAsync(fCallback){this.onAfterSolve();return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Application Login *//* -------------------------------------------------------------------------- *//**
90
+ * @param {(error?: Error) => void} fCallback
91
+ */},{key:"onBeforeLoginAsync",value:function onBeforeLoginAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onBeforeLoginAsync:"));}return fCallback();}/**
92
+ * @param {(error?: Error) => void} fCallback
93
+ */},{key:"onLoginAsync",value:function onLoginAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onLoginAsync:"));}return fCallback();}/**
94
+ * @param {(error?: Error) => void} fCallback
95
+ */},{key:"loginAsync",value:function loginAsync(fCallback){var _this4=this;var tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');var tmpCallback=fCallback;if(typeof tmpCallback!=='function'){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," loginAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this4.log.error("PictApp [".concat(_this4.UUID,"]::[").concat(_this4.Hash,"] ").concat(_this4.options.Name," loginAsync Auto Callback Error: ").concat(pError),pError);}};}tmpAnticipate.anticipate(this.onBeforeLoginAsync.bind(this));tmpAnticipate.anticipate(this.onLoginAsync.bind(this));tmpAnticipate.anticipate(this.onAfterLoginAsync.bind(this));// check and see if we should automatically trigger a data load
96
+ if(this.options.AutoLoadDataAfterLogin){tmpAnticipate.anticipate(function(fNext){if(!_this4.isLoggedIn()){return fNext();}if(_this4.pict.LogNoisiness>1){_this4.log.trace("PictApp [".concat(_this4.UUID,"]::[").concat(_this4.Hash,"] ").concat(_this4.options.Name," auto loading data after login..."));}//TODO: should data load errors funnel here? this creates a weird coupling between login and data load callbacks
97
+ _this4.loadDataAsync(function(pError){fNext(pError);});});}tmpAnticipate.wait(function(pError){if(_this4.pict.LogNoisiness>2){_this4.log.trace("PictApp [".concat(_this4.UUID,"]::[").concat(_this4.Hash,"] ").concat(_this4.options.Name," loginAsync() complete."));}_this4.lastLoginTimestamp=_this4.fable.log.getTimeStamp();return tmpCallback(pError);});}/**
98
+ * Check if the application state is logged in. Defaults to true. Override this method in your application based on login requirements.
99
+ *
100
+ * @return {boolean}
101
+ */},{key:"isLoggedIn",value:function isLoggedIn(){return true;}/**
102
+ * @param {(error?: Error) => void} fCallback
103
+ */},{key:"onAfterLoginAsync",value:function onAfterLoginAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onAfterLoginAsync:"));}return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Application LoadData *//* -------------------------------------------------------------------------- *//**
104
+ * @param {(error?: Error) => void} fCallback
105
+ */},{key:"onBeforeLoadDataAsync",value:function onBeforeLoadDataAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onBeforeLoadDataAsync:"));}return fCallback();}/**
106
+ * @param {(error?: Error) => void} fCallback
107
+ */},{key:"onLoadDataAsync",value:function onLoadDataAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onLoadDataAsync:"));}return fCallback();}/**
108
+ * @param {(error?: Error) => void} fCallback
109
+ */},{key:"loadDataAsync",value:function loadDataAsync(fCallback){var _this5=this;var tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');var tmpCallback=fCallback;if(typeof tmpCallback!=='function'){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," loadDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this5.log.error("PictApp [".concat(_this5.UUID,"]::[").concat(_this5.Hash,"] ").concat(_this5.options.Name," loadDataAsync Auto Callback Error: ").concat(pError),pError);}};}tmpAnticipate.anticipate(this.onBeforeLoadDataAsync.bind(this));// Walk through any loaded providers and load their data as well.
110
+ var tmpLoadedProviders=Object.keys(this.pict.providers);var tmpProvidersToLoadData=[];for(var i=0;i<tmpLoadedProviders.length;i++){var tmpProvider=this.pict.providers[tmpLoadedProviders[i]];if(tmpProvider.options.AutoLoadDataWithApp){tmpProvidersToLoadData.push(tmpProvider);}}// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
111
+ tmpProvidersToLoadData.sort(function(a,b){return a.options.AutoLoadDataOrdinal-b.options.AutoLoadDataOrdinal;});for(var _i7=0,_tmpProvidersToLoadDa=tmpProvidersToLoadData;_i7<_tmpProvidersToLoadDa.length;_i7++){var _tmpProvider=_tmpProvidersToLoadDa[_i7];tmpAnticipate.anticipate(_tmpProvider.onBeforeLoadDataAsync.bind(_tmpProvider));}tmpAnticipate.anticipate(this.onLoadDataAsync.bind(this));//TODO: think about ways to parallelize these
112
+ for(var _i8=0,_tmpProvidersToLoadDa2=tmpProvidersToLoadData;_i8<_tmpProvidersToLoadDa2.length;_i8++){var _tmpProvider2=_tmpProvidersToLoadDa2[_i8];tmpAnticipate.anticipate(_tmpProvider2.onLoadDataAsync.bind(_tmpProvider2));}tmpAnticipate.anticipate(this.onAfterLoadDataAsync.bind(this));for(var _i9=0,_tmpProvidersToLoadDa3=tmpProvidersToLoadData;_i9<_tmpProvidersToLoadDa3.length;_i9++){var _tmpProvider3=_tmpProvidersToLoadDa3[_i9];tmpAnticipate.anticipate(_tmpProvider3.onAfterLoadDataAsync.bind(_tmpProvider3));}tmpAnticipate.wait(/** @param {Error} [pError] */function(pError){if(_this5.pict.LogNoisiness>2){_this5.log.trace("PictApp [".concat(_this5.UUID,"]::[").concat(_this5.Hash,"] ").concat(_this5.options.Name," loadDataAsync() complete."));}_this5.lastLoadDataTimestamp=_this5.fable.log.getTimeStamp();return tmpCallback(pError);});}/**
113
+ * @param {(error?: Error) => void} fCallback
114
+ */},{key:"onAfterLoadDataAsync",value:function onAfterLoadDataAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onAfterLoadDataAsync:"));}return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Application SaveData *//* -------------------------------------------------------------------------- *//**
115
+ * @param {(error?: Error) => void} fCallback
116
+ */},{key:"onBeforeSaveDataAsync",value:function onBeforeSaveDataAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onBeforeSaveDataAsync:"));}return fCallback();}/**
117
+ * @param {(error?: Error) => void} fCallback
118
+ */},{key:"onSaveDataAsync",value:function onSaveDataAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onSaveDataAsync:"));}return fCallback();}/**
119
+ * @param {(error?: Error) => void} fCallback
120
+ */},{key:"saveDataAsync",value:function saveDataAsync(fCallback){var _this6=this;var tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');var tmpCallback=fCallback;if(typeof tmpCallback!=='function'){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," saveDataAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this6.log.error("PictApp [".concat(_this6.UUID,"]::[").concat(_this6.Hash,"] ").concat(_this6.options.Name," saveDataAsync Auto Callback Error: ").concat(pError),pError);}};}tmpAnticipate.anticipate(this.onBeforeSaveDataAsync.bind(this));// Walk through any loaded providers and load their data as well.
121
+ var tmpLoadedProviders=Object.keys(this.pict.providers);var tmpProvidersToSaveData=[];for(var i=0;i<tmpLoadedProviders.length;i++){var tmpProvider=this.pict.providers[tmpLoadedProviders[i]];if(tmpProvider.options.AutoSaveDataWithApp){tmpProvidersToSaveData.push(tmpProvider);}}// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
122
+ tmpProvidersToSaveData.sort(function(a,b){return a.options.AutoSaveDataOrdinal-b.options.AutoSaveDataOrdinal;});for(var _i0=0,_tmpProvidersToSaveDa=tmpProvidersToSaveData;_i0<_tmpProvidersToSaveDa.length;_i0++){var _tmpProvider4=_tmpProvidersToSaveDa[_i0];tmpAnticipate.anticipate(_tmpProvider4.onBeforeSaveDataAsync.bind(_tmpProvider4));}tmpAnticipate.anticipate(this.onSaveDataAsync.bind(this));//TODO: think about ways to parallelize these
123
+ for(var _i1=0,_tmpProvidersToSaveDa2=tmpProvidersToSaveData;_i1<_tmpProvidersToSaveDa2.length;_i1++){var _tmpProvider5=_tmpProvidersToSaveDa2[_i1];tmpAnticipate.anticipate(_tmpProvider5.onSaveDataAsync.bind(_tmpProvider5));}tmpAnticipate.anticipate(this.onAfterSaveDataAsync.bind(this));for(var _i10=0,_tmpProvidersToSaveDa3=tmpProvidersToSaveData;_i10<_tmpProvidersToSaveDa3.length;_i10++){var _tmpProvider6=_tmpProvidersToSaveDa3[_i10];tmpAnticipate.anticipate(_tmpProvider6.onAfterSaveDataAsync.bind(_tmpProvider6));}tmpAnticipate.wait(/** @param {Error} [pError] */function(pError){if(_this6.pict.LogNoisiness>2){_this6.log.trace("PictApp [".concat(_this6.UUID,"]::[").concat(_this6.Hash,"] ").concat(_this6.options.Name," saveDataAsync() complete."));}_this6.lastSaveDataTimestamp=_this6.fable.log.getTimeStamp();return tmpCallback(pError);});}/**
124
+ * @param {(error?: Error) => void} fCallback
125
+ */},{key:"onAfterSaveDataAsync",value:function onAfterSaveDataAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onAfterSaveDataAsync:"));}return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Initialize Application *//* -------------------------------------------------------------------------- *//**
126
+ * @return {boolean}
127
+ */},{key:"onBeforeInitialize",value:function onBeforeInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onBeforeInitialize:"));}return true;}/**
128
+ * @param {(error?: Error) => void} fCallback
129
+ */},{key:"onBeforeInitializeAsync",value:function onBeforeInitializeAsync(fCallback){this.onBeforeInitialize();return fCallback();}/**
130
+ * @return {boolean}
131
+ */},{key:"onInitialize",value:function onInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onInitialize:"));}return true;}/**
132
+ * @param {(error?: Error) => void} fCallback
133
+ */},{key:"onInitializeAsync",value:function onInitializeAsync(fCallback){this.onInitialize();return fCallback();}/**
134
+ * @return {boolean}
135
+ */},{key:"initialize",value:function initialize(){if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow APPLICATION [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," initialize:"));}if(!this.initializeTimestamp){this.onBeforeInitialize();if('ConfigurationOnlyViews'in this.options){// Load all the configuration only views
136
+ for(var i=0;i<this.options.ConfigurationOnlyViews.length;i++){var tmpViewIdentifier=typeof this.options.ConfigurationOnlyViews[i].ViewIdentifier==='undefined'?"AutoView-".concat(this.fable.getUUID()):this.options.ConfigurationOnlyViews[i].ViewIdentifier;this.log.info("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," adding configuration only view: ").concat(tmpViewIdentifier));this.pict.addView(tmpViewIdentifier,this.options.ConfigurationOnlyViews[i]);}}this.onInitialize();// Walk through any loaded providers and initialize them as well.
137
+ var tmpLoadedProviders=Object.keys(this.pict.providers);var tmpProvidersToInitialize=[];for(var _i11=0;_i11<tmpLoadedProviders.length;_i11++){var tmpProvider=this.pict.providers[tmpLoadedProviders[_i11]];if(tmpProvider.options.AutoInitialize){tmpProvidersToInitialize.push(tmpProvider);}}// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
138
+ tmpProvidersToInitialize.sort(function(a,b){return a.options.AutoInitializeOrdinal-b.options.AutoInitializeOrdinal;});for(var _i12=0;_i12<tmpProvidersToInitialize.length;_i12++){tmpProvidersToInitialize[_i12].initialize();}// Now walk through any loaded views and initialize them as well.
139
+ var tmpLoadedViews=Object.keys(this.pict.views);var tmpViewsToInitialize=[];for(var _i13=0;_i13<tmpLoadedViews.length;_i13++){var tmpView=this.pict.views[tmpLoadedViews[_i13]];if(tmpView.options.AutoInitialize){tmpViewsToInitialize.push(tmpView);}}// Sort the views by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
140
+ tmpViewsToInitialize.sort(function(a,b){return a.options.AutoInitializeOrdinal-b.options.AutoInitializeOrdinal;});for(var _i14=0;_i14<tmpViewsToInitialize.length;_i14++){tmpViewsToInitialize[_i14].initialize();}this.onAfterInitialize();if(this.options.AutoSolveAfterInitialize){if(this.pict.LogNoisiness>1){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," auto solving after initialization..."));}// Solve the template synchronously
141
+ this.solve();}// Now check and see if we should automatically render as well
142
+ if(this.options.AutoRenderMainViewportViewAfterInitialize){if(this.pict.LogNoisiness>1){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," auto rendering after initialization..."));}// Render the template synchronously
143
+ this.render();}this.initializeTimestamp=this.fable.log.getTimeStamp();this.onCompletionOfInitialize();return true;}else{this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," initialize called but initialization is already completed. Aborting."));return false;}}/**
144
+ * @param {(error?: Error) => void} fCallback
145
+ */},{key:"initializeAsync",value:function initializeAsync(fCallback){var _this7=this;if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow APPLICATION [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," initializeAsync:"));}// Allow the callback to be passed in as the last parameter no matter what
146
+ var tmpCallback=typeof fCallback==='function'?fCallback:false;if(!tmpCallback){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," initializeAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this7.log.error("PictApp [".concat(_this7.UUID,"]::[").concat(_this7.Hash,"] ").concat(_this7.options.Name," initializeAsync Auto Callback Error: ").concat(pError),pError);}};}if(!this.initializeTimestamp){var tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," beginning initialization..."));}if('ConfigurationOnlyViews'in this.options){// Load all the configuration only views
147
+ for(var i=0;i<this.options.ConfigurationOnlyViews.length;i++){var tmpViewIdentifier=typeof this.options.ConfigurationOnlyViews[i].ViewIdentifier==='undefined'?"AutoView-".concat(this.fable.getUUID()):this.options.ConfigurationOnlyViews[i].ViewIdentifier;this.log.info("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," adding configuration only view: ").concat(tmpViewIdentifier));this.pict.addView(tmpViewIdentifier,this.options.ConfigurationOnlyViews[i]);}}tmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));tmpAnticipate.anticipate(this.onInitializeAsync.bind(this));// Walk through any loaded providers and solve them as well.
148
+ var tmpLoadedProviders=Object.keys(this.pict.providers);var tmpProvidersToInitialize=[];for(var _i15=0;_i15<tmpLoadedProviders.length;_i15++){var tmpProvider=this.pict.providers[tmpLoadedProviders[_i15]];if(tmpProvider.options.AutoInitialize){tmpProvidersToInitialize.push(tmpProvider);}}// Sort the providers by their priority (if they are all priority 0, it will end up being add order due to JSON Object Property Key order stuff)
149
+ tmpProvidersToInitialize.sort(function(a,b){return a.options.AutoInitializeOrdinal-b.options.AutoInitializeOrdinal;});for(var _i16=0;_i16<tmpProvidersToInitialize.length;_i16++){tmpAnticipate.anticipate(tmpProvidersToInitialize[_i16].initializeAsync.bind(tmpProvidersToInitialize[_i16]));}// Now walk through any loaded views and initialize them as well.
150
+ // TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.
151
+ var tmpLoadedViews=Object.keys(this.pict.views);var tmpViewsToInitialize=[];for(var _i17=0;_i17<tmpLoadedViews.length;_i17++){var tmpView=this.pict.views[tmpLoadedViews[_i17]];if(tmpView.options.AutoInitialize){tmpViewsToInitialize.push(tmpView);}}// Sort the views by their priority
152
+ // If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff
153
+ tmpViewsToInitialize.sort(function(a,b){return a.options.AutoInitializeOrdinal-b.options.AutoInitializeOrdinal;});for(var _i18=0;_i18<tmpViewsToInitialize.length;_i18++){var _tmpView=tmpViewsToInitialize[_i18];tmpAnticipate.anticipate(_tmpView.initializeAsync.bind(_tmpView));}tmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));if(this.options.AutoLoginAfterInitialize){if(this.pict.LogNoisiness>1){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," auto login (asynchronously) after initialization..."));}tmpAnticipate.anticipate(this.loginAsync.bind(this));}if(this.options.AutoSolveAfterInitialize){if(this.pict.LogNoisiness>1){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," auto solving (asynchronously) after initialization..."));}tmpAnticipate.anticipate(this.solveAsync.bind(this));}if(this.options.AutoRenderMainViewportViewAfterInitialize){if(this.pict.LogNoisiness>1){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," auto rendering (asynchronously) after initialization..."));}tmpAnticipate.anticipate(this.renderMainViewportAsync.bind(this));}tmpAnticipate.wait(function(pError){if(pError){_this7.log.error("PictApp [".concat(_this7.UUID,"]::[").concat(_this7.Hash,"] ").concat(_this7.options.Name," initializeAsync Error: ").concat(pError.message||pError),{stack:pError.stack});}_this7.initializeTimestamp=_this7.fable.log.getTimeStamp();if(_this7.pict.LogNoisiness>2){_this7.log.trace("PictApp [".concat(_this7.UUID,"]::[").concat(_this7.Hash,"] ").concat(_this7.options.Name," initialization complete."));}return tmpCallback();});}else{this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," async initialize called but initialization is already completed. Aborting."));// TODO: Should this be an error?
154
+ return this.onCompletionOfInitializeAsync(tmpCallback);}}/**
155
+ * @return {boolean}
156
+ */},{key:"onAfterInitialize",value:function onAfterInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onAfterInitialize:"));}return true;}/**
157
+ * @param {(error?: Error) => void} fCallback
158
+ */},{key:"onAfterInitializeAsync",value:function onAfterInitializeAsync(fCallback){this.onAfterInitialize();return fCallback();}/**
159
+ * @return {boolean}
160
+ */},{key:"onCompletionOfInitialize",value:function onCompletionOfInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onCompletionOfInitialize:"));}return true;}/**
161
+ * @param {(error?: Error) => void} fCallback
162
+ */},{key:"onCompletionOfInitializeAsync",value:function onCompletionOfInitializeAsync(fCallback){this.onCompletionOfInitialize();return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Marshal Data From All Views *//* -------------------------------------------------------------------------- *//**
163
+ * @return {boolean}
164
+ */},{key:"onBeforeMarshalFromViews",value:function onBeforeMarshalFromViews(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onBeforeMarshalFromViews:"));}return true;}/**
165
+ * @param {(error?: Error) => void} fCallback
166
+ */},{key:"onBeforeMarshalFromViewsAsync",value:function onBeforeMarshalFromViewsAsync(fCallback){this.onBeforeMarshalFromViews();return fCallback();}/**
167
+ * @return {boolean}
168
+ */},{key:"onMarshalFromViews",value:function onMarshalFromViews(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onMarshalFromViews:"));}return true;}/**
169
+ * @param {(error?: Error) => void} fCallback
170
+ */},{key:"onMarshalFromViewsAsync",value:function onMarshalFromViewsAsync(fCallback){this.onMarshalFromViews();return fCallback();}/**
171
+ * @return {boolean}
172
+ */},{key:"marshalFromViews",value:function marshalFromViews(){if(this.pict.LogNoisiness>2){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," executing marshalFromViews() function..."));}this.onBeforeMarshalFromViews();// Now walk through any loaded views and initialize them as well.
173
+ var tmpLoadedViews=Object.keys(this.pict.views);var tmpViewsToMarshalFromViews=[];for(var i=0;i<tmpLoadedViews.length;i++){var tmpView=this.pict.views[tmpLoadedViews[i]];tmpViewsToMarshalFromViews.push(tmpView);}for(var _i19=0;_i19<tmpViewsToMarshalFromViews.length;_i19++){tmpViewsToMarshalFromViews[_i19].marshalFromView();}this.onMarshalFromViews();this.onAfterMarshalFromViews();this.lastMarshalFromViewsTimestamp=this.fable.log.getTimeStamp();return true;}/**
174
+ * @param {(error?: Error) => void} fCallback
175
+ */},{key:"marshalFromViewsAsync",value:function marshalFromViewsAsync(fCallback){var _this8=this;var tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');// Allow the callback to be passed in as the last parameter no matter what
176
+ var tmpCallback=typeof fCallback==='function'?fCallback:false;if(!tmpCallback){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," marshalFromViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this8.log.error("PictApp [".concat(_this8.UUID,"]::[").concat(_this8.Hash,"] ").concat(_this8.options.Name," marshalFromViewsAsync Auto Callback Error: ").concat(pError),pError);}};}tmpAnticipate.anticipate(this.onBeforeMarshalFromViewsAsync.bind(this));// Walk through any loaded views and marshalFromViews them as well.
177
+ var tmpLoadedViews=Object.keys(this.pict.views);var tmpViewsToMarshalFromViews=[];for(var i=0;i<tmpLoadedViews.length;i++){var tmpView=this.pict.views[tmpLoadedViews[i]];tmpViewsToMarshalFromViews.push(tmpView);}for(var _i20=0;_i20<tmpViewsToMarshalFromViews.length;_i20++){tmpAnticipate.anticipate(tmpViewsToMarshalFromViews[_i20].marshalFromViewAsync.bind(tmpViewsToMarshalFromViews[_i20]));}tmpAnticipate.anticipate(this.onMarshalFromViewsAsync.bind(this));tmpAnticipate.anticipate(this.onAfterMarshalFromViewsAsync.bind(this));tmpAnticipate.wait(function(pError){if(_this8.pict.LogNoisiness>2){_this8.log.trace("PictApp [".concat(_this8.UUID,"]::[").concat(_this8.Hash,"] ").concat(_this8.options.Name," marshalFromViewsAsync() complete."));}_this8.lastMarshalFromViewsTimestamp=_this8.fable.log.getTimeStamp();return tmpCallback(pError);});}/**
178
+ * @return {boolean}
179
+ */},{key:"onAfterMarshalFromViews",value:function onAfterMarshalFromViews(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onAfterMarshalFromViews:"));}return true;}/**
180
+ * @param {(error?: Error) => void} fCallback
181
+ */},{key:"onAfterMarshalFromViewsAsync",value:function onAfterMarshalFromViewsAsync(fCallback){this.onAfterMarshalFromViews();return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Marshal Data To All Views *//* -------------------------------------------------------------------------- *//**
182
+ * @return {boolean}
183
+ */},{key:"onBeforeMarshalToViews",value:function onBeforeMarshalToViews(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onBeforeMarshalToViews:"));}return true;}/**
184
+ * @param {(error?: Error) => void} fCallback
185
+ */},{key:"onBeforeMarshalToViewsAsync",value:function onBeforeMarshalToViewsAsync(fCallback){this.onBeforeMarshalToViews();return fCallback();}/**
186
+ * @return {boolean}
187
+ */},{key:"onMarshalToViews",value:function onMarshalToViews(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onMarshalToViews:"));}return true;}/**
188
+ * @param {(error?: Error) => void} fCallback
189
+ */},{key:"onMarshalToViewsAsync",value:function onMarshalToViewsAsync(fCallback){this.onMarshalToViews();return fCallback();}/**
190
+ * @return {boolean}
191
+ */},{key:"marshalToViews",value:function marshalToViews(){if(this.pict.LogNoisiness>2){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," executing marshalToViews() function..."));}this.onBeforeMarshalToViews();// Now walk through any loaded views and initialize them as well.
192
+ var tmpLoadedViews=Object.keys(this.pict.views);var tmpViewsToMarshalToViews=[];for(var i=0;i<tmpLoadedViews.length;i++){var tmpView=this.pict.views[tmpLoadedViews[i]];tmpViewsToMarshalToViews.push(tmpView);}for(var _i21=0;_i21<tmpViewsToMarshalToViews.length;_i21++){tmpViewsToMarshalToViews[_i21].marshalToView();}this.onMarshalToViews();this.onAfterMarshalToViews();this.lastMarshalToViewsTimestamp=this.fable.log.getTimeStamp();return true;}/**
193
+ * @param {(error?: Error) => void} fCallback
194
+ */},{key:"marshalToViewsAsync",value:function marshalToViewsAsync(fCallback){var _this9=this;var tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');// Allow the callback to be passed in as the last parameter no matter what
195
+ var tmpCallback=typeof fCallback==='function'?fCallback:false;if(!tmpCallback){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," marshalToViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this9.log.error("PictApp [".concat(_this9.UUID,"]::[").concat(_this9.Hash,"] ").concat(_this9.options.Name," marshalToViewsAsync Auto Callback Error: ").concat(pError),pError);}};}tmpAnticipate.anticipate(this.onBeforeMarshalToViewsAsync.bind(this));// Walk through any loaded views and marshalToViews them as well.
196
+ var tmpLoadedViews=Object.keys(this.pict.views);var tmpViewsToMarshalToViews=[];for(var i=0;i<tmpLoadedViews.length;i++){var tmpView=this.pict.views[tmpLoadedViews[i]];tmpViewsToMarshalToViews.push(tmpView);}for(var _i22=0;_i22<tmpViewsToMarshalToViews.length;_i22++){tmpAnticipate.anticipate(tmpViewsToMarshalToViews[_i22].marshalToViewAsync.bind(tmpViewsToMarshalToViews[_i22]));}tmpAnticipate.anticipate(this.onMarshalToViewsAsync.bind(this));tmpAnticipate.anticipate(this.onAfterMarshalToViewsAsync.bind(this));tmpAnticipate.wait(function(pError){if(_this9.pict.LogNoisiness>2){_this9.log.trace("PictApp [".concat(_this9.UUID,"]::[").concat(_this9.Hash,"] ").concat(_this9.options.Name," marshalToViewsAsync() complete."));}_this9.lastMarshalToViewsTimestamp=_this9.fable.log.getTimeStamp();return tmpCallback(pError);});}/**
197
+ * @return {boolean}
198
+ */},{key:"onAfterMarshalToViews",value:function onAfterMarshalToViews(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onAfterMarshalToViews:"));}return true;}/**
199
+ * @param {(error?: Error) => void} fCallback
200
+ */},{key:"onAfterMarshalToViewsAsync",value:function onAfterMarshalToViewsAsync(fCallback){this.onAfterMarshalToViews();return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Render View *//* -------------------------------------------------------------------------- *//**
201
+ * @return {boolean}
202
+ */},{key:"onBeforeRender",value:function onBeforeRender(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onBeforeRender:"));}return true;}/**
203
+ * @param {(error?: Error) => void} fCallback
204
+ */},{key:"onBeforeRenderAsync",value:function onBeforeRenderAsync(fCallback){this.onBeforeRender();return fCallback();}/**
205
+ * @param {string} [pViewIdentifier] - The hash of the view to render. By default, the main viewport view is rendered.
206
+ * @param {string} [pRenderableHash] - The hash of the renderable to render.
207
+ * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.
208
+ * @param {string} [pTemplateDataAddress] - The address where the data for the template is stored.
209
+ *
210
+ * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?
211
+ */},{key:"render",value:function render(pViewIdentifier,pRenderableHash,pRenderDestinationAddress,pTemplateDataAddress){var tmpViewIdentifier=typeof pViewIdentifier!=='string'?this.options.MainViewportViewIdentifier:pViewIdentifier;var tmpRenderableHash=typeof pRenderableHash!=='string'?this.options.MainViewportRenderableHash:pRenderableHash;var tmpRenderDestinationAddress=typeof pRenderDestinationAddress!=='string'?this.options.MainViewportDestinationAddress:pRenderDestinationAddress;var tmpTemplateDataAddress=typeof pTemplateDataAddress!=='string'?this.options.MainViewportDefaultDataAddress:pTemplateDataAddress;if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow APPLICATION [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," VIEW Renderable[").concat(tmpRenderableHash,"] Destination[").concat(tmpRenderDestinationAddress,"] TemplateDataAddress[").concat(tmpTemplateDataAddress,"] render:"));}this.onBeforeRender();// Now get the view (by hash) from the loaded views
212
+ var tmpView=typeof tmpViewIdentifier==='string'?this.servicesMap.PictView[tmpViewIdentifier]:false;if(!tmpView){this.log.error("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," could not render from View ").concat(tmpViewIdentifier," because it is not a valid view."));return false;}this.onRender();tmpView.render(tmpRenderableHash,tmpRenderDestinationAddress,tmpTemplateDataAddress);this.onAfterRender();return true;}/**
213
+ * @return {boolean}
214
+ */},{key:"onRender",value:function onRender(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onRender:"));}return true;}/**
215
+ * @param {(error?: Error) => void} fCallback
216
+ */},{key:"onRenderAsync",value:function onRenderAsync(fCallback){this.onRender();return fCallback();}/**
217
+ * @param {string|((error?: Error) => void)} pViewIdentifier - The hash of the view to render. By default, the main viewport view is rendered. (or the callback)
218
+ * @param {string|((error?: Error) => void)} [pRenderableHash] - The hash of the renderable to render. (or the callback)
219
+ * @param {string|((error?: Error) => void)} [pRenderDestinationAddress] - The address where the renderable will be rendered. (or the callback)
220
+ * @param {string|((error?: Error) => void)} [pTemplateDataAddress] - The address where the data for the template is stored. (or the callback)
221
+ * @param {(error?: Error) => void} [fCallback] - The callback, if all other parameters are provided.
222
+ *
223
+ * TODO: Should we support objects for pTemplateDataAddress for parity with pict-view?
224
+ */},{key:"renderAsync",value:function renderAsync(pViewIdentifier,pRenderableHash,pRenderDestinationAddress,pTemplateDataAddress,fCallback){var _this0=this;var tmpViewIdentifier=typeof pViewIdentifier!=='string'?this.options.MainViewportViewIdentifier:pViewIdentifier;var tmpRenderableHash=typeof pRenderableHash!=='string'?this.options.MainViewportRenderableHash:pRenderableHash;var tmpRenderDestinationAddress=typeof pRenderDestinationAddress!=='string'?this.options.MainViewportDestinationAddress:pRenderDestinationAddress;var tmpTemplateDataAddress=typeof pTemplateDataAddress!=='string'?this.options.MainViewportDefaultDataAddress:pTemplateDataAddress;// Allow the callback to be passed in as the last parameter no matter what
225
+ var tmpCallback=typeof fCallback==='function'?fCallback:typeof pTemplateDataAddress==='function'?pTemplateDataAddress:typeof pRenderDestinationAddress==='function'?pRenderDestinationAddress:typeof pRenderableHash==='function'?pRenderableHash:typeof pViewIdentifier==='function'?pViewIdentifier:false;if(!tmpCallback){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this0.log.error("PictApp [".concat(_this0.UUID,"]::[").concat(_this0.Hash,"] ").concat(_this0.options.Name," renderAsync Auto Callback Error: ").concat(pError),pError);}};}if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow APPLICATION [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," VIEW Renderable[").concat(tmpRenderableHash,"] Destination[").concat(tmpRenderDestinationAddress,"] TemplateDataAddress[").concat(tmpTemplateDataAddress,"] renderAsync:"));}var tmpRenderAnticipate=this.fable.newAnticipate();tmpRenderAnticipate.anticipate(this.onBeforeRenderAsync.bind(this));var tmpView=typeof tmpViewIdentifier==='string'?this.servicesMap.PictView[tmpViewIdentifier]:false;if(!tmpView){var tmpErrorMessage="PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," could not asynchronously render from View ").concat(tmpViewIdentifier," because it is not a valid view.");if(this.pict.LogNoisiness>3){this.log.error(tmpErrorMessage);}return tmpCallback(new Error(tmpErrorMessage));}tmpRenderAnticipate.anticipate(this.onRenderAsync.bind(this));tmpRenderAnticipate.anticipate(function(fNext){tmpView.renderAsync.call(tmpView,tmpRenderableHash,tmpRenderDestinationAddress,tmpTemplateDataAddress,fNext);});tmpRenderAnticipate.anticipate(this.onAfterRenderAsync.bind(this));return tmpRenderAnticipate.wait(tmpCallback);}/**
226
+ * @return {boolean}
227
+ */},{key:"onAfterRender",value:function onAfterRender(){if(this.pict.LogNoisiness>3){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," onAfterRender:"));}return true;}/**
228
+ * @param {(error?: Error) => void} fCallback
229
+ */},{key:"onAfterRenderAsync",value:function onAfterRenderAsync(fCallback){this.onAfterRender();return fCallback();}/**
230
+ * @return {boolean}
231
+ */},{key:"renderMainViewport",value:function renderMainViewport(){if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow APPLICATION [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," renderMainViewport:"));}return this.render();}/**
232
+ * @param {(error?: Error) => void} fCallback
233
+ */},{key:"renderMainViewportAsync",value:function renderMainViewportAsync(fCallback){if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow APPLICATION [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," renderMainViewportAsync:"));}return this.renderAsync(fCallback);}/**
234
+ * @return {void}
235
+ */},{key:"renderAutoViews",value:function renderAutoViews(){var _this1=this;if(this.pict.LogNoisiness>0){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," beginning renderAutoViews..."));}// Now walk through any loaded views and sort them by the AutoRender ordinal
236
+ var tmpLoadedViews=Object.keys(this.pict.views);// Sort the views by their priority
237
+ // If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff
238
+ tmpLoadedViews.sort(function(a,b){return _this1.pict.views[a].options.AutoRenderOrdinal-_this1.pict.views[b].options.AutoRenderOrdinal;});for(var i=0;i<tmpLoadedViews.length;i++){var tmpView=this.pict.views[tmpLoadedViews[i]];if(tmpView.options.AutoRender){tmpView.render();}}if(this.pict.LogNoisiness>0){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," renderAutoViewsAsync complete."));}}/**
239
+ * @param {(error?: Error) => void} fCallback
240
+ */},{key:"renderAutoViewsAsync",value:function renderAutoViewsAsync(fCallback){var _this10=this;var tmpAnticipate=this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');// Allow the callback to be passed in as the last parameter no matter what
241
+ var tmpCallback=typeof fCallback==='function'?fCallback:false;if(!tmpCallback){this.log.warn("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," renderAutoViewsAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this10.log.error("PictApp [".concat(_this10.UUID,"]::[").concat(_this10.Hash,"] ").concat(_this10.options.Name," renderAutoViewsAsync Auto Callback Error: ").concat(pError),pError);}};}if(this.pict.LogNoisiness>0){this.log.trace("PictApp [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," beginning renderAutoViewsAsync..."));}// Now walk through any loaded views and sort them by the AutoRender ordinal
242
+ // TODO: Some optimization cleverness could be gained by grouping them into a parallelized async operation, by ordinal.
243
+ var tmpLoadedViews=Object.keys(this.pict.views);// Sort the views by their priority
244
+ // If they are all the default priority 0, it will end up being add order due to JSON Object Property Key order stuff
245
+ tmpLoadedViews.sort(function(a,b){return _this10.pict.views[a].options.AutoRenderOrdinal-_this10.pict.views[b].options.AutoRenderOrdinal;});for(var i=0;i<tmpLoadedViews.length;i++){var tmpView=this.pict.views[tmpLoadedViews[i]];if(tmpView.options.AutoRender){tmpAnticipate.anticipate(tmpView.renderAsync.bind(tmpView));}}tmpAnticipate.wait(function(pError){_this10.lastAutoRenderTimestamp=_this10.fable.log.getTimeStamp();if(_this10.pict.LogNoisiness>0){_this10.log.trace("PictApp [".concat(_this10.UUID,"]::[").concat(_this10.Hash,"] ").concat(_this10.options.Name," renderAutoViewsAsync complete."));}return tmpCallback(pError);});}/**
246
+ * @return {boolean}
247
+ */},{key:"isPictApplication",get:function get(){return true;}}]);}(libFableServiceBase);module.exports=PictApplication;},{"../package.json":5,"fable-serviceproviderbase":4}],7:[function(require,module,exports){module.exports={"name":"pict-provider","version":"1.0.12","description":"Pict Provider Base Class","main":"source/Pict-Provider.js","scripts":{"start":"node source/Pict-Provider.js","test":"npx quack test","tests":"npx quack test -g","coverage":"npx quack coverage","build":"npx quack build","docker-dev-build":"docker build ./ -f Dockerfile_LUXURYCode -t pict-provider-image:local","docker-dev-run":"docker run -it -d --name pict-provider-dev -p 24125:8080 -p 30027:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/pict-provider\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" pict-provider-image:local","docker-dev-shell":"docker exec -it pict-provider-dev /bin/bash","lint":"eslint source/**","types":"tsc -p ."},"types":"types/source/Pict-Provider.d.ts","repository":{"type":"git","url":"git+https://github.com/stevenvelozo/pict-provider.git"},"author":"steven velozo <steven@velozo.com>","license":"MIT","bugs":{"url":"https://github.com/stevenvelozo/pict-provider/issues"},"homepage":"https://github.com/stevenvelozo/pict-provider#readme","devDependencies":{"@eslint/js":"^9.39.1","eslint":"^9.39.1","pict":"^1.0.351","quackage":"^1.0.58","typescript":"^5.9.3"},"dependencies":{"fable-serviceproviderbase":"^3.0.19"},"mocha":{"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]}};},{}],8:[function(require,module,exports){var libFableServiceBase=require('fable-serviceproviderbase');var libPackage=require('../package.json');var defaultPictProviderSettings={ProviderIdentifier:false,// If this is set to true, when the App initializes this will.
248
+ // After the App initializes, initialize will be called as soon as it's added.
249
+ AutoInitialize:true,AutoInitializeOrdinal:0,AutoLoadDataWithApp:true,AutoLoadDataOrdinal:0,AutoSolveWithApp:true,AutoSolveOrdinal:0,Manifests:{},Templates:[]};var PictProvider=/*#__PURE__*/function(_libFableServiceBase2){/**
250
+ * @param {import('fable')} pFable - The Fable instance.
251
+ * @param {Record<string, any>} [pOptions] - The options for the provider.
252
+ * @param {string} [pServiceHash] - The service hash for the provider.
253
+ */function PictProvider(pFable,pOptions,pServiceHash){var _this11;_classCallCheck(this,PictProvider);// Intersect default options, parent constructor, service information
254
+ var tmpOptions=Object.assign({},JSON.parse(JSON.stringify(defaultPictProviderSettings)),pOptions);_this11=_callSuper(this,PictProvider,[pFable,tmpOptions,pServiceHash]);/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */_this11.fable;/** @type {import('fable') & import('pict') & { instantiateServiceProviderWithoutRegistration(pServiceType: string, pOptions?: Record<string, any>, pCustomServiceHash?: string): any }} */_this11.pict;/** @type {any} */_this11.log;/** @type {Record<string, any>} */_this11.options;/** @type {string} */_this11.UUID;/** @type {string} */_this11.Hash;if(!_this11.options.ProviderIdentifier){_this11.options.ProviderIdentifier="AutoProviderID-".concat(_this11.fable.getUUID());}_this11.serviceType='PictProvider';/** @type {Record<string, any>} */_this11._Package=libPackage;// Convenience and consistency naming
255
+ _this11.pict=_this11.fable;// Wire in the essential Pict application state
256
+ /** @type {Record<string, any>} */_this11.AppData=_this11.pict.AppData;/** @type {Record<string, any>} */_this11.Bundle=_this11.pict.Bundle;_this11.initializeTimestamp=false;_this11.lastSolvedTimestamp=false;for(var i=0;i<_this11.options.Templates.length;i++){var tmpDefaultTemplate=_this11.options.Templates[i];if(!tmpDefaultTemplate.hasOwnProperty('Postfix')||!tmpDefaultTemplate.hasOwnProperty('Template')){_this11.log.error("PictProvider [".concat(_this11.UUID,"]::[").concat(_this11.Hash,"] ").concat(_this11.options.ProviderIdentifier," could not load Default Template ").concat(i," in the options array."),tmpDefaultTemplate);}else{if(!tmpDefaultTemplate.Source){tmpDefaultTemplate.Source="PictProvider [".concat(_this11.UUID,"]::[").concat(_this11.Hash,"] ").concat(_this11.options.ProviderIdentifier," options object.");}_this11.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix,tmpDefaultTemplate.Postfix,tmpDefaultTemplate.Template,tmpDefaultTemplate.Source);}}return _this11;}/* -------------------------------------------------------------------------- *//* Code Section: Initialization *//* -------------------------------------------------------------------------- */_inherits(PictProvider,_libFableServiceBase2);return _createClass(PictProvider,[{key:"onBeforeInitialize",value:function onBeforeInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," onBeforeInitialize:"));}return true;}/**
257
+ * @param {(pError?: Error) => void} fCallback - The callback to call after pre-pinitialization.
258
+ *
259
+ * @return {void}
260
+ */},{key:"onBeforeInitializeAsync",value:function onBeforeInitializeAsync(fCallback){this.onBeforeInitialize();return fCallback();}},{key:"onInitialize",value:function onInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," onInitialize:"));}return true;}/**
261
+ * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.
262
+ *
263
+ * @return {void}
264
+ */},{key:"onInitializeAsync",value:function onInitializeAsync(fCallback){this.onInitialize();return fCallback();}},{key:"initialize",value:function initialize(){if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow PROVIDER [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," initialize:"));}if(!this.initializeTimestamp){this.onBeforeInitialize();this.onInitialize();this.onAfterInitialize();this.initializeTimestamp=this.pict.log.getTimeStamp();return true;}else{this.log.warn("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," initialize called but initialization is already completed. Aborting."));return false;}}/**
265
+ * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.
266
+ *
267
+ * @return {void}
268
+ */},{key:"initializeAsync",value:function initializeAsync(fCallback){var _this12=this;if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow PROVIDER [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," initializeAsync:"));}if(!this.initializeTimestamp){var tmpAnticipate=this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');if(this.pict.LogNoisiness>0){this.log.info("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," beginning initialization..."));}tmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));tmpAnticipate.anticipate(this.onInitializeAsync.bind(this));tmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));tmpAnticipate.wait(function(pError){_this12.initializeTimestamp=_this12.pict.log.getTimeStamp();if(pError){_this12.log.error("PictProvider [".concat(_this12.UUID,"]::[").concat(_this12.Hash,"] ").concat(_this12.options.ProviderIdentifier," initialization failed: ").concat(pError.message||pError),{Stack:pError.stack});}else if(_this12.pict.LogNoisiness>0){_this12.log.info("PictProvider [".concat(_this12.UUID,"]::[").concat(_this12.Hash,"] ").concat(_this12.options.ProviderIdentifier," initialization complete."));}return fCallback();});}else{this.log.warn("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," async initialize called but initialization is already completed. Aborting."));// TODO: Should this be an error?
269
+ return fCallback();}}},{key:"onAfterInitialize",value:function onAfterInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," onAfterInitialize:"));}return true;}/**
270
+ * @param {(pError?: Error) => void} fCallback - The callback to call after initialization.
271
+ *
272
+ * @return {void}
273
+ */},{key:"onAfterInitializeAsync",value:function onAfterInitializeAsync(fCallback){this.onAfterInitialize();return fCallback();}},{key:"onPreRender",value:function onPreRender(){if(this.pict.LogNoisiness>3){this.log.trace("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," onPreRender:"));}return true;}/**
274
+ * @param {(pError?: Error) => void} fCallback - The callback to call after pre-render.
275
+ *
276
+ * @return {void}
277
+ */},{key:"onPreRenderAsync",value:function onPreRenderAsync(fCallback){this.onPreRender();return fCallback();}},{key:"render",value:function render(){return this.onPreRender();}/**
278
+ * @param {(pError?: Error) => void} fCallback - The callback to call after render.
279
+ *
280
+ * @return {void}
281
+ */},{key:"renderAsync",value:function renderAsync(fCallback){this.onPreRender();return fCallback();}},{key:"onPreSolve",value:function onPreSolve(){if(this.pict.LogNoisiness>3){this.log.trace("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," onPreSolve:"));}return true;}/**
282
+ * @param {(pError?: Error) => void} fCallback - The callback to call after pre-solve.
283
+ *
284
+ * @return {void}
285
+ */},{key:"onPreSolveAsync",value:function onPreSolveAsync(fCallback){this.onPreSolve();return fCallback();}},{key:"solve",value:function solve(){return this.onPreSolve();}/**
286
+ * @param {(pError?: Error) => void} fCallback - The callback to call after solve.
287
+ *
288
+ * @return {void}
289
+ */},{key:"solveAsync",value:function solveAsync(fCallback){this.onPreSolve();return fCallback();}/**
290
+ * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.
291
+ */},{key:"onBeforeLoadDataAsync",value:function onBeforeLoadDataAsync(fCallback){return fCallback();}/**
292
+ * Hook to allow the provider to load data during application data load.
293
+ *
294
+ * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.
295
+ */},{key:"onLoadDataAsync",value:function onLoadDataAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," onLoadDataAsync:"));}return fCallback();}/**
296
+ * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.
297
+ */},{key:"onAfterLoadDataAsync",value:function onAfterLoadDataAsync(fCallback){return fCallback();}/**
298
+ * @param {(pError?: Error) => void} fCallback - The callback to call after the data pre-load.
299
+ *
300
+ * @return {void}
301
+ */},{key:"onBeforeSaveDataAsync",value:function onBeforeSaveDataAsync(fCallback){return fCallback();}/**
302
+ * Hook to allow the provider to load data during application data load.
303
+ *
304
+ * @param {(pError?: Error) => void} fCallback - The callback to call after the data load.
305
+ *
306
+ * @return {void}
307
+ */},{key:"onSaveDataAsync",value:function onSaveDataAsync(fCallback){if(this.pict.LogNoisiness>3){this.log.trace("PictProvider [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ProviderIdentifier," onSaveDataAsync:"));}return fCallback();}/**
308
+ * @param {(pError?: Error) => void} fCallback - The callback to call after the data post-load.
309
+ *
310
+ * @return {void}
311
+ */},{key:"onAfterSaveDataAsync",value:function onAfterSaveDataAsync(fCallback){return fCallback();}}]);}(libFableServiceBase);module.exports=PictProvider;},{"../package.json":7,"fable-serviceproviderbase":4}],9:[function(require,module,exports){// The container for all the Pict-Section-Flow related code.
312
+ // The main flow diagram view class
313
+ module.exports=require('./views/PictView-Flow.js');// Node rendering view
314
+ module.exports.PictViewFlowNode=require('./views/PictView-Flow-Node.js');// Toolbar views
315
+ module.exports.PictViewFlowToolbar=require('./views/PictView-Flow-Toolbar.js');module.exports.PictViewFlowFloatingToolbar=require('./views/PictView-Flow-FloatingToolbar.js');// Services
316
+ module.exports.PictServiceFlowInteractionManager=require('./services/PictService-Flow-InteractionManager.js');module.exports.PictServiceFlowConnectionRenderer=require('./services/PictService-Flow-ConnectionRenderer.js');module.exports.PictServiceFlowTether=require('./services/PictService-Flow-Tether.js');module.exports.PictServiceFlowLayout=require('./services/PictService-Flow-Layout.js');module.exports.PictServiceFlowPathGenerator=require('./services/PictService-Flow-PathGenerator.js');module.exports.PictServiceFlowViewportManager=require('./services/PictService-Flow-ViewportManager.js');module.exports.PictServiceFlowSelectionManager=require('./services/PictService-Flow-SelectionManager.js');module.exports.PictServiceFlowPanelManager=require('./services/PictService-Flow-PanelManager.js');module.exports.PictServiceFlowDataManager=require('./services/PictService-Flow-DataManager.js');module.exports.PictServiceFlowConnectionHandleManager=require('./services/PictService-Flow-ConnectionHandleManager.js');module.exports.PictServiceFlowRenderManager=require('./services/PictService-Flow-RenderManager.js');module.exports.PictServiceFlowPortRenderer=require('./services/PictService-Flow-PortRenderer.js');// Providers
317
+ module.exports.PictProviderFlowNodeTypes=require('./providers/PictProvider-Flow-NodeTypes.js');module.exports.PictProviderFlowEventHandler=require('./providers/PictProvider-Flow-EventHandler.js');module.exports.PictProviderFlowLayouts=require('./providers/PictProvider-Flow-Layouts.js');module.exports.PictProviderFlowSVGHelpers=require('./providers/PictProvider-Flow-SVGHelpers.js');module.exports.PictProviderFlowGeometry=require('./providers/PictProvider-Flow-Geometry.js');module.exports.PictProviderFlowPanelChrome=require('./providers/PictProvider-Flow-PanelChrome.js');module.exports.PictProviderFlowCSS=require('./providers/PictProvider-Flow-CSS.js');module.exports.PictProviderFlowIcons=require('./providers/PictProvider-Flow-Icons.js');module.exports.PictProviderFlowConnectorShapes=require('./providers/PictProvider-Flow-ConnectorShapes.js');// FlowCard base class
318
+ module.exports.PictFlowCard=require('./PictFlowCard.js');// FlowCardPropertiesPanel base class and panel types
319
+ module.exports.PictFlowCardPropertiesPanel=require('./PictFlowCardPropertiesPanel.js');module.exports.FlowCardPropertiesPanelTemplate=require('./panels/FlowCardPropertiesPanel-Template.js');module.exports.FlowCardPropertiesPanelMarkdown=require('./panels/FlowCardPropertiesPanel-Markdown.js');module.exports.FlowCardPropertiesPanelForm=require('./panels/FlowCardPropertiesPanel-Form.js');module.exports.FlowCardPropertiesPanelView=require('./panels/FlowCardPropertiesPanel-View.js');// Properties panel renderer view
320
+ module.exports.PictViewFlowPropertiesPanel=require('./views/PictView-Flow-PropertiesPanel.js');},{"./PictFlowCard.js":10,"./PictFlowCardPropertiesPanel.js":11,"./panels/FlowCardPropertiesPanel-Form.js":12,"./panels/FlowCardPropertiesPanel-Markdown.js":13,"./panels/FlowCardPropertiesPanel-Template.js":14,"./panels/FlowCardPropertiesPanel-View.js":15,"./providers/PictProvider-Flow-CSS.js":16,"./providers/PictProvider-Flow-ConnectorShapes.js":17,"./providers/PictProvider-Flow-EventHandler.js":18,"./providers/PictProvider-Flow-Geometry.js":19,"./providers/PictProvider-Flow-Icons.js":20,"./providers/PictProvider-Flow-Layouts.js":21,"./providers/PictProvider-Flow-NodeTypes.js":22,"./providers/PictProvider-Flow-PanelChrome.js":24,"./providers/PictProvider-Flow-SVGHelpers.js":25,"./services/PictService-Flow-ConnectionHandleManager.js":27,"./services/PictService-Flow-ConnectionRenderer.js":28,"./services/PictService-Flow-DataManager.js":29,"./services/PictService-Flow-InteractionManager.js":30,"./services/PictService-Flow-Layout.js":31,"./services/PictService-Flow-PanelManager.js":32,"./services/PictService-Flow-PathGenerator.js":33,"./services/PictService-Flow-PortRenderer.js":34,"./services/PictService-Flow-RenderManager.js":35,"./services/PictService-Flow-SelectionManager.js":36,"./services/PictService-Flow-Tether.js":37,"./services/PictService-Flow-ViewportManager.js":38,"./views/PictView-Flow-FloatingToolbar.js":39,"./views/PictView-Flow-Node.js":40,"./views/PictView-Flow-PropertiesPanel.js":41,"./views/PictView-Flow-Toolbar.js":42,"./views/PictView-Flow.js":43}],10:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
321
+ * PictFlowCard - Base class for flow diagram cards.
322
+ *
323
+ * Developers create subclasses of PictFlowCard to define reusable node types
324
+ * that appear in the flow palette. Each card describes a discrete operation
325
+ * (e.g. "If-Then-Else", "File Read") with configurable inputs, outputs, and
326
+ * metadata. Pict-Section-Flow uses registered cards to build a palette for
327
+ * the user to drag onto the graph.
328
+ *
329
+ * Configurable properties:
330
+ * - Title (string, required) - Display name shown on the node
331
+ * - Name (string, optional) - Longer descriptive name
332
+ * - Code (string, required) - Short identifier (e.g. "ITE", "SW")
333
+ * - Description (string, optional) - Brief explanation of what the card does
334
+ * - Icon (string, optional) - Icon identifier or emoji
335
+ * - PreviewImage (string, optional) - URL to a preview/thumbnail image
336
+ * - Documentation (string, optional) - URL or inline documentation text
337
+ * - Tooltip (string, optional) - Hover tooltip text
338
+ * - Inputs (array) - Named input ports, each with:
339
+ * - Name (string) - Port label
340
+ * - Side (string) - Port side ('left', 'top', etc.)
341
+ * - MinimumInputCount (number) - Minimum connections accepted (default 0)
342
+ * - MaximumInputCount (number) - Maximum connections accepted (default -1, unlimited)
343
+ * - Outputs (array) - Named output ports
344
+ * - Enabled (boolean) - Whether this card is available in the palette
345
+ * - PropertiesPanel (object, optional) - Configuration for the on-graph properties panel
346
+ * - PanelType (string) - 'Template', 'Markdown', 'Form', or 'View'
347
+ * - DefaultWidth (number) - Panel width (default 300)
348
+ * - DefaultHeight (number) - Panel height (default 200)
349
+ * - Title (string) - Panel title bar text
350
+ * - Configuration (object) - Panel-type-specific configuration
351
+ * - BodyContent (object, optional) - Custom content rendered in the node body area
352
+ * - ContentType (string) - 'svg', 'html', or 'canvas'
353
+ * - Template (string) - Pict template string (html/svg only)
354
+ * - TemplateHash (string) - Registered template hash (takes precedence over Template)
355
+ * - Templates (array) - Template definitions to register [{Hash, Template}]
356
+ * - RenderCallback (function)- Imperative render callback (required for canvas)
357
+ * - Padding (number) - Inner padding in pixels (default 2)
358
+ * - ShowTypeLabel (boolean, default true) - Whether to show the type label/code badge on hover
359
+ * - PortLabelsOnHover (boolean, default false) - When true, port labels only appear on hover
360
+ * - PortLabelsVertical (boolean, default false) - When true, port labels render vertically
361
+ * - PortLabelPadding (boolean, default false) - When true, port labels have extra padding to avoid overlapping body content
362
+ * - LabelsInFront (boolean, default true) - When true, labels render in front of body content; when false, behind
363
+ *
364
+ * Usage:
365
+ * class MyCard extends PictFlowCard {
366
+ * constructor(pFable, pOptions, pServiceHash) {
367
+ * super(pFable, pOptions, pServiceHash);
368
+ * this.cardTitle = 'My Card';
369
+ * this.cardCode = 'MC';
370
+ * this.cardInputs = [{ Name: 'Data', Side: 'left', MinimumInputCount: 1, MaximumInputCount: 1 }];
371
+ * this.cardOutputs = [{ Name: 'Result', Side: 'right' }];
372
+ * }
373
+ * }
374
+ */var PictFlowCard=/*#__PURE__*/function(_libFableServiceProvi){function PictFlowCard(pFable,pOptions,pServiceHash){var _this13;_classCallCheck(this,PictFlowCard);var tmpOptions=Object.assign({},PictFlowCard.default_configuration,pOptions);_this13=_callSuper(this,PictFlowCard,[pFable,tmpOptions,pServiceHash]);_this13.serviceType='PictFlowCard';// --- Card metadata ---
375
+ _this13.cardTitle=tmpOptions.Title?tmpOptions.Title:'Card';_this13.cardName=tmpOptions.Name?tmpOptions.Name:false;_this13.cardCode=tmpOptions.Code?tmpOptions.Code:'';_this13.cardDescription=tmpOptions.Description?tmpOptions.Description:false;_this13.cardIcon=tmpOptions.Icon?tmpOptions.Icon:false;_this13.cardPreviewImage=tmpOptions.PreviewImage?tmpOptions.PreviewImage:false;_this13.cardDocumentation=tmpOptions.Documentation?tmpOptions.Documentation:false;_this13.cardTooltip=tmpOptions.Tooltip?tmpOptions.Tooltip:false;_this13.cardHelp=tmpOptions.Help?tmpOptions.Help:false;// --- Card enabled state ---
376
+ _this13.cardEnabled=typeof tmpOptions.Enabled==='boolean'?tmpOptions.Enabled:true;// --- Card appearance ---
377
+ _this13.cardTitleBarColor=tmpOptions.TitleBarColor?tmpOptions.TitleBarColor:'#2c3e50';_this13.cardBodyStyle=tmpOptions.BodyStyle?tmpOptions.BodyStyle:{};_this13.cardWidth=typeof tmpOptions.Width==='number'?tmpOptions.Width:180;_this13.cardHeight=typeof tmpOptions.Height==='number'?tmpOptions.Height:80;_this13.cardCategory=tmpOptions.Category?tmpOptions.Category:'General';// --- Input and Output port definitions ---
378
+ // Inputs: [{ Name: 'In', Side: 'left', MinimumInputCount: 0, MaximumInputCount: -1 }]
379
+ // Outputs: [{ Name: 'Out', Side: 'right' }]
380
+ _this13.cardInputs=Array.isArray(tmpOptions.Inputs)?tmpOptions.Inputs:[];_this13.cardOutputs=Array.isArray(tmpOptions.Outputs)?tmpOptions.Outputs:[];// --- Properties panel configuration ---
381
+ _this13.cardPropertiesPanel=tmpOptions.PropertiesPanel&&_typeof(tmpOptions.PropertiesPanel)==='object'?tmpOptions.PropertiesPanel:null;// --- Body content configuration ---
382
+ _this13.cardBodyContent=tmpOptions.BodyContent&&_typeof(tmpOptions.BodyContent)==='object'?tmpOptions.BodyContent:null;// --- Label display booleans ---
383
+ _this13.cardShowTypeLabel=typeof tmpOptions.ShowTypeLabel==='boolean'?tmpOptions.ShowTypeLabel:true;_this13.cardPortLabelsOnHover=typeof tmpOptions.PortLabelsOnHover==='boolean'?tmpOptions.PortLabelsOnHover:false;_this13.cardPortLabelsVertical=typeof tmpOptions.PortLabelsVertical==='boolean'?tmpOptions.PortLabelsVertical:false;_this13.cardPortLabelPadding=typeof tmpOptions.PortLabelPadding==='boolean'?tmpOptions.PortLabelPadding:false;_this13.cardPortLabelsOutside=typeof tmpOptions.PortLabelsOutside==='boolean'?tmpOptions.PortLabelsOutside:false;_this13.cardLabelsInFront=typeof tmpOptions.LabelsInFront==='boolean'?tmpOptions.LabelsInFront:true;return _this13;}/**
384
+ * Generate the node type configuration object for the NodeTypes provider.
385
+ * This converts the card's properties into the format expected by
386
+ * PictProviderFlowNodeTypes.registerNodeType().
387
+ *
388
+ * @returns {Object} Node type configuration
389
+ */_inherits(PictFlowCard,_libFableServiceProvi);return _createClass(PictFlowCard,[{key:"getNodeTypeConfiguration",value:function getNodeTypeConfiguration(){var tmpPorts=[];// Build input ports
390
+ for(var i=0;i<this.cardInputs.length;i++){var tmpInput=this.cardInputs[i];var tmpPort={Hash:null,Direction:'input',Side:tmpInput.Side||'left',Label:tmpInput.Name||"In ".concat(i+1),MinimumInputCount:typeof tmpInput.MinimumInputCount==='number'?tmpInput.MinimumInputCount:0,MaximumInputCount:typeof tmpInput.MaximumInputCount==='number'?tmpInput.MaximumInputCount:-1};if(tmpInput.PortType){tmpPort.PortType=tmpInput.PortType;}if(tmpInput.DataType){tmpPort.DataType=tmpInput.DataType;}tmpPorts.push(tmpPort);}// Build output ports
391
+ for(var _i23=0;_i23<this.cardOutputs.length;_i23++){var tmpOutput=this.cardOutputs[_i23];var tmpOutPort={Hash:null,Direction:'output',Side:tmpOutput.Side||'right',Label:tmpOutput.Name||"Out ".concat(_i23+1)};if(tmpOutput.PortType){tmpOutPort.PortType=tmpOutput.PortType;}if(tmpOutput.DataType){tmpOutPort.DataType=tmpOutput.DataType;}tmpPorts.push(tmpOutPort);}// If no ports were defined, provide sensible defaults
392
+ if(tmpPorts.length===0){tmpPorts.push({Hash:null,Direction:'input',Side:'left',Label:'In'});tmpPorts.push({Hash:null,Direction:'output',Side:'right',Label:'Out'});}var tmpResult={Hash:this.cardCode,Label:this.cardTitle,DefaultWidth:this.cardWidth,DefaultHeight:this.cardHeight,DefaultPorts:tmpPorts,TitleBarColor:this.cardTitleBarColor,BodyStyle:JSON.parse(JSON.stringify(this.cardBodyStyle)),// Extended FlowCard metadata stored alongside the type
393
+ CardMetadata:{Name:this.cardName,Code:this.cardCode,Description:this.cardDescription,Icon:this.cardIcon,PreviewImage:this.cardPreviewImage,Documentation:this.cardDocumentation,Tooltip:this.cardTooltip,Enabled:this.cardEnabled,Category:this.cardCategory,Help:this.cardHelp}};// Include label display booleans
394
+ tmpResult.ShowTypeLabel=this.cardShowTypeLabel;tmpResult.PortLabelsOnHover=this.cardPortLabelsOnHover;tmpResult.PortLabelsVertical=this.cardPortLabelsVertical;tmpResult.PortLabelPadding=this.cardPortLabelPadding;tmpResult.PortLabelsOutside=this.cardPortLabelsOutside;tmpResult.LabelsInFront=this.cardLabelsInFront;// Include properties panel config if defined
395
+ if(this.cardPropertiesPanel){tmpResult.PropertiesPanel=JSON.parse(JSON.stringify(this.cardPropertiesPanel));}// Include body content config if defined
396
+ if(this.cardBodyContent){tmpResult.BodyContent=JSON.parse(JSON.stringify(this.cardBodyContent));// RenderCallback cannot be serialized — preserve the original function reference
397
+ if(typeof this.options.BodyContent.RenderCallback==='function'){tmpResult.BodyContent.RenderCallback=this.options.BodyContent.RenderCallback;}}return tmpResult;}/**
398
+ * Register this card with a FlowView's node type provider.
399
+ *
400
+ * @param {Object} pFlowView - The PictViewFlow instance
401
+ * @returns {boolean} Whether registration succeeded
402
+ */},{key:"registerWithFlowView",value:function registerWithFlowView(pFlowView){if(!pFlowView||!pFlowView._NodeTypeProvider){this.log.warn('PictFlowCard registerWithFlowView: no valid FlowView or NodeTypeProvider');return false;}var tmpConfig=this.getNodeTypeConfiguration();return pFlowView._NodeTypeProvider.registerNodeType(tmpConfig);}}]);}(libFableServiceProviderBase);module.exports=PictFlowCard;module.exports.default_configuration={Title:'Card',Name:false,Code:'',Description:false,Icon:false,PreviewImage:false,Documentation:false,Tooltip:false,Inputs:[],Outputs:[],Enabled:true,TitleBarColor:'#2c3e50',BodyStyle:{},Width:180,Height:80,Category:'General',PropertiesPanel:null,BodyContent:null,ShowTypeLabel:true,PortLabelsOnHover:false,PortLabelsVertical:false,PortLabelPadding:false,PortLabelsOutside:false,LabelsInFront:true};},{"fable-serviceproviderbase":4}],11:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
403
+ * PictFlowCardPropertiesPanel - Base class for flow card property panels.
404
+ *
405
+ * Developers create subclasses to define what UI appears when a user opens
406
+ * the properties panel for a node on the flow graph. Four built-in panel
407
+ * types are provided:
408
+ *
409
+ * - Template - Renders pict templates
410
+ * - Markdown - Renders markdown via pict-section-content
411
+ * - Form - Creates an ephemeral pict-section-form section
412
+ * - View - Renders an existing registered pict-view
413
+ *
414
+ * Configurable properties:
415
+ * - PanelType (string) - Panel type identifier
416
+ * - Title (string) - Panel title bar text
417
+ * - Width (number) - Default panel width in pixels
418
+ * - Height (number) - Default panel height in pixels
419
+ * - Configuration (object) - Panel-type-specific configuration
420
+ */var PictFlowCardPropertiesPanel=/*#__PURE__*/function(_libFableServiceProvi2){function PictFlowCardPropertiesPanel(pFable,pOptions,pServiceHash){var _this14;_classCallCheck(this,PictFlowCardPropertiesPanel);var tmpOptions=Object.assign({},PictFlowCardPropertiesPanel.default_configuration,pOptions);_this14=_callSuper(this,PictFlowCardPropertiesPanel,[pFable,tmpOptions,pServiceHash]);_this14.serviceType='PictFlowCardPropertiesPanel';// Panel metadata
421
+ _this14.panelType=tmpOptions.PanelType||'Base';_this14.panelTitle=tmpOptions.Title||'Properties';_this14.panelWidth=typeof tmpOptions.Width==='number'?tmpOptions.Width:300;_this14.panelHeight=typeof tmpOptions.Height==='number'?tmpOptions.Height:200;// Reference to the flow view (set when panel is activated)
422
+ _this14._FlowView=null;// The node data this panel is operating on (set when panel is opened)
423
+ _this14._NodeData=null;// The DOM container element for panel content (set during render)
424
+ _this14._ContentContainer=null;// The panel configuration (panel-type-specific)
425
+ _this14._Configuration=tmpOptions.Configuration||{};return _this14;}/**
426
+ * Render the panel's content into a DOM container element.
427
+ * Subclasses MUST override this.
428
+ *
429
+ * @param {HTMLElement} pContainer - The DOM element to render into
430
+ * @param {Object} pNodeData - The node data object (has .Data property)
431
+ */_inherits(PictFlowCardPropertiesPanel,_libFableServiceProvi2);return _createClass(PictFlowCardPropertiesPanel,[{key:"render",value:function render(pContainer,pNodeData){this._ContentContainer=pContainer;this._NodeData=pNodeData;}/**
432
+ * Marshal data FROM the node's Data object INTO the panel UI.
433
+ * Called when the panel opens or when data changes externally.
434
+ *
435
+ * @param {Object} pNodeData
436
+ */},{key:"marshalToPanel",value:function marshalToPanel(pNodeData){this._NodeData=pNodeData;}/**
437
+ * Marshal data FROM the panel UI INTO the node's Data object.
438
+ * Called before saving or when the panel is about to close.
439
+ *
440
+ * @param {Object} pNodeData
441
+ */},{key:"marshalFromPanel",value:function marshalFromPanel(pNodeData){// Subclasses override
442
+ }/**
443
+ * Called when the panel is being destroyed (closed).
444
+ * Subclasses should clean up resources.
445
+ */},{key:"destroy",value:function destroy(){this._ContentContainer=null;this._NodeData=null;}}]);}(libFableServiceProviderBase);module.exports=PictFlowCardPropertiesPanel;module.exports.default_configuration={PanelType:'Base',Title:'Properties',Width:300,Height:200,Configuration:{}};},{"fable-serviceproviderbase":4}],12:[function(require,module,exports){var libPictFlowCardPropertiesPanel=require('../PictFlowCardPropertiesPanel.js');/**
446
+ * FlowCardPropertiesPanel-Form
447
+ *
448
+ * Creates an ephemeral pict-section-form section to edit the node's Data object.
449
+ * Uses PictViewFormMetacontroller.injectManifest() to dynamically create form
450
+ * sections at runtime.
451
+ *
452
+ * Note: pict-section-form must be available in the consuming application
453
+ * (it is an optional/peer dependency, not bundled with pict-section-flow).
454
+ *
455
+ * Configuration:
456
+ * {
457
+ * PanelType: 'Form',
458
+ * Configuration: {
459
+ * Manifest: {
460
+ * Sections: [...],
461
+ * Descriptors: {...}
462
+ * }
463
+ * }
464
+ * }
465
+ */var FlowCardPropertiesPanelForm=/*#__PURE__*/function(_libPictFlowCardPrope){function FlowCardPropertiesPanelForm(pFable,pOptions,pServiceHash){var _this15;_classCallCheck(this,FlowCardPropertiesPanelForm);_this15=_callSuper(this,FlowCardPropertiesPanelForm,[pFable,pOptions,pServiceHash]);_this15.serviceType='PictFlowCardPropertiesPanel-Form';_this15._Metacontroller=null;_this15._InjectedSectionHash=null;return _this15;}/**
466
+ * Render the form into the panel body.
467
+ */_inherits(FlowCardPropertiesPanelForm,_libPictFlowCardPrope);return _createClass(FlowCardPropertiesPanelForm,[{key:"render",value:function render(pContainer,pNodeData){_superPropGet(FlowCardPropertiesPanelForm,"render",this,3)([pContainer,pNodeData]);if(!this._Configuration||!this._Configuration.Manifest){pContainer.innerHTML='<em>No form manifest configured</em>';return;}// Create a unique container ID for the form section
468
+ var tmpContainerID="pict-flow-panel-form-".concat(pNodeData.Hash);pContainer.innerHTML="<div id=\"".concat(tmpContainerID,"\"></div>");// Bind the node data to AppData.Record so the form descriptors
469
+ // (which use addresses like Record.Data.SearchString) resolve against
470
+ // the actual node object.
471
+ this.fable.AppData.Record=pNodeData;try{// Look for an existing metacontroller or create one
472
+ if(!this._Metacontroller){// Try to find PictFormMetacontroller service type (check both common names)
473
+ var tmpServiceType=null;if(this.fable.servicesMap.hasOwnProperty('PictFormMetacontroller')){tmpServiceType='PictFormMetacontroller';}else if(this.fable.servicesMap.hasOwnProperty('PictViewFormMetacontroller')){tmpServiceType='PictViewFormMetacontroller';}if(tmpServiceType){this._Metacontroller=this.fable.instantiateServiceProviderWithoutRegistration(tmpServiceType,{ViewIdentifier:"FlowPanelForm-".concat(pNodeData.Hash),DefaultDestinationAddress:"#".concat(tmpContainerID),AutoRender:false,AutoPopulateAfterRender:true,AutoSolveBeforeRender:false});}}if(this._Metacontroller&&typeof this._Metacontroller.injectManifestAndRender==='function'){// Create the FormContainer div that the metacontroller's
474
+ // updateMetatemplateInDOM() expects when adding section wrappers.
475
+ // Normally this is created when the metacontroller renders its own
476
+ // metatemplate, but we skip that step since we only need the
477
+ // injected section views, not the metacontroller's own renderable.
478
+ var tmpFormContainerID="Pict-".concat(this._Metacontroller.UUID,"-FormContainer");var tmpContainerEl=pContainer.querySelector("#".concat(tmpContainerID));if(tmpContainerEl){tmpContainerEl.innerHTML="<div id=\"".concat(tmpFormContainerID,"\" class=\"pict-form\"></div>");}// Deep clone the manifest so each panel gets its own copy
479
+ var tmpManifest=JSON.parse(JSON.stringify(this._Configuration.Manifest));this._InjectedSectionHash=tmpManifest.Hash||null;// Use injectManifestAndRender which properly creates section views,
480
+ // updates the metatemplate in the DOM, and renders each section view
481
+ this._Metacontroller.injectManifestAndRender(tmpManifest);}else if(this._Metacontroller&&typeof this._Metacontroller.injectManifest==='function'){// Fallback for older pict-section-form versions: inject the
482
+ // manifest and render each section view individually
483
+ var _tmpManifest=JSON.parse(JSON.stringify(this._Configuration.Manifest));var tmpViewsToRender=this._Metacontroller.injectManifest(_tmpManifest);this._InjectedSectionHash=_tmpManifest.Hash||null;// Create container divs for each section view and render them
484
+ var _tmpContainerEl=pContainer.querySelector("#".concat(tmpContainerID));if(_tmpContainerEl&&tmpViewsToRender.length>0){var tmpInnerHTML='';for(var i=0;i<tmpViewsToRender.length;i++){var tmpDestID=tmpViewsToRender[i].options.DefaultDestinationAddress;if(tmpDestID&&tmpDestID.charAt(0)==='#'){tmpDestID=tmpDestID.substring(1);}tmpInnerHTML+="<div id=\"".concat(tmpDestID,"\" class=\"pict-form-view\"></div>");}_tmpContainerEl.innerHTML=tmpInnerHTML;for(var _i24=0;_i24<tmpViewsToRender.length;_i24++){tmpViewsToRender[_i24].render();}}}else{pContainer.innerHTML='<em>pict-section-form is not available. Install it in your application to use Form panels.</em>';}}catch(pError){this.log.warn("FlowCardPropertiesPanel-Form render error: ".concat(pError.message));pContainer.innerHTML="<em>Form render error: ".concat(pError.message,"</em>");}}},{key:"marshalFromPanel",value:function marshalFromPanel(pNodeData){if(this._Metacontroller&&typeof this._Metacontroller.marshalFromView==='function'){this._Metacontroller.marshalFromView();}}},{key:"destroy",value:function destroy(){this._Metacontroller=null;this._InjectedSectionHash=null;_superPropGet(FlowCardPropertiesPanelForm,"destroy",this,3)([]);}}]);}(libPictFlowCardPropertiesPanel);module.exports=FlowCardPropertiesPanelForm;module.exports.default_configuration=Object.assign({},libPictFlowCardPropertiesPanel.default_configuration,{PanelType:'Form',Configuration:{Manifest:null}});},{"../PictFlowCardPropertiesPanel.js":11}],13:[function(require,module,exports){var libPictFlowCardPropertiesPanel=require('../PictFlowCardPropertiesPanel.js');/**
485
+ * FlowCardPropertiesPanel-Markdown
486
+ *
487
+ * Renders markdown content into the panel body using pict-section-content's
488
+ * PictContentProvider service. When pict-section-content is installed and its
489
+ * PictContentProvider service type has been registered with the pict instance,
490
+ * full markdown rendering is available (headings, lists, tables, code blocks
491
+ * with syntax highlighting, KaTeX equations, Mermaid diagrams, etc.).
492
+ *
493
+ * If PictContentProvider is not available, the panel falls back to displaying
494
+ * the raw markdown as pre-formatted text.
495
+ *
496
+ * Configuration:
497
+ * {
498
+ * PanelType: 'Markdown',
499
+ * Configuration: {
500
+ * Markdown: '# Title\nSome **markdown** content'
501
+ * }
502
+ * }
503
+ *
504
+ * Or use an address to pull markdown from the node's data:
505
+ * {
506
+ * PanelType: 'Markdown',
507
+ * Configuration: {
508
+ * MarkdownAddress: 'Data.MarkdownContent'
509
+ * }
510
+ * }
511
+ */var FlowCardPropertiesPanelMarkdown=/*#__PURE__*/function(_libPictFlowCardPrope2){function FlowCardPropertiesPanelMarkdown(pFable,pOptions,pServiceHash){var _this16;_classCallCheck(this,FlowCardPropertiesPanelMarkdown);_this16=_callSuper(this,FlowCardPropertiesPanelMarkdown,[pFable,pOptions,pServiceHash]);_this16.serviceType='PictFlowCardPropertiesPanel-Markdown';_this16._ContentProvider=null;return _this16;}/**
512
+ * Render markdown into the panel.
513
+ */_inherits(FlowCardPropertiesPanelMarkdown,_libPictFlowCardPrope2);return _createClass(FlowCardPropertiesPanelMarkdown,[{key:"render",value:function render(pContainer,pNodeData){_superPropGet(FlowCardPropertiesPanelMarkdown,"render",this,3)([pContainer,pNodeData]);this._renderMarkdown();}},{key:"marshalToPanel",value:function marshalToPanel(pNodeData){_superPropGet(FlowCardPropertiesPanelMarkdown,"marshalToPanel",this,3)([pNodeData]);this._renderMarkdown();}},{key:"_renderMarkdown",value:function _renderMarkdown(){if(!this._ContentContainer||!this._Configuration)return;var tmpMarkdown='';if(this._Configuration.MarkdownAddress&&this._NodeData){// Resolve markdown from node data using manyfest
514
+ tmpMarkdown=this.fable.manifest.getValueByHash(this._NodeData,this._Configuration.MarkdownAddress)||'';}else if(this._Configuration.Markdown){tmpMarkdown=this._Configuration.Markdown;}if(!tmpMarkdown){this._ContentContainer.innerHTML='<em>No content</em>';return;}// Use pict-section-content's PictContentProvider for markdown rendering.
515
+ // The consuming application must register the PictContentProvider service
516
+ // type (from pict-section-content) for this to work.
517
+ try{if(!this._ContentProvider){if(this.fable.servicesMap.hasOwnProperty('PictContentProvider')){this._ContentProvider=this.fable.instantiateServiceProviderWithoutRegistration('PictContentProvider',{});}}if(this._ContentProvider&&typeof this._ContentProvider.parseMarkdown==='function'){var tmpHTML=this._ContentProvider.parseMarkdown(tmpMarkdown);this._ContentContainer.innerHTML=tmpHTML;// Post-render hooks for equations and diagrams
518
+ if(typeof this._ContentProvider.renderKaTeXEquations==='function'){this._ContentProvider.renderKaTeXEquations(this._ContentContainer);}if(typeof this._ContentProvider.renderMermaidDiagrams==='function'){this._ContentProvider.renderMermaidDiagrams(this._ContentContainer);}}else{// PictContentProvider not registered — render as pre-formatted text
519
+ this._ContentContainer.innerHTML="<pre style=\"white-space: pre-wrap; font-family: inherit;\">".concat(this._escapeHTML(tmpMarkdown),"</pre>");}}catch(pError){this.log.warn("FlowCardPropertiesPanel-Markdown render error: ".concat(pError.message));this._ContentContainer.innerHTML="<pre style=\"white-space: pre-wrap; font-family: inherit;\">".concat(this._escapeHTML(tmpMarkdown),"</pre>");}}},{key:"_escapeHTML",value:function _escapeHTML(pText){var tmpDiv=document.createElement('div');tmpDiv.textContent=pText;return tmpDiv.innerHTML;}},{key:"destroy",value:function destroy(){this._ContentProvider=null;_superPropGet(FlowCardPropertiesPanelMarkdown,"destroy",this,3)([]);}}]);}(libPictFlowCardPropertiesPanel);module.exports=FlowCardPropertiesPanelMarkdown;module.exports.default_configuration=Object.assign({},libPictFlowCardPropertiesPanel.default_configuration,{PanelType:'Markdown',Configuration:{Markdown:'',MarkdownAddress:''}});},{"../PictFlowCardPropertiesPanel.js":11}],14:[function(require,module,exports){var libPictFlowCardPropertiesPanel=require('../PictFlowCardPropertiesPanel.js');/**
520
+ * FlowCardPropertiesPanel-Template
521
+ *
522
+ * Renders pict templates into the panel body.
523
+ *
524
+ * Configuration:
525
+ * {
526
+ * PanelType: 'Template',
527
+ * Configuration: {
528
+ * Templates: [
529
+ * { Hash: 'my-template', Template: '<div>{~D:Record.Data.SomeValue~}</div>' }
530
+ * ],
531
+ * TemplateHash: 'my-template'
532
+ * }
533
+ * }
534
+ */var FlowCardPropertiesPanelTemplate=/*#__PURE__*/function(_libPictFlowCardPrope3){function FlowCardPropertiesPanelTemplate(pFable,pOptions,pServiceHash){var _this17;_classCallCheck(this,FlowCardPropertiesPanelTemplate);_this17=_callSuper(this,FlowCardPropertiesPanelTemplate,[pFable,pOptions,pServiceHash]);_this17.serviceType='PictFlowCardPropertiesPanel-Template';_this17._TemplatesRegistered=false;return _this17;}/**
535
+ * Register templates with the pict template provider and render.
536
+ */_inherits(FlowCardPropertiesPanelTemplate,_libPictFlowCardPrope3);return _createClass(FlowCardPropertiesPanelTemplate,[{key:"render",value:function render(pContainer,pNodeData){_superPropGet(FlowCardPropertiesPanelTemplate,"render",this,3)([pContainer,pNodeData]);if(!this._Configuration||!this._Configuration.Templates)return;// Register templates with pict (only once)
537
+ if(!this._TemplatesRegistered){var tmpTemplates=this._Configuration.Templates;for(var i=0;i<tmpTemplates.length;i++){if(tmpTemplates[i].Hash&&tmpTemplates[i].Template){this.fable.TemplateProvider.addTemplate(tmpTemplates[i].Hash,tmpTemplates[i].Template);}}this._TemplatesRegistered=true;}this._renderTemplate();}},{key:"marshalToPanel",value:function marshalToPanel(pNodeData){_superPropGet(FlowCardPropertiesPanelTemplate,"marshalToPanel",this,3)([pNodeData]);this._renderTemplate();}},{key:"_renderTemplate",value:function _renderTemplate(){if(!this._ContentContainer||!this._NodeData)return;var tmpTemplateHash=this._Configuration.TemplateHash;if(!tmpTemplateHash)return;var tmpRecord=this._NodeData;var tmpHTML=this.fable.parseTemplateByHash(tmpTemplateHash,tmpRecord,null,[tmpRecord]);this._ContentContainer.innerHTML=tmpHTML;}}]);}(libPictFlowCardPropertiesPanel);module.exports=FlowCardPropertiesPanelTemplate;module.exports.default_configuration=Object.assign({},libPictFlowCardPropertiesPanel.default_configuration,{PanelType:'Template',Configuration:{Templates:[],TemplateHash:''}});},{"../PictFlowCardPropertiesPanel.js":11}],15:[function(require,module,exports){var libPictFlowCardPropertiesPanel=require('../PictFlowCardPropertiesPanel.js');/**
538
+ * FlowCardPropertiesPanel-View
539
+ *
540
+ * Renders an existing registered pict-view into the panel body.
541
+ * The view's destination is temporarily overridden to render inside
542
+ * the panel container.
543
+ *
544
+ * Configuration:
545
+ * {
546
+ * PanelType: 'View',
547
+ * Configuration: {
548
+ * ViewHash: 'MyCustomViewIdentifier'
549
+ * }
550
+ * }
551
+ */var FlowCardPropertiesPanelView=/*#__PURE__*/function(_libPictFlowCardPrope4){function FlowCardPropertiesPanelView(pFable,pOptions,pServiceHash){var _this18;_classCallCheck(this,FlowCardPropertiesPanelView);_this18=_callSuper(this,FlowCardPropertiesPanelView,[pFable,pOptions,pServiceHash]);_this18.serviceType='PictFlowCardPropertiesPanel-View';_this18._OriginalDestination=null;_this18._ViewInstance=null;return _this18;}/**
552
+ * Render the referenced pict-view into the panel body.
553
+ */_inherits(FlowCardPropertiesPanelView,_libPictFlowCardPrope4);return _createClass(FlowCardPropertiesPanelView,[{key:"render",value:function render(pContainer,pNodeData){_superPropGet(FlowCardPropertiesPanelView,"render",this,3)([pContainer,pNodeData]);if(!this._Configuration||!this._Configuration.ViewHash){pContainer.innerHTML='<em>No ViewHash configured</em>';return;}var tmpViewHash=this._Configuration.ViewHash;// Create a unique container ID
554
+ var tmpContainerID="pict-flow-panel-view-".concat(pNodeData.Hash);pContainer.innerHTML="<div id=\"".concat(tmpContainerID,"\"></div>");try{// Look up the view in the pict instance
555
+ var tmpPict=this.pict||this.fable;if(tmpPict.views&&tmpPict.views[tmpViewHash]){this._ViewInstance=tmpPict.views[tmpViewHash];// Save original destination
556
+ this._OriginalDestination=this._ViewInstance.options.DefaultDestinationAddress;// Override destination to our panel container
557
+ this._ViewInstance.options.DefaultDestinationAddress="#".concat(tmpContainerID);if(typeof this._ViewInstance.render==='function'){this._ViewInstance.render();}}else{pContainer.innerHTML="<em>View \"".concat(tmpViewHash,"\" not found</em>");}}catch(pError){this.log.warn("FlowCardPropertiesPanel-View render error: ".concat(pError.message));pContainer.innerHTML="<em>View render error: ".concat(pError.message,"</em>");}}},{key:"marshalFromPanel",value:function marshalFromPanel(pNodeData){if(this._ViewInstance&&typeof this._ViewInstance.marshalFromView==='function'){this._ViewInstance.marshalFromView();}}},{key:"destroy",value:function destroy(){// Restore original destination
558
+ if(this._ViewInstance&&this._OriginalDestination){this._ViewInstance.options.DefaultDestinationAddress=this._OriginalDestination;}this._ViewInstance=null;this._OriginalDestination=null;_superPropGet(FlowCardPropertiesPanelView,"destroy",this,3)([]);}}]);}(libPictFlowCardPropertiesPanel);module.exports=FlowCardPropertiesPanelView;module.exports.default_configuration=Object.assign({},libPictFlowCardPropertiesPanel.default_configuration,{PanelType:'View',Configuration:{ViewHash:''}});},{"../PictFlowCardPropertiesPanel.js":11}],16:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
559
+ * PictProvider-Flow-CSS
560
+ *
561
+ * Centralized CSS provider for the flow diagram.
562
+ * All flow-related CSS is organized into domain-specific getter methods,
563
+ * providing a single source of truth and enabling future theming.
564
+ */var _ProviderConfiguration={ProviderIdentifier:'PictProviderFlowCSS'};var PictProviderFlowCSS=/*#__PURE__*/function(_libFableServiceProvi3){function PictProviderFlowCSS(pFable,pOptions,pServiceHash){var _this19;_classCallCheck(this,PictProviderFlowCSS);var tmpOptions=Object.assign({},_ProviderConfiguration,pOptions);_this19=_callSuper(this,PictProviderFlowCSS,[pFable,tmpOptions,pServiceHash]);_this19.serviceType='PictProviderFlowCSS';_this19._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this19;}// ── Container ──────────────────────────────────────────────────────────
565
+ /**
566
+ * CSS for the flow container, SVG container, panning/connecting cursors, and grid pattern.
567
+ * @returns {string}
568
+ */_inherits(PictProviderFlowCSS,_libFableServiceProvi3);return _createClass(PictProviderFlowCSS,[{key:"getContainerCSS",value:function getContainerCSS(){return/*css*/"\n\t\t.pict-flow-container {\n\t\t\t/* \u2500\u2500 Design Tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\t\t\t Override these custom properties to theme the flow diagram.\n\t\t\t Node-type classes (.pict-flow-node-{type}) can scope-override\n\t\t\t any variable for per-type variation. */\n\n\t\t\t/* Text */\n\t\t\t--pf-text-primary: #2c3e50;\n\t\t\t--pf-text-heading: #1a252f;\n\t\t\t--pf-text-secondary: #7f8c8d;\n\t\t\t--pf-text-tertiary: #8e99a4;\n\t\t\t--pf-text-placeholder: #95a5a6;\n\n\t\t\t/* Node */\n\t\t\t--pf-node-body-fill: #ffffff;\n\t\t\t--pf-node-body-stroke: #d0d4d8;\n\t\t\t--pf-node-body-stroke-hover: #b0b8c0;\n\t\t\t--pf-node-body-stroke-width: 1;\n\t\t\t--pf-node-body-radius: 8px;\n\t\t\t--pf-node-shadow: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.10));\n\t\t\t--pf-node-shadow-hover: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.15));\n\t\t\t--pf-node-shadow-selected: drop-shadow(0 2px 8px rgba(52, 152, 219, 0.25));\n\t\t\t--pf-node-shadow-dragging: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.20));\n\t\t\t--pf-node-title-fill: #ffffff;\n\t\t\t--pf-node-title-size: 11.5px;\n\t\t\t--pf-node-title-weight: 600;\n\t\t\t--pf-node-title-bar-color: #2c3e50;\n\t\t\t--pf-node-type-label-fill: #a0a8b0;\n\t\t\t--pf-node-selected-stroke: #3498db;\n\n\t\t\t/* Node Variants */\n\t\t\t--pf-node-start-fill: #eafaf1;\n\t\t\t--pf-node-start-stroke: #27ae60;\n\t\t\t--pf-node-end-fill: #e8f8f5;\n\t\t\t--pf-node-end-stroke: #1abc9c;\n\t\t\t--pf-node-halt-fill: #fdedec;\n\t\t\t--pf-node-halt-stroke: #e74c3c;\n\t\t\t--pf-node-decision-fill: #fff9e6;\n\t\t\t--pf-node-decision-stroke: #f39c12;\n\n\t\t\t/* Ports */\n\t\t\t--pf-port-input-fill: #3498db;\n\t\t\t--pf-port-output-fill: #2ecc71;\n\t\t\t--pf-port-stroke: #ffffff;\n\t\t\t--pf-port-stroke-width: 2;\n\t\t\t--pf-port-label-bg: rgba(255, 253, 240, 0.5);\n\t\t\t--pf-port-label-text: #2c3e50;\n\n\t\t\t/* Port Type Colors */\n\t\t\t--pf-port-event-in-fill: #3498db;\n\t\t\t--pf-port-event-out-fill: #2ecc71;\n\t\t\t--pf-port-setting-fill: #e67e22;\n\t\t\t--pf-port-value-fill: #f1c40f;\n\t\t\t--pf-port-error-fill: #e74c3c;\n\n\t\t\t/* Connection Type Colors (match source port) */\n\t\t\t--pf-connection-event-in-stroke: #3498db;\n\t\t\t--pf-connection-event-out-stroke: #2ecc71;\n\t\t\t--pf-connection-setting-stroke: #e67e22;\n\t\t\t--pf-connection-value-stroke: #f1c40f;\n\t\t\t--pf-connection-error-stroke: #e74c3c;\n\n\t\t\t/* Connections */\n\t\t\t--pf-connection-stroke: #95a5a6;\n\t\t\t--pf-connection-stroke-hover: #7f8c8d;\n\t\t\t--pf-connection-selected-stroke: #3498db;\n\n\t\t\t/* Panels */\n\t\t\t--pf-panel-bg: #ffffff;\n\t\t\t--pf-panel-border: #d0d4d8;\n\t\t\t--pf-panel-radius: 8px;\n\t\t\t--pf-panel-shadow: 0 4px 12px rgba(0,0,0,0.10), 0 1px 3px rgba(0,0,0,0.06);\n\t\t\t--pf-panel-titlebar-bg: #f7f8fa;\n\t\t\t--pf-panel-titlebar-border: #e8eaed;\n\t\t\t--pf-panel-title-color: #2c3e50;\n\n\t\t\t/* Tabs */\n\t\t\t--pf-tab-text: #8e99a4;\n\t\t\t--pf-tab-text-hover: #5a6a7a;\n\t\t\t--pf-tab-active-border: var(--pf-node-selected-stroke);\n\t\t\t--pf-resize-handle-hover: #e0e3e6;\n\n\t\t\t/* Forms & Inputs */\n\t\t\t--pf-input-border: #d5d8dc;\n\t\t\t--pf-input-border-focus: #3498db;\n\t\t\t--pf-divider-light: #ecf0f1;\n\t\t\t--pf-divider-medium: #e8eaed;\n\n\t\t\t/* Buttons */\n\t\t\t--pf-button-border: #bdc3c7;\n\t\t\t--pf-button-hover-border: #95a5a6;\n\t\t\t--pf-button-hover-bg: #ecf0f1;\n\t\t\t--pf-button-active-bg: #d5dbdb;\n\t\t\t--pf-button-danger-text: #e74c3c;\n\t\t\t--pf-button-danger-hover-bg: #fdedec;\n\t\t\t--pf-button-close-color: #b0b8c0;\n\n\t\t\t/* Badges */\n\t\t\t--pf-badge-category-bg: #f0f2f4;\n\t\t\t--pf-badge-category-text: #6b7b8d;\n\t\t\t--pf-badge-code-bg: #eaf2f8;\n\t\t\t--pf-badge-code-text: #2980b9;\n\n\t\t\t/* Info Panel */\n\t\t\t--pf-port-item-bg: #f8f9fa;\n\n\t\t\t/* Toolbar */\n\t\t\t--pf-toolbar-bg: #ffffff;\n\t\t\t--pf-toolbar-border: #e0e0e0;\n\n\t\t\t/* Palette Cards */\n\t\t\t--pf-card-border: #d5d8dc;\n\t\t\t--pf-card-hover-bg: #eaf2f8;\n\t\t\t--pf-card-hover-shadow: 0 1px 3px rgba(52, 152, 219, 0.15);\n\n\t\t\t/* Canvas */\n\t\t\t--pf-canvas-bg: #fafafa;\n\t\t\t--pf-grid-stroke: #e8e8e8;\n\n\t\t\tposition: relative;\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tmin-height: 400px;\n\t\t\toverflow: hidden;\n\t\t\tbackground-color: var(--pf-canvas-bg);\n\t\t\tborder: 1px solid var(--pf-toolbar-border);\n\t\t\tborder-radius: 4px;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t}\n\t\t.pict-flow-svg-container {\n\t\t\tflex: 1;\n\t\t\tmin-height: 0;\n\t\t\tposition: relative;\n\t\t}\n\t\t.pict-flow-svg {\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tcursor: grab;\n\t\t\tuser-select: none;\n\t\t\t-webkit-user-select: none;\n\t\t}\n\t\t.pict-flow-svg.panning {\n\t\t\tcursor: grabbing;\n\t\t}\n\t\t.pict-flow-svg.connecting {\n\t\t\tcursor: crosshair;\n\t\t}\n\t\t.pict-flow-grid-pattern line {\n\t\t\tstroke: var(--pf-grid-stroke);\n\t\t\tstroke-width: 0.5;\n\t\t}\n\t\t";}// ── Nodes ──────────────────────────────────────────────────────────────
569
+ /**
570
+ * CSS for base node styling: body, hover/selected/dragging states, title bar, title text, type label.
571
+ * @returns {string}
572
+ */},{key:"getNodeCSS",value:function getNodeCSS(){return/*css*/"\n\t\t.pict-flow-node {\n\t\t\tcursor: pointer;\n\t\t\tfilter: var(--pf-node-shadow);\n\t\t\ttransition: filter 0.2s;\n\t\t}\n\t\t.pict-flow-node:hover {\n\t\t\tfilter: var(--pf-node-shadow-hover);\n\t\t}\n\t\t.pict-flow-node:hover .pict-flow-node-body {\n\t\t\tstroke: var(--pf-node-body-stroke-hover);\n\t\t\tstroke-width: 1.5;\n\t\t}\n\t\t.pict-flow-node.selected {\n\t\t\tfilter: var(--pf-node-shadow-selected);\n\t\t}\n\t\t.pict-flow-node.selected .pict-flow-node-body {\n\t\t\tstroke: var(--pf-node-selected-stroke);\n\t\t\tstroke-width: 2;\n\t\t}\n\t\t.pict-flow-node.dragging {\n\t\t\topacity: 0.9;\n\t\t\tcursor: grabbing;\n\t\t\tfilter: var(--pf-node-shadow-dragging);\n\t\t}\n\t\t.pict-flow-node-body {\n\t\t\tfill: var(--pf-node-body-fill);\n\t\t\tstroke: var(--pf-node-body-stroke);\n\t\t\tstroke-width: var(--pf-node-body-stroke-width);\n\t\t\trx: var(--pf-node-body-radius);\n\t\t\try: var(--pf-node-body-radius);\n\t\t\ttransition: stroke 0.2s, stroke-width 0.2s;\n\t\t}\n\t\t.pict-flow-node-title-bar {\n\t\t\tfill: var(--pf-node-title-bar-color);\n\t\t\trx: var(--pf-node-body-radius);\n\t\t\try: var(--pf-node-body-radius);\n\t\t}\n\t\t.pict-flow-node-title-bar-bottom {\n\t\t\tfill: var(--pf-node-title-bar-color);\n\t\t}\n\t\t.pict-flow-node-title {\n\t\t\tfill: var(--pf-node-title-fill);\n\t\t\tfont-size: var(--pf-node-title-size);\n\t\t\tfont-weight: var(--pf-node-title-weight);\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\t\t\tletter-spacing: 0.2px;\n\t\t\tpointer-events: none;\n\t\t}\n\t\t.pict-flow-node-type-label {\n\t\t\tfill: var(--pf-node-type-label-fill);\n\t\t\tfont-size: 9.5px;\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.3px;\n\t\t\tpointer-events: none;\n\t\t\topacity: 0;\n\t\t\ttransition: opacity 0.2s;\n\t\t}\n\t\t.pict-flow-node:hover .pict-flow-node-type-label {\n\t\t\topacity: 1;\n\t\t}\n\t\t.pict-flow-node-card-code {\n\t\t\topacity: 0;\n\t\t\ttransition: opacity 0.2s;\n\t\t}\n\t\t.pict-flow-node:hover .pict-flow-node-card-code {\n\t\t\topacity: 1;\n\t\t}\n\t\t/* Title-bar icon: invert SVG paths to white for dark title bars */\n\t\t.pict-flow-node-title-icon {\n\t\t\tfilter: brightness(0) invert(1);\n\t\t}\n\t\t";}// ── Body Content ──────────────────────────────────────────────────────
573
+ /**
574
+ * CSS for custom body content in nodes: SVG group, foreignObject, HTML container, canvas.
575
+ * @returns {string}
576
+ */},{key:"getBodyContentCSS",value:function getBodyContentCSS(){return/*css*/"\n\t\t.pict-flow-node-body-content {\n\t\t\tpointer-events: none;\n\t\t}\n\t\t.pict-flow-node-body-content-fo {\n\t\t\toverflow: hidden;\n\t\t}\n\t\t.pict-flow-node-body-content-html {\n\t\t\toverflow: hidden;\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tbox-sizing: border-box;\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\t\t\tfont-size: 11px;\n\t\t\tcolor: var(--pf-text-primary);\n\t\t\tpointer-events: auto;\n\t\t}\n\t\t.pict-flow-node-body-content-canvas {\n\t\t\tdisplay: block;\n\t\t\tpointer-events: auto;\n\t\t}\n\t\t";}// ── Node Variants ──────────────────────────────────────────────────────
577
+ /**
578
+ * CSS overrides for specific node types: start, end, halt, decision.
579
+ * @returns {string}
580
+ */},{key:"getNodeVariantCSS",value:function getNodeVariantCSS(){return/*css*/"\n\t\t.pict-flow-node-decision .pict-flow-node-body {\n\t\t\tfill: var(--pf-node-decision-fill);\n\t\t\tstroke: var(--pf-node-decision-stroke);\n\t\t\tstroke-width: 1.5;\n\t\t}\n\t\t.pict-flow-node-start .pict-flow-node-body {\n\t\t\tfill: var(--pf-node-start-fill);\n\t\t\tstroke: var(--pf-node-start-stroke);\n\t\t\tstroke-width: 1.5;\n\t\t}\n\t\t.pict-flow-node-end .pict-flow-node-body {\n\t\t\tfill: var(--pf-node-end-fill);\n\t\t\tstroke: var(--pf-node-end-stroke);\n\t\t\tstroke-width: 1.5;\n\t\t}\n\t\t.pict-flow-node-halt .pict-flow-node-body {\n\t\t\tfill: var(--pf-node-halt-fill);\n\t\t\tstroke: var(--pf-node-halt-stroke);\n\t\t\tstroke-width: 1.5;\n\t\t}\n\t\t";}// ── Ports ──────────────────────────────────────────────────────────────
581
+ /**
582
+ * CSS for port circles: input/output coloring, hover states, labels.
583
+ * @returns {string}
584
+ */},{key:"getPortCSS",value:function getPortCSS(){return/*css*/"\n\t\t.pict-flow-port {\n\t\t\tcursor: crosshair;\n\t\t\ttransition: r 0.15s, filter 0.15s;\n\t\t\tfilter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.12));\n\t\t}\n\t\t.pict-flow-port.input {\n\t\t\tfill: var(--pf-port-input-fill);\n\t\t\tstroke: var(--pf-port-stroke);\n\t\t\tstroke-width: var(--pf-port-stroke-width);\n\t\t}\n\t\t.pict-flow-port.output {\n\t\t\tfill: var(--pf-port-output-fill);\n\t\t\tstroke: var(--pf-port-stroke);\n\t\t\tstroke-width: var(--pf-port-stroke-width);\n\t\t}\n\t\t.pict-flow-port:hover {\n\t\t\tr: 7;\n\t\t\tfilter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.20));\n\t\t}\n\t\t/* Port type color overrides */\n\t\t.pict-flow-port.port-type-event-in {\n\t\t\tfill: var(--pf-port-event-in-fill);\n\t\t}\n\t\t.pict-flow-port.port-type-event-out {\n\t\t\tfill: var(--pf-port-event-out-fill);\n\t\t}\n\t\t.pict-flow-port.port-type-setting {\n\t\t\tfill: var(--pf-port-setting-fill);\n\t\t}\n\t\t.pict-flow-port.port-type-value {\n\t\t\tfill: var(--pf-port-value-fill);\n\t\t}\n\t\t.pict-flow-port.port-type-error {\n\t\t\tfill: var(--pf-port-error-fill);\n\t\t}\n\t\t.pict-flow-port-label {\n\t\t\tfont-size: 8px;\n\t\t\tfont-weight: 600;\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\t\t\tpointer-events: none;\n\t\t}\n\t\t/* Port label badge background */\n\t\t.pict-flow-port-label-bg {\n\t\t\tpointer-events: none;\n\t\t}\n\t\t/* Port labels on hover: hidden by default, revealed on node hover */\n\t\t.pict-flow-node-port-labels-hover .pict-flow-port-label,\n\t\t.pict-flow-node-port-labels-hover .pict-flow-port-label-bg {\n\t\t\topacity: 0;\n\t\t\ttransition: opacity 0.2s;\n\t\t}\n\t\t.pict-flow-node-port-labels-hover:hover .pict-flow-port-label,\n\t\t.pict-flow-node-port-labels-hover:hover .pict-flow-port-label-bg {\n\t\t\topacity: 1;\n\t\t}\n\t\t";}// ── Connections ────────────────────────────────────────────────────────
585
+ /**
586
+ * CSS for connection paths: base, hover/selected states, hitarea, drag-connection.
587
+ * @returns {string}
588
+ */},{key:"getConnectionCSS",value:function getConnectionCSS(){return/*css*/"\n\t\t.pict-flow-connection {\n\t\t\tfill: none;\n\t\t\tstroke: var(--pf-connection-stroke);\n\t\t\tstroke-width: 2;\n\t\t\tcursor: pointer;\n\t\t\ttransition: stroke 0.15s;\n\t\t}\n\t\t.pict-flow-connection:hover {\n\t\t\tstroke: var(--pf-connection-stroke-hover);\n\t\t\tstroke-width: 3;\n\t\t}\n\t\t.pict-flow-connection.selected {\n\t\t\tstroke: var(--pf-connection-selected-stroke);\n\t\t\tstroke-width: 3;\n\t\t}\n\t\t/* Connection type color overrides (based on source port type) */\n\t\t.pict-flow-connection.conn-type-event-in {\n\t\t\tstroke: var(--pf-connection-event-in-stroke);\n\t\t}\n\t\t.pict-flow-connection.conn-type-event-out {\n\t\t\tstroke: var(--pf-connection-event-out-stroke);\n\t\t}\n\t\t.pict-flow-connection.conn-type-setting {\n\t\t\tstroke: var(--pf-connection-setting-stroke);\n\t\t}\n\t\t.pict-flow-connection.conn-type-value {\n\t\t\tstroke: var(--pf-connection-value-stroke);\n\t\t}\n\t\t.pict-flow-connection.conn-type-error {\n\t\t\tstroke: var(--pf-connection-error-stroke);\n\t\t}\n\t\t.pict-flow-connection-hitarea {\n\t\t\tfill: none;\n\t\t\tstroke: transparent;\n\t\t\tstroke-width: 12;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.pict-flow-drag-connection {\n\t\t\tfill: none;\n\t\t\tstroke: var(--pf-node-selected-stroke);\n\t\t\tstroke-width: 2;\n\t\t\tstroke-dasharray: 6 3;\n\t\t\tpointer-events: none;\n\t\t}\n\t\t";}// ── Connection Handles ─────────────────────────────────────────────────
589
+ /**
590
+ * CSS for connection waypoint handles and midpoint handles.
591
+ * @returns {string}
592
+ */},{key:"getHandleCSS",value:function getHandleCSS(){return/*css*/"\n\t\t.pict-flow-connection-handle {\n\t\t\tfill: var(--pf-panel-bg);\n\t\t\tstroke: var(--pf-node-selected-stroke);\n\t\t\tstroke-width: 2;\n\t\t\tcursor: grab;\n\t\t\ttransition: r 0.15s;\n\t\t\tfilter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));\n\t\t}\n\t\t.pict-flow-connection-handle:hover {\n\t\t\tr: 8;\n\t\t\tstroke-width: 2.5;\n\t\t}\n\t\t.pict-flow-connection-handle-midpoint {\n\t\t\tfill: var(--pf-panel-bg);\n\t\t\tstroke: var(--pf-port-setting-fill);\n\t\t\tstroke-width: 2;\n\t\t\tcursor: grab;\n\t\t\ttransition: r 0.15s;\n\t\t\tfilter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));\n\t\t}\n\t\t.pict-flow-connection-handle-midpoint:hover {\n\t\t\tr: 8;\n\t\t\tstroke-width: 2.5;\n\t\t}\n\t\t";}// ── Tethers ────────────────────────────────────────────────────────────
593
+ /**
594
+ * CSS for tether lines, hitareas, handles, and midpoint handles.
595
+ * @returns {string}
596
+ */},{key:"getTetherCSS",value:function getTetherCSS(){return/*css*/"\n\t\t.pict-flow-tether-line {\n\t\t\tfill: none;\n\t\t\tstroke: var(--pf-connection-stroke);\n\t\t\tstroke-width: 1.5;\n\t\t\tstroke-dasharray: 6 4;\n\t\t\tpointer-events: visibleStroke;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.pict-flow-tether-line.selected {\n\t\t\tstroke: var(--pf-node-selected-stroke);\n\t\t\tstroke-width: 2;\n\t\t}\n\t\t.pict-flow-tether-hitarea {\n\t\t\tfill: none;\n\t\t\tstroke: transparent;\n\t\t\tstroke-width: 10;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.pict-flow-tether-handle {\n\t\t\tfill: var(--pf-panel-bg);\n\t\t\tstroke: var(--pf-node-selected-stroke);\n\t\t\tstroke-width: 2;\n\t\t\tcursor: grab;\n\t\t\ttransition: r 0.15s;\n\t\t\tfilter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));\n\t\t}\n\t\t.pict-flow-tether-handle:hover {\n\t\t\tr: 8;\n\t\t\tstroke-width: 2.5;\n\t\t}\n\t\t.pict-flow-tether-handle-midpoint {\n\t\t\tfill: var(--pf-panel-bg);\n\t\t\tstroke: var(--pf-port-setting-fill);\n\t\t\tstroke-width: 2;\n\t\t\tcursor: grab;\n\t\t\ttransition: r 0.15s;\n\t\t\tfilter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));\n\t\t}\n\t\t.pict-flow-tether-handle-midpoint:hover {\n\t\t\tr: 8;\n\t\t\tstroke-width: 2.5;\n\t\t}\n\t\t";}// ── Panels ─────────────────────────────────────────────────────────────
597
+ /**
598
+ * CSS for property panels: foreign object, panel container, titlebar, close button, body, indicator.
599
+ * @returns {string}
600
+ */},{key:"getPanelCSS",value:function getPanelCSS(){return/*css*/"\n\t\t.pict-flow-node-panel-indicator {\n\t\t\tfill: var(--pf-node-selected-stroke);\n\t\t\tstroke: none;\n\t\t\topacity: 0.6;\n\t\t\tcursor: pointer;\n\t\t\ttransition: opacity 0.15s;\n\t\t}\n\t\t.pict-flow-node-panel-indicator:hover {\n\t\t\topacity: 1.0;\n\t\t}\n\t\t.pict-flow-panel-foreign-object {\n\t\t\toverflow: visible;\n\t\t}\n\t\t.pict-flow-panel {\n\t\t\tbackground: var(--pf-panel-bg);\n\t\t\tborder: 1px solid var(--pf-panel-border);\n\t\t\tborder-radius: var(--pf-panel-radius);\n\t\t\tbox-shadow: var(--pf-panel-shadow);\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\t\t\tfont-size: 13px;\n\t\t\toverflow: hidden;\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t.pict-flow-panel-titlebar {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: space-between;\n\t\t\tpadding: 8px 12px;\n\t\t\tbackground: var(--pf-panel-titlebar-bg);\n\t\t\tborder-bottom: 1px solid var(--pf-panel-titlebar-border);\n\t\t\tcursor: grab;\n\t\t\tuser-select: none;\n\t\t\t-webkit-user-select: none;\n\t\t\tflex-shrink: 0;\n\t\t}\n\t\t.pict-flow-panel-titlebar.dragging {\n\t\t\tcursor: grabbing;\n\t\t}\n\t\t.pict-flow-panel-title-text {\n\t\t\tfont-weight: 600;\n\t\t\tfont-size: 12px;\n\t\t\tcolor: var(--pf-panel-title-color);\n\t\t\twhite-space: nowrap;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t\tletter-spacing: 0.1px;\n\t\t}\n\t\t.pict-flow-panel-close-btn {\n\t\t\tcursor: pointer;\n\t\t\tcolor: var(--pf-button-close-color);\n\t\t\tfont-size: 14px;\n\t\t\tline-height: 1;\n\t\t\tpadding: 4px;\n\t\t\tborder: none;\n\t\t\tbackground: none;\n\t\t\tborder-radius: 4px;\n\t\t\ttransition: background-color 0.15s, color 0.15s;\n\t\t}\n\t\t.pict-flow-panel-close-btn:hover {\n\t\t\tcolor: var(--pf-button-danger-text);\n\t\t\tbackground-color: rgba(231, 76, 60, 0.08);\n\t\t}\n\t\t.pict-flow-panel-content {\n\t\t\tflex: 1;\n\t\t\toverflow-y: auto;\n\t\t\tmin-height: 0;\n\t\t\tpadding: 0;\n\t\t}\n\t\t.pict-flow-panel-tab-pane {\n\t\t\tpadding: 10px 12px;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t";}// ── Info Panels ────────────────────────────────────────────────────────
601
+ /**
602
+ * CSS for the info/hover panel and all sub-elements: header, description, badges, sections, ports.
603
+ * @returns {string}
604
+ */},{key:"getInfoPanelCSS",value:function getInfoPanelCSS(){return/*css*/"\n\t\t.pict-flow-info-panel {\n\t\t\tpadding: 2px 0;\n\t\t\tfont-size: 12px;\n\t\t\tline-height: 1.5;\n\t\t\tcolor: var(--pf-text-primary);\n\t\t}\n\t\t.pict-flow-info-panel-header {\n\t\t\tfont-size: 13px;\n\t\t\tfont-weight: 600;\n\t\t\tmargin-bottom: 6px;\n\t\t\tcolor: var(--pf-text-heading);\n\t\t}\n\t\t.pict-flow-info-panel-header.with-icon {\n\t\t\tfont-size: 14px;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 6px;\n\t\t}\n\t\t.pict-flow-info-panel-description {\n\t\t\tfont-size: 11px;\n\t\t\tcolor: var(--pf-text-secondary);\n\t\t\tmargin-bottom: 10px;\n\t\t\tline-height: 1.45;\n\t\t}\n\t\t.pict-flow-info-panel-badges {\n\t\t\tmargin-bottom: 10px;\n\t\t\tdisplay: flex;\n\t\t\tflex-wrap: wrap;\n\t\t\tgap: 4px;\n\t\t}\n\t\t.pict-flow-info-panel-badge {\n\t\t\tdisplay: inline-block;\n\t\t\tpadding: 2px 8px;\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 10px;\n\t\t}\n\t\t.pict-flow-info-panel-badge.category {\n\t\t\tbackground: var(--pf-badge-category-bg);\n\t\t\tcolor: var(--pf-badge-category-text);\n\t\t}\n\t\t.pict-flow-info-panel-badge.code {\n\t\t\tbackground: var(--pf-badge-code-bg);\n\t\t\tcolor: var(--pf-badge-code-text);\n\t\t\tfont-family: \"SF Mono\", \"Fira Code\", monospace;\n\t\t}\n\t\t.pict-flow-info-panel-section {\n\t\t\tmargin-bottom: 8px;\n\t\t}\n\t\t.pict-flow-info-panel-section-title {\n\t\t\tfont-size: 10px;\n\t\t\tfont-weight: 600;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.5px;\n\t\t\tcolor: var(--pf-text-tertiary);\n\t\t\tmargin-bottom: 4px;\n\t\t\tpadding-bottom: 2px;\n\t\t\tborder-bottom: 1px solid var(--pf-divider-light);\n\t\t}\n\t\t.pict-flow-info-panel-port {\n\t\t\tpadding: 3px 8px;\n\t\t\tbackground: var(--pf-port-item-bg);\n\t\t\tmargin-bottom: 3px;\n\t\t\tfont-size: 11px;\n\t\t\tborder-radius: 3px;\n\t\t}\n\t\t.pict-flow-info-panel-port.input {\n\t\t\tborder-left: 3px solid var(--pf-port-input-fill);\n\t\t}\n\t\t.pict-flow-info-panel-port.output {\n\t\t\tborder-left: 3px solid var(--pf-port-output-fill);\n\t\t}\n\t\t/* Info panel port type color overrides */\n\t\t.pict-flow-info-panel-port.port-type-event-in {\n\t\t\tborder-left-color: var(--pf-port-event-in-fill);\n\t\t}\n\t\t.pict-flow-info-panel-port.port-type-event-out {\n\t\t\tborder-left-color: var(--pf-port-event-out-fill);\n\t\t}\n\t\t.pict-flow-info-panel-port.port-type-setting {\n\t\t\tborder-left-color: var(--pf-port-setting-fill);\n\t\t}\n\t\t.pict-flow-info-panel-port.port-type-value {\n\t\t\tborder-left-color: var(--pf-port-value-fill);\n\t\t}\n\t\t.pict-flow-info-panel-port.port-type-error {\n\t\t\tborder-left-color: var(--pf-port-error-fill);\n\t\t}\n\t\t.pict-flow-info-panel-port-constraint {\n\t\t\tcolor: var(--pf-text-tertiary);\n\t\t\tfont-size: 10px;\n\t\t}\n\t\t/* Port summary section appended below form panels */\n\t\t.pict-flow-port-summary {\n\t\t\tmargin-top: 12px;\n\t\t\tpadding-top: 8px;\n\t\t\tborder-top: 1px solid var(--pf-divider-medium);\n\t\t}\n\t\t.pict-flow-info-panel-port.event {\n\t\t\tborder-left: 3px solid var(--pf-port-event-in-fill);\n\t\t}\n\t\t.pict-flow-info-panel-port.value {\n\t\t\tborder-left: 3px solid var(--pf-port-value-fill);\n\t\t}\n\t\t";}// ── Node Properties Editor ────────────────────────────────────────────
605
+ /**
606
+ * CSS for the node properties editor fields used in the Appearance tab.
607
+ * @returns {string}
608
+ */},{key:"getNodePropsEditorCSS",value:function getNodePropsEditorCSS(){return/*css*/"\n\t\t.pict-flow-node-props-fields {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tgap: 6px;\n\t\t}\n\t\t.pict-flow-node-props-field {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 8px;\n\t\t}\n\t\t.pict-flow-node-props-label {\n\t\t\tfont-size: 11px;\n\t\t\tcolor: var(--pf-text-secondary);\n\t\t\tmin-width: 72px;\n\t\t\tflex-shrink: 0;\n\t\t}\n\t\t.pict-flow-node-props-input {\n\t\t\tflex: 1;\n\t\t\tpadding: 3px 6px;\n\t\t\tborder: 1px solid var(--pf-input-border);\n\t\t\tborder-radius: 3px;\n\t\t\tfont-size: 11px;\n\t\t\toutline: none;\n\t\t\tbox-sizing: border-box;\n\t\t\tmin-width: 0;\n\t\t}\n\t\t.pict-flow-node-props-input:focus {\n\t\t\tborder-color: var(--pf-input-border-focus);\n\t\t}\n\t\t.pict-flow-node-props-color {\n\t\t\twidth: 28px;\n\t\t\theight: 24px;\n\t\t\tpadding: 1px;\n\t\t\tcursor: pointer;\n\t\t\tflex: 0 0 28px;\n\t\t}\n\t\t";}// ── Panel Tabs & Resize ───────────────────────────────────────────────
609
+ /**
610
+ * CSS for the tab bar, tab panes, resize handle, and help content.
611
+ * @returns {string}
612
+ */},{key:"getPanelTabsCSS",value:function getPanelTabsCSS(){return/*css*/"\n\t\t.pict-flow-panel-resize-handle {\n\t\t\theight: 6px;\n\t\t\tcursor: ns-resize;\n\t\t\tbackground: transparent;\n\t\t\tflex-shrink: 0;\n\t\t\ttransition: background-color 0.15s;\n\t\t\tborder-top: 1px solid var(--pf-panel-titlebar-border);\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t}\n\t\t.pict-flow-panel-resize-handle::after {\n\t\t\tcontent: '';\n\t\t\twidth: 24px;\n\t\t\theight: 2px;\n\t\t\tborder-radius: 1px;\n\t\t\tbackground: var(--pf-resize-handle-hover);\n\t\t\ttransition: background-color 0.15s, width 0.15s;\n\t\t}\n\t\t.pict-flow-panel-resize-handle:hover::after {\n\t\t\tbackground: var(--pf-button-hover-border);\n\t\t\twidth: 32px;\n\t\t}\n\t\t.pict-flow-panel-tabbar {\n\t\t\tdisplay: flex;\n\t\t\tflex-shrink: 0;\n\t\t\tborder-top: 1px solid var(--pf-panel-titlebar-border);\n\t\t\tbackground: var(--pf-panel-titlebar-bg);\n\t\t}\n\t\t.pict-flow-panel-tab {\n\t\t\tflex: 1;\n\t\t\tpadding: 5px 8px;\n\t\t\tfont-size: 11px;\n\t\t\ttext-align: center;\n\t\t\tcursor: pointer;\n\t\t\tcolor: var(--pf-tab-text);\n\t\t\tborder-top: 2px solid transparent;\n\t\t\ttransition: color 0.15s, border-top-color 0.15s;\n\t\t\tuser-select: none;\n\t\t\t-webkit-user-select: none;\n\t\t}\n\t\t.pict-flow-panel-tab:hover {\n\t\t\tcolor: var(--pf-tab-text-hover);\n\t\t}\n\t\t.pict-flow-panel-tab.active {\n\t\t\tborder-top-color: var(--pf-node-selected-stroke);\n\t\t\tcolor: var(--pf-panel-title-color);\n\t\t\tfont-weight: 600;\n\t\t}\n\t\t.pict-flow-panel-help-content {\n\t\t\tfont-size: 12px;\n\t\t\tline-height: 1.5;\n\t\t\tcolor: var(--pf-text-primary);\n\t\t}\n\t\t.pict-flow-panel-help-content p {\n\t\t\tmargin: 0 0 8px 0;\n\t\t}\n\t\t";}// ── Fullscreen ─────────────────────────────────────────────────────────
613
+ /**
614
+ * CSS for fullscreen mode.
615
+ * @returns {string}
616
+ */},{key:"getFullscreenCSS",value:function getFullscreenCSS(){return/*css*/"\n\t\t.pict-flow-fullscreen {\n\t\t\tposition: fixed;\n\t\t\ttop: 0;\n\t\t\tleft: 0;\n\t\t\twidth: 100vw;\n\t\t\theight: 100vh;\n\t\t\tz-index: 9999;\n\t\t\tborder-radius: 0;\n\t\t\tborder: none;\n\t\t\tmin-height: 100vh;\n\t\t}\n\t\t.pict-flow-fullscreen .pict-flow-svg {\n\t\t\tmin-height: calc(100vh - 50px);\n\t\t}\n\t\t";}// ── Toolbar ────────────────────────────────────────────────────────────
617
+ /**
618
+ * CSS for the toolbar: buttons, groups, labels, selects.
619
+ * @returns {string}
620
+ */},{key:"getToolbarCSS",value:function getToolbarCSS(){return/*css*/"\n\t\t.pict-flow-toolbar {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.5em;\n\t\t\tpadding: 0.5em 0.75em;\n\t\t\tbackground-color: var(--pf-toolbar-bg);\n\t\t\tborder-bottom: 1px solid var(--pf-toolbar-border);\n\t\t\tflex-wrap: wrap;\n\t\t}\n\t\t.pict-flow-toolbar-group {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.25em;\n\t\t\tpadding-right: 0.75em;\n\t\t\tborder-right: 1px solid var(--pf-toolbar-border);\n\t\t}\n\t\t.pict-flow-toolbar-group:last-child {\n\t\t\tborder-right: none;\n\t\t\tpadding-right: 0;\n\t\t}\n\t\t.pict-flow-toolbar-btn {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tgap: 0.35em;\n\t\t\tpadding: 0.35em 0.65em;\n\t\t\tborder: 1px solid var(--pf-button-border);\n\t\t\tborder-radius: 4px;\n\t\t\tbackground-color: var(--pf-toolbar-bg);\n\t\t\tcolor: var(--pf-text-primary);\n\t\t\tfont-size: 0.85em;\n\t\t\tcursor: pointer;\n\t\t\ttransition: background-color 0.15s, border-color 0.15s;\n\t\t\tuser-select: none;\n\t\t\t-webkit-user-select: none;\n\t\t}\n\t\t.pict-flow-toolbar-btn:focus {\n\t\t\toutline: none;\n\t\t}\n\t\t.pict-flow-toolbar-btn:hover {\n\t\t\tbackground-color: var(--pf-button-hover-bg);\n\t\t\tborder-color: var(--pf-button-hover-border);\n\t\t}\n\t\t.pict-flow-toolbar-btn:active {\n\t\t\tbackground-color: var(--pf-button-active-bg);\n\t\t}\n\t\t.pict-flow-toolbar-btn-icon {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.pict-flow-toolbar-btn-icon svg {\n\t\t\tdisplay: block;\n\t\t}\n\t\t.pict-flow-toolbar-btn-text {\n\t\t\twhite-space: nowrap;\n\t\t}\n\t\t.pict-flow-toolbar-btn-chevron {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tmargin-left: 0.15em;\n\t\t}\n\t\t.pict-flow-toolbar-right {\n\t\t\tmargin-left: auto;\n\t\t\tborder-right: none;\n\t\t\tpadding-right: 0;\n\t\t}\n\t\t.pict-flow-toolbar-label {\n\t\t\tfont-size: 0.8em;\n\t\t\tcolor: var(--pf-text-secondary);\n\t\t\tmargin-right: 0.25em;\n\t\t}\n\t\t.pict-flow-toolbar-select {\n\t\t\tpadding: 0.3em 0.5em;\n\t\t\tborder: 1px solid var(--pf-button-border);\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 0.85em;\n\t\t\tbackground-color: var(--pf-toolbar-bg);\n\t\t\tcolor: var(--pf-text-primary);\n\t\t}\n\t\t";}// ── Card Palette ───────────────────────────────────────────────────────
621
+ /**
622
+ * CSS for the card palette: toggle, body, categories, cards, swatches.
623
+ * @returns {string}
624
+ */},{key:"getPaletteCSS",value:function getPaletteCSS(){return/*css*/"\n\t\t.pict-flow-palette-category {\n\t\t\tmargin-bottom: 0.5em;\n\t\t}\n\t\t.pict-flow-palette-category:last-child {\n\t\t\tmargin-bottom: 0;\n\t\t}\n\t\t.pict-flow-palette-category-label {\n\t\t\tfont-size: 0.7em;\n\t\t\tfont-weight: 700;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.05em;\n\t\t\tcolor: var(--pf-text-placeholder);\n\t\t\tmargin-bottom: 0.35em;\n\t\t\tpadding-bottom: 0.2em;\n\t\t\tborder-bottom: 1px solid var(--pf-divider-light);\n\t\t}\n\t\t.pict-flow-palette-cards {\n\t\t\tdisplay: flex;\n\t\t\tflex-wrap: wrap;\n\t\t\tgap: 0.35em;\n\t\t}\n\t\t.pict-flow-palette-card {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.35em;\n\t\t\tpadding: 0.35em 0.6em;\n\t\t\tborder: 1px solid var(--pf-card-border);\n\t\t\tborder-radius: 4px;\n\t\t\tbackground-color: var(--pf-panel-bg);\n\t\t\tfont-size: 0.8em;\n\t\t\tcursor: pointer;\n\t\t\ttransition: background-color 0.15s, border-color 0.15s, box-shadow 0.15s;\n\t\t\tuser-select: none;\n\t\t\t-webkit-user-select: none;\n\t\t\tposition: relative;\n\t\t}\n\t\t.pict-flow-palette-card:hover {\n\t\t\tbackground-color: var(--pf-card-hover-bg);\n\t\t\tborder-color: var(--pf-node-selected-stroke);\n\t\t\tbox-shadow: var(--pf-card-hover-shadow);\n\t\t}\n\t\t.pict-flow-palette-card.disabled {\n\t\t\topacity: 0.45;\n\t\t\tpointer-events: none;\n\t\t\tcursor: default;\n\t\t}\n\t\t.pict-flow-palette-card-icon {\n\t\t\tfont-size: 1.1em;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.pict-flow-palette-card-swatch {\n\t\t\twidth: 10px;\n\t\t\theight: 10px;\n\t\t\tborder-radius: 2px;\n\t\t\tflex-shrink: 0;\n\t\t}\n\t\t.pict-flow-palette-card-title {\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--pf-text-primary);\n\t\t\twhite-space: nowrap;\n\t\t}\n\t\t.pict-flow-palette-card-code {\n\t\t\tfont-size: 0.8em;\n\t\t\tcolor: var(--pf-text-placeholder);\n\t\t\tfont-family: monospace;\n\t\t}\n\t\t.pict-flow-toolbar-select.layout-select {\n\t\t\tmin-width: 120px;\n\t\t\tmax-width: 200px;\n\t\t}\n\t\t";}// ── Popups ────────────────────────────────────────────────────────────
625
+ /**
626
+ * CSS for toolbar dropdown popups (Add Node, Cards, Layout).
627
+ * @returns {string}
628
+ */},{key:"getPopupCSS",value:function getPopupCSS(){return/*css*/"\n\t\t.pict-flow-toolbar-popup-anchor {\n\t\t\tposition: relative;\n\t\t}\n\t\t.pict-flow-toolbar-popup {\n\t\t\tposition: absolute;\n\t\t\tz-index: 1000;\n\t\t\tbackground: var(--pf-panel-bg);\n\t\t\tborder: 1px solid var(--pf-card-border);\n\t\t\tborder-radius: 6px;\n\t\t\tbox-shadow: 0 4px 16px rgba(0,0,0,0.12);\n\t\t\tmin-width: 240px;\n\t\t\tmax-height: 340px;\n\t\t\toverflow-y: auto;\n\t\t\tpadding: 0.35em 0;\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\t\t\tfont-size: 13px;\n\t\t}\n\t\t.pict-flow-popup-search-wrapper {\n\t\t\tposition: relative;\n\t\t\tpadding: 0.4em 0.5em;\n\t\t\tborder-bottom: 1px solid var(--pf-divider-light);\n\t\t}\n\t\t.pict-flow-popup-search-icon {\n\t\t\tposition: absolute;\n\t\t\tleft: 0.85em;\n\t\t\ttop: 50%;\n\t\t\ttransform: translateY(-50%);\n\t\t\tpointer-events: none;\n\t\t\tline-height: 1;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t}\n\t\t.pict-flow-popup-search {\n\t\t\twidth: 100%;\n\t\t\tpadding: 0.4em 0.5em 0.4em 2em;\n\t\t\tborder: 1px solid var(--pf-input-border);\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 0.9em;\n\t\t\toutline: none;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t.pict-flow-popup-search:focus {\n\t\t\tborder-color: var(--pf-input-border-focus);\n\t\t}\n\t\t.pict-flow-popup-list-item {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.5em;\n\t\t\tpadding: 0.45em 0.75em;\n\t\t\tcursor: pointer;\n\t\t\ttransition: background-color 0.1s;\n\t\t}\n\t\t.pict-flow-popup-list-item:hover {\n\t\t\tbackground-color: var(--pf-card-hover-bg);\n\t\t}\n\t\t.pict-flow-popup-list-item-icon {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tflex-shrink: 0;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.pict-flow-popup-list-item-label {\n\t\t\tflex: 1;\n\t\t\tcolor: var(--pf-text-primary);\n\t\t\tfont-weight: 500;\n\t\t}\n\t\t.pict-flow-popup-list-item-code {\n\t\t\tfont-size: 0.8em;\n\t\t\tcolor: var(--pf-text-placeholder);\n\t\t\tfont-family: monospace;\n\t\t\tbackground: var(--pf-badge-category-bg);\n\t\t\tpadding: 0.1em 0.4em;\n\t\t\tborder-radius: 3px;\n\t\t}\n\t\t.pict-flow-popup-divider {\n\t\t\theight: 1px;\n\t\t\tbackground: var(--pf-divider-light);\n\t\t\tmargin: 0.25em 0;\n\t\t}\n\t\t.pict-flow-popup-list-empty {\n\t\t\ttext-align: center;\n\t\t\tcolor: var(--pf-text-placeholder);\n\t\t\tpadding: 1.5em 0.75em;\n\t\t\tfont-size: 0.9em;\n\t\t}\n\t\t.pict-flow-popup-layout-save {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.5em;\n\t\t\tpadding: 0.45em 0.75em;\n\t\t\tcursor: pointer;\n\t\t\ttransition: background-color 0.1s;\n\t\t\tcolor: var(--pf-text-primary);\n\t\t\tfont-weight: 500;\n\t\t}\n\t\t.pict-flow-popup-layout-save:hover {\n\t\t\tbackground-color: var(--pf-card-hover-bg);\n\t\t}\n\t\t.pict-flow-popup-layout-save-icon {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tflex-shrink: 0;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.pict-flow-popup-layout-save-input-row {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.35em;\n\t\t\tpadding: 0.35em 0.5em;\n\t\t}\n\t\t.pict-flow-popup-layout-save-input {\n\t\t\tflex: 1;\n\t\t\tpadding: 0.35em 0.5em;\n\t\t\tborder: 1px solid var(--pf-input-border);\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 0.9em;\n\t\t\toutline: none;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t.pict-flow-popup-layout-save-input:focus {\n\t\t\tborder-color: var(--pf-input-border-focus);\n\t\t}\n\t\t.pict-flow-popup-layout-save-confirm {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\twidth: 28px;\n\t\t\theight: 28px;\n\t\t\tborder: 1px solid var(--pf-input-border);\n\t\t\tborder-radius: 4px;\n\t\t\tbackground: var(--pf-panel-bg);\n\t\t\tcursor: pointer;\n\t\t\tflex-shrink: 0;\n\t\t\ttransition: background-color 0.15s, border-color 0.15s;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.pict-flow-popup-layout-save-confirm:hover {\n\t\t\tbackground-color: var(--pf-card-hover-bg);\n\t\t\tborder-color: var(--pf-input-border-focus);\n\t\t}\n\t\t.pict-flow-popup-layout-row {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tpadding: 0.45em 0.75em;\n\t\t\tcursor: pointer;\n\t\t\ttransition: background-color 0.1s;\n\t\t}\n\t\t.pict-flow-popup-layout-row:hover {\n\t\t\tbackground-color: var(--pf-card-hover-bg);\n\t\t}\n\t\t.pict-flow-popup-layout-name {\n\t\t\tflex: 1;\n\t\t\tcolor: var(--pf-text-primary);\n\t\t}\n\t\t.pict-flow-popup-layout-delete {\n\t\t\tdisplay: none;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tborder: none;\n\t\t\tbackground: none;\n\t\t\tcolor: var(--pf-button-danger-text);\n\t\t\tcursor: pointer;\n\t\t\tpadding: 2px 4px;\n\t\t\tborder-radius: 3px;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.pict-flow-popup-layout-row:hover .pict-flow-popup-layout-delete {\n\t\t\tdisplay: inline-flex;\n\t\t}\n\t\t.pict-flow-popup-layout-delete:hover {\n\t\t\tbackground-color: var(--pf-button-danger-hover-bg);\n\t\t}\n\t\t.pict-flow-popup-settings-section {\n\t\t\tpadding: 0.5em 0.75em;\n\t\t}\n\t\t.pict-flow-popup-settings-label {\n\t\t\tdisplay: block;\n\t\t\tfont-size: 0.8em;\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--pf-text-secondary);\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.05em;\n\t\t\tmargin-bottom: 0.35em;\n\t\t}\n\t\t.pict-flow-popup-settings-select {\n\t\t\twidth: 100%;\n\t\t\tpadding: 0.4em 0.5em;\n\t\t\tborder: 1px solid var(--pf-input-border);\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 0.9em;\n\t\t\tbackground: var(--pf-panel-bg);\n\t\t\tcolor: var(--pf-text-primary);\n\t\t\tcursor: pointer;\n\t\t\toutline: none;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t.pict-flow-popup-settings-select:focus {\n\t\t\tborder-color: var(--pf-input-border-focus);\n\t\t}\n\t\t.pict-flow-popup-settings-slider-row {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.5em;\n\t\t}\n\t\t.pict-flow-popup-settings-slider {\n\t\t\tflex: 1;\n\t\t\t-webkit-appearance: none;\n\t\t\tappearance: none;\n\t\t\theight: 4px;\n\t\t\tbackground: var(--pf-input-border);\n\t\t\tborder-radius: 2px;\n\t\t\toutline: none;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.pict-flow-popup-settings-slider::-webkit-slider-thumb {\n\t\t\t-webkit-appearance: none;\n\t\t\tappearance: none;\n\t\t\twidth: 14px;\n\t\t\theight: 14px;\n\t\t\tbackground: var(--pf-node-selected-stroke);\n\t\t\tborder-radius: 50%;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.pict-flow-popup-settings-slider::-moz-range-thumb {\n\t\t\twidth: 14px;\n\t\t\theight: 14px;\n\t\t\tbackground: var(--pf-node-selected-stroke);\n\t\t\tborder-radius: 50%;\n\t\t\tcursor: pointer;\n\t\t\tborder: none;\n\t\t}\n\t\t.pict-flow-popup-settings-slider-value {\n\t\t\tfont-size: 0.85em;\n\t\t\tcolor: var(--pf-text-secondary);\n\t\t\tmin-width: 2.5em;\n\t\t\ttext-align: right;\n\t\t}\n\t\t";}// ── Collapsed Toolbar ─────────────────────────────────────────────────
629
+ /**
630
+ * CSS for the collapsed toolbar state (small expand button in corner).
631
+ * @returns {string}
632
+ */},{key:"getCollapsedToolbarCSS",value:function getCollapsedToolbarCSS(){return/*css*/"\n\t\t.pict-flow-toolbar-collapsed {\n\t\t\tposition: absolute;\n\t\t\ttop: 8px;\n\t\t\tright: 8px;\n\t\t\tz-index: 100;\n\t\t\tdisplay: none;\n\t\t}\n\t\t.pict-flow-toolbar-collapsed.visible {\n\t\t\tdisplay: block;\n\t\t}\n\t\t.pict-flow-toolbar-expand-btn {\n\t\t\twidth: 36px;\n\t\t\theight: 36px;\n\t\t\tborder-radius: 6px;\n\t\t\tborder: 1px solid var(--pf-card-border);\n\t\t\tbackground-color: var(--pf-toolbar-bg);\n\t\t\tbox-shadow: 0 2px 6px rgba(0,0,0,0.1);\n\t\t\tcursor: pointer;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\ttransition: background-color 0.15s, box-shadow 0.15s;\n\t\t}\n\t\t.pict-flow-toolbar-expand-btn:hover {\n\t\t\tbackground-color: var(--pf-button-hover-bg);\n\t\t\tbox-shadow: 0 2px 8px rgba(0,0,0,0.15);\n\t\t}\n\t\t";}// ── Floating Toolbar ──────────────────────────────────────────────────
633
+ /**
634
+ * CSS for the floating draggable toolbar.
635
+ * @returns {string}
636
+ */},{key:"getFloatingToolbarCSS",value:function getFloatingToolbarCSS(){return/*css*/"\n\t\t.pict-flow-floating-toolbar {\n\t\t\tposition: absolute;\n\t\t\tz-index: 100;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tgap: 2px;\n\t\t\tpadding: 4px;\n\t\t\tborder-radius: 8px;\n\t\t\tborder: 1px solid var(--pf-card-border);\n\t\t\tbackground-color: var(--pf-toolbar-bg);\n\t\t\tbox-shadow: 0 4px 16px rgba(0,0,0,0.12);\n\t\t\tpointer-events: auto;\n\t\t}\n\t\t.pict-flow-floating-grip {\n\t\t\tcursor: grab;\n\t\t\tpadding: 4px;\n\t\t\tborder-radius: 4px;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\ttransition: background-color 0.15s;\n\t\t}\n\t\t.pict-flow-floating-grip:hover {\n\t\t\tbackground-color: var(--pf-button-hover-bg);\n\t\t}\n\t\t.pict-flow-floating-grip:active {\n\t\t\tcursor: grabbing;\n\t\t}\n\t\t.pict-flow-floating-btn {\n\t\t\twidth: 32px;\n\t\t\theight: 32px;\n\t\t\tborder: none;\n\t\t\tborder-radius: 4px;\n\t\t\tbackground-color: transparent;\n\t\t\tcursor: pointer;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\ttransition: background-color 0.15s;\n\t\t}\n\t\t.pict-flow-floating-btn:focus {\n\t\t\toutline: none;\n\t\t}\n\t\t.pict-flow-floating-btn:hover {\n\t\t\tbackground-color: var(--pf-button-hover-bg);\n\t\t}\n\t\t.pict-flow-floating-separator {\n\t\t\theight: 1px;\n\t\t\tbackground-color: var(--pf-divider-light);\n\t\t\tmargin: 2px 4px;\n\t\t}\n\t\t/* Collapsed floating toolbar \u2014 grip-only draggable square */\n\t\t.pict-flow-floating-toolbar.collapsed .pict-flow-floating-btn,\n\t\t.pict-flow-floating-toolbar.collapsed .pict-flow-floating-separator {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.pict-flow-floating-toolbar.collapsed {\n\t\t\tpadding: 0;\n\t\t\tborder-radius: 6px;\n\t\t}\n\t\t.pict-flow-floating-toolbar.collapsed .pict-flow-floating-grip {\n\t\t\twidth: 32px;\n\t\t\theight: 32px;\n\t\t\tpadding: 0;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t}\n\t\t.pict-flow-floating-toolbar.collapsed .pict-flow-floating-grip span {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tline-height: 1;\n\t\t}\n\t\t";}// ── Icons ─────────────────────────────────────────────────────────────
637
+ /**
638
+ * CSS for inline SVG icons in palette cards, toolbar buttons, info panel headers, and panel close buttons.
639
+ * @returns {string}
640
+ */},{key:"getIconCSS",value:function getIconCSS(){return/*css*/"\n\t\t.pict-flow-icon-svg {\n\t\t\tpointer-events: none;\n\t\t}\n\t\t.pict-flow-palette-card-icon svg {\n\t\t\tdisplay: inline-block;\n\t\t\tvertical-align: middle;\n\t\t}\n\t\t.pict-flow-toolbar-btn-icon {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.pict-flow-toolbar-btn-icon svg {\n\t\t\tdisplay: block;\n\t\t\tvertical-align: middle;\n\t\t}\n\t\t.pict-flow-info-panel-header.with-icon svg {\n\t\t\tdisplay: inline-block;\n\t\t\tvertical-align: middle;\n\t\t\tmargin-right: 4px;\n\t\t}\n\t\t.pict-flow-panel-close-icon {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.pict-flow-panel-close-icon svg {\n\t\t\tdisplay: block;\n\t\t}\n\t\t.pict-flow-palette-toggle-arrow svg {\n\t\t\tdisplay: block;\n\t\t}\n\t\t";}// ── Bracket Node CSS ──────────────────────────────────────────────────
641
+ /**
642
+ * CSS for bracket-style node bodies used by sketch/blueprint themes.
643
+ *
644
+ * The bracket fill rects share class `.pict-flow-node-body` for fill
645
+ * inheritance, so these rules must use parent-qualified selectors
646
+ * (specificity ≥ 0,2,0) to override the base, variant, hover, and
647
+ * selected rules that set stroke and rx/ry on `.pict-flow-node-body`.
648
+ *
649
+ * @returns {string}
650
+ */},{key:"getBracketNodeCSS",value:function getBracketNodeCSS(){return/*css*/"\n\t\t/* Bracket outline path */\n\t\t.pict-flow-node-bracket {\n\t\t\tfill: none;\n\t\t\tstroke: var(--pf-node-body-stroke);\n\t\t\tstroke-width: 2;\n\t\t\tstroke-linecap: round;\n\t\t\tstroke-linejoin: round;\n\t\t}\n\t\t.pict-flow-node.selected .pict-flow-node-bracket {\n\t\t\tstroke: var(--pf-node-selected-stroke);\n\t\t\tstroke-width: 2;\n\t\t}\n\t\t.pict-flow-node:hover .pict-flow-node-bracket {\n\t\t\tstroke: var(--pf-node-body-stroke-hover);\n\t\t\tstroke-width: 1.5;\n\t\t}\n\n\t\t/* Bracket fill rects: no stroke, no rounded corners.\n\t\t Uses parent-qualified selectors to beat variant rules\n\t\t (e.g. .pict-flow-node-start .pict-flow-node-body). */\n\t\t.pict-flow-node .pict-flow-node-bracket-fill,\n\t\t.pict-flow-node .pict-flow-node-bracket-title-fill {\n\t\t\tstroke: none;\n\t\t\tstroke-width: 0;\n\t\t\trx: 0;\n\t\t\try: 0;\n\t\t}\n\t\t/* Beat hover rule: .pict-flow-node:hover .pict-flow-node-body */\n\t\t.pict-flow-node:hover .pict-flow-node-bracket-fill,\n\t\t.pict-flow-node:hover .pict-flow-node-bracket-title-fill {\n\t\t\tstroke: none;\n\t\t\tstroke-width: 0;\n\t\t}\n\t\t/* Beat selected rule: .pict-flow-node.selected .pict-flow-node-body */\n\t\t.pict-flow-node.selected .pict-flow-node-bracket-fill,\n\t\t.pict-flow-node.selected .pict-flow-node-bracket-title-fill {\n\t\t\tstroke: none;\n\t\t\tstroke-width: 0;\n\t\t}\n\t\t";}// ── Aggregate Methods ──────────────────────────────────────────────────
651
+ /**
652
+ * Concatenate all domain CSS getters into a single CSS string.
653
+ * Includes theme overrides if a theme provider is active.
654
+ * @returns {string}
655
+ */},{key:"generateCSS",value:function generateCSS(){var tmpBaseCSS=this.getContainerCSS()+this.getNodeCSS()+this.getBodyContentCSS()+this.getNodeVariantCSS()+this.getPortCSS()+this.getConnectionCSS()+this.getHandleCSS()+this.getTetherCSS()+this.getPanelCSS()+this.getInfoPanelCSS()+this.getNodePropsEditorCSS()+this.getPanelTabsCSS()+this.getBracketNodeCSS()+this.getFullscreenCSS()+this.getToolbarCSS()+this.getPaletteCSS()+this.getPopupCSS()+this.getCollapsedToolbarCSS()+this.getFloatingToolbarCSS()+this.getIconCSS();// Apply theme overrides if a theme provider exists
656
+ if(this._FlowView&&this._FlowView._ThemeProvider){var tmpTheme=this._FlowView._ThemeProvider.getActiveTheme();if(tmpTheme&&tmpTheme.CSSVariables&&Object.keys(tmpTheme.CSSVariables).length>0){var tmpOverrides='.pict-flow-container {\n';for(var tmpKey in tmpTheme.CSSVariables){tmpOverrides+='\t'+tmpKey+': '+tmpTheme.CSSVariables[tmpKey]+';\n';}tmpOverrides+='}\n';tmpBaseCSS+=tmpOverrides;}if(tmpTheme&&tmpTheme.AdditionalCSS){tmpBaseCSS+=tmpTheme.AdditionalCSS;}}return tmpBaseCSS;}/**
657
+ * Register all flow CSS with pict's CSSMap service.
658
+ * Uses correct parameter ordering: (hash, content, priority, provider).
659
+ * Removes existing CSS first to allow theme re-registration,
660
+ * then re-injects into the DOM.
661
+ */},{key:"registerCSS",value:function registerCSS(){if(this.fable&&this.fable.CSSMap){// Remove existing CSS first so we can re-register with updated theme overrides
662
+ this.fable.CSSMap.removeCSS('PictSectionFlow-CSS');this.fable.CSSMap.addCSS('PictSectionFlow-CSS',this.generateCSS(),500,'PictProviderFlowCSS');// Re-inject into the DOM to apply the updated CSS
663
+ this.fable.CSSMap.injectCSS();}else{this.log.warn('PictProviderFlowCSS: CSSMap not available; CSS not registered.');}}}]);}(libFableServiceProviderBase);module.exports=PictProviderFlowCSS;module.exports.default_configuration=_ProviderConfiguration;},{"fable-serviceproviderbase":4}],17:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');var PictProviderFlowConnectorShapes=/*#__PURE__*/function(_libFableServiceProvi4){function PictProviderFlowConnectorShapes(pFable,pOptions,pServiceHash){var _this20;_classCallCheck(this,PictProviderFlowConnectorShapes);_this20=_callSuper(this,PictProviderFlowConnectorShapes,[pFable,pOptions,pServiceHash]);_this20.serviceType='PictProviderFlowConnectorShapes';_this20._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;// Default shape configurations — each keyed by a shape identifier
664
+ // _OriginalShapes stores a deep copy for reset when switching themes.
665
+ _this20._DefaultShapes={'port':{ElementType:'circle',Attributes:{r:'5'},ClassName:'pict-flow-port'},'panel-indicator':{ElementType:'rect',Attributes:{rx:'2',ry:'2'},ClassName:'pict-flow-node-panel-indicator'},'connection-path':{ElementType:'path',Attributes:{},ClassName:'pict-flow-connection'},'connection-hitarea':{ElementType:'path',Attributes:{},ClassName:'pict-flow-connection-hitarea'},'connection-handle':{ElementType:'circle',Attributes:{r:'6'},ClassName:'pict-flow-connection-handle'},'connection-handle-midpoint':{ElementType:'circle',Attributes:{r:'6'},ClassName:'pict-flow-connection-handle-midpoint'},'drag-connection':{ElementType:'path',Attributes:{},ClassName:'pict-flow-drag-connection'},'tether-path':{ElementType:'path',Attributes:{},ClassName:'pict-flow-tether-line'},'tether-hitarea':{ElementType:'path',Attributes:{},ClassName:'pict-flow-tether-hitarea'},'tether-handle':{ElementType:'circle',Attributes:{r:'6'},ClassName:'pict-flow-tether-handle'},'tether-handle-midpoint':{ElementType:'circle',Attributes:{r:'6'},ClassName:'pict-flow-tether-handle-midpoint'},'arrowhead-connection':{MarkerWidth:'5',MarkerHeight:'7',RefX:'7.5',RefY:'3.5',Points:'0 0, 5 3.5, 0 7',Fill:'#95a5a6'},'arrowhead-connection-selected':{MarkerWidth:'5',MarkerHeight:'7',RefX:'7.5',RefY:'3.5',Points:'0 0, 5 3.5, 0 7',Fill:'#3498db'},'arrowhead-tether':{MarkerWidth:'4',MarkerHeight:'6',RefX:'6',RefY:'3',Points:'0 0, 4 3, 0 6',Fill:'#95a5a6'}};// Store a deep copy for resetting when switching themes
666
+ _this20._OriginalShapes=JSON.parse(JSON.stringify(_this20._DefaultShapes));return _this20;}// ── Theme Override Methods ─────────────────────────────────────────────
667
+ /**
668
+ * Apply theme-specific shape overrides.
669
+ * Merges the overrides into the active shape configs.
670
+ * @param {Object} pOverrides - Map of shape key to partial config
671
+ */_inherits(PictProviderFlowConnectorShapes,_libFableServiceProvi4);return _createClass(PictProviderFlowConnectorShapes,[{key:"applyThemeOverrides",value:function applyThemeOverrides(pOverrides){if(!pOverrides||_typeof(pOverrides)!=='object'){return;}for(var tmpKey in pOverrides){if(this._DefaultShapes.hasOwnProperty(tmpKey)){Object.assign(this._DefaultShapes[tmpKey],pOverrides[tmpKey]);}else{this._DefaultShapes[tmpKey]=pOverrides[tmpKey];}}}/**
672
+ * Reset all shape configs to their original defaults.
673
+ * Called before applying new theme overrides to prevent accumulation.
674
+ */},{key:"resetToDefaults",value:function resetToDefaults(){this._DefaultShapes=JSON.parse(JSON.stringify(this._OriginalShapes));}/**
675
+ * Get a shape configuration by key.
676
+ * @param {string} pShapeKey
677
+ * @returns {Object|null}
678
+ */},{key:"getShapeConfig",value:function getShapeConfig(pShapeKey){if(this._DefaultShapes.hasOwnProperty(pShapeKey)){return this._DefaultShapes[pShapeKey];}return null;}/**
679
+ * Override or add a shape configuration.
680
+ * Consumers can call this to customize connector shapes without subclassing.
681
+ * @param {string} pShapeKey
682
+ * @param {Object} pConfig
683
+ */},{key:"setShapeConfig",value:function setShapeConfig(pShapeKey,pConfig){this._DefaultShapes[pShapeKey]=pConfig;}/**
684
+ * Get all registered shape keys.
685
+ * @returns {string[]}
686
+ */},{key:"getShapeKeys",value:function getShapeKeys(){return Object.keys(this._DefaultShapes);}// ---- Factory Methods ----
687
+ /**
688
+ * Create a port SVG element.
689
+ * @param {Object} pPortData - Port data with Hash, Direction
690
+ * @param {{x: number, y: number}} pPosition - Local position within the node group
691
+ * @param {string} pNodeHash - The owning node hash
692
+ * @returns {SVGCircleElement}
693
+ */},{key:"createPortElement",value:function createPortElement(pPortData,pPosition,pNodeHash){var tmpConfig=this._DefaultShapes['port'];var tmpElement=this._FlowView._SVGHelperProvider.createSVGElement(tmpConfig.ElementType);var tmpClassName=tmpConfig.ClassName+' '+pPortData.Direction;if(pPortData.PortType){tmpClassName+=' port-type-'+pPortData.PortType;}tmpElement.setAttribute('class',tmpClassName);tmpElement.setAttribute('cx',String(pPosition.x));tmpElement.setAttribute('cy',String(pPosition.y));// Apply config attributes (r, etc.)
694
+ for(var tmpKey in tmpConfig.Attributes){tmpElement.setAttribute(tmpKey,tmpConfig.Attributes[tmpKey]);}tmpElement.setAttribute('data-port-hash',pPortData.Hash);tmpElement.setAttribute('data-node-hash',pNodeHash);tmpElement.setAttribute('data-port-direction',pPortData.Direction);if(pPortData.PortType){tmpElement.setAttribute('data-port-type',pPortData.PortType);}tmpElement.setAttribute('data-element-type','port');return tmpElement;}/**
695
+ * Create a panel indicator SVG element.
696
+ * @param {string} pNodeHash
697
+ * @param {number} pX
698
+ * @param {number} pY
699
+ * @param {number} pWidth
700
+ * @param {number} pHeight
701
+ * @returns {SVGRectElement}
702
+ */},{key:"createPanelIndicatorElement",value:function createPanelIndicatorElement(pNodeHash,pX,pY,pWidth,pHeight){var tmpConfig=this._DefaultShapes['panel-indicator'];var tmpElement=this._FlowView._SVGHelperProvider.createSVGElement(tmpConfig.ElementType);tmpElement.setAttribute('class',tmpConfig.ClassName);tmpElement.setAttribute('x',String(pX));tmpElement.setAttribute('y',String(pY));tmpElement.setAttribute('width',String(pWidth));tmpElement.setAttribute('height',String(pHeight));// Apply config attributes (rx, ry, etc.)
703
+ for(var tmpKey in tmpConfig.Attributes){tmpElement.setAttribute(tmpKey,tmpConfig.Attributes[tmpKey]);}tmpElement.setAttribute('data-node-hash',pNodeHash);tmpElement.setAttribute('data-element-type','panel-indicator');return tmpElement;}/**
704
+ * Create a visible connection path SVG element.
705
+ * @param {string} pPath - The SVG path d-string
706
+ * @param {string} pConnectionHash
707
+ * @param {boolean} pIsSelected
708
+ * @param {string} pViewIdentifier
709
+ * @returns {SVGPathElement}
710
+ */},{key:"createConnectionPathElement",value:function createConnectionPathElement(pPath,pConnectionHash,pIsSelected,pViewIdentifier){var tmpConfig=this._DefaultShapes['connection-path'];var tmpElement=this._FlowView._SVGHelperProvider.createSVGElement(tmpConfig.ElementType);tmpElement.setAttribute('class',tmpConfig.ClassName+(pIsSelected?' selected':''));tmpElement.setAttribute('d',pPath);tmpElement.setAttribute('data-connection-hash',pConnectionHash);tmpElement.setAttribute('data-element-type','connection');// Arrow marker
711
+ var tmpMarkerConfig=pIsSelected?this._DefaultShapes['arrowhead-connection-selected']:this._DefaultShapes['arrowhead-connection'];// The marker id follows the naming convention used in generateMarkerDefs
712
+ var tmpMarkerId=pIsSelected?'flow-arrowhead-selected-'+pViewIdentifier:'flow-arrowhead-'+pViewIdentifier;tmpElement.setAttribute('marker-end','url(#'+tmpMarkerId+')');return tmpElement;}/**
713
+ * Create a connection hit area SVG element (wider invisible path for click targeting).
714
+ * @param {string} pPath - The SVG path d-string
715
+ * @param {string} pConnectionHash
716
+ * @returns {SVGPathElement}
717
+ */},{key:"createConnectionHitAreaElement",value:function createConnectionHitAreaElement(pPath,pConnectionHash){var tmpConfig=this._DefaultShapes['connection-hitarea'];var tmpElement=this._FlowView._SVGHelperProvider.createSVGElement(tmpConfig.ElementType);tmpElement.setAttribute('class',tmpConfig.ClassName);tmpElement.setAttribute('d',pPath);tmpElement.setAttribute('data-connection-hash',pConnectionHash);tmpElement.setAttribute('data-element-type','connection-hitarea');return tmpElement;}/**
718
+ * Create a drag handle circle element.
719
+ * Works for both connection handles and tether handles.
720
+ * @param {string} pOwnerHash - Connection hash or panel hash
721
+ * @param {string} pHandleType - e.g. 'ortho-corner1', 'bezier-midpoint'
722
+ * @param {number} pX
723
+ * @param {number} pY
724
+ * @param {string} pShapeKey - 'connection-handle', 'connection-handle-midpoint', 'tether-handle', 'tether-handle-midpoint'
725
+ * @returns {SVGCircleElement}
726
+ */},{key:"createHandleElement",value:function createHandleElement(pOwnerHash,pHandleType,pX,pY,pShapeKey){var tmpConfig=this._DefaultShapes[pShapeKey]||this._DefaultShapes['connection-handle'];var tmpElement=this._FlowView._SVGHelperProvider.createSVGElement(tmpConfig.ElementType);tmpElement.setAttribute('class',tmpConfig.ClassName);tmpElement.setAttribute('cx',String(pX));tmpElement.setAttribute('cy',String(pY));// Apply config attributes (r, etc.)
727
+ for(var tmpKey in tmpConfig.Attributes){tmpElement.setAttribute(tmpKey,tmpConfig.Attributes[tmpKey]);}tmpElement.setAttribute('data-handle-type',pHandleType);return tmpElement;}/**
728
+ * Create a complete drag handle element with all data attributes set and
729
+ * append it to the given layer. Unifies the handle-creation logic that
730
+ * was previously duplicated in ConnectionRenderer and TetherService.
731
+ *
732
+ * @param {SVGGElement} pLayer - The SVG group to append the handle to
733
+ * @param {string} pOwnerHash - Connection hash or panel hash
734
+ * @param {string} pHandleType - e.g. 'ortho-corner1', 'bezier-midpoint'
735
+ * @param {number} pX
736
+ * @param {number} pY
737
+ * @param {string} pShapeKey - Shape config key ('connection-handle', 'tether-handle-midpoint', etc.)
738
+ * @param {string} pElementType - data-element-type value ('connection-handle' or 'tether-handle')
739
+ * @param {string} pOwnerAttrName - data attribute name for the owner ('data-connection-hash' or 'data-panel-hash')
740
+ * @returns {SVGElement}
741
+ */},{key:"createFullHandle",value:function createFullHandle(pLayer,pOwnerHash,pHandleType,pX,pY,pShapeKey,pElementType,pOwnerAttrName){var tmpHandle=this.createHandleElement(pOwnerHash,pHandleType,pX,pY,pShapeKey);tmpHandle.setAttribute('data-element-type',pElementType);tmpHandle.setAttribute(pOwnerAttrName,pOwnerHash);pLayer.appendChild(tmpHandle);return tmpHandle;}/**
742
+ * Create a temporary drag connection path element.
743
+ * @param {string} pPath - The SVG path d-string
744
+ * @returns {SVGPathElement}
745
+ */},{key:"createDragConnectionElement",value:function createDragConnectionElement(pPath){var tmpConfig=this._DefaultShapes['drag-connection'];var tmpElement=this._FlowView._SVGHelperProvider.createSVGElement(tmpConfig.ElementType);tmpElement.setAttribute('class',tmpConfig.ClassName);tmpElement.setAttribute('d',pPath);return tmpElement;}/**
746
+ * Create a visible tether path SVG element.
747
+ * @param {string} pPath - The SVG path d-string
748
+ * @param {string} pPanelHash
749
+ * @param {boolean} pIsSelected
750
+ * @param {string} pViewIdentifier
751
+ * @returns {SVGPathElement}
752
+ */},{key:"createTetherPathElement",value:function createTetherPathElement(pPath,pPanelHash,pIsSelected,pViewIdentifier){var tmpConfig=this._DefaultShapes['tether-path'];var tmpElement=this._FlowView._SVGHelperProvider.createSVGElement(tmpConfig.ElementType);tmpElement.setAttribute('class',tmpConfig.ClassName+(pIsSelected?' selected':''));tmpElement.setAttribute('d',pPath);tmpElement.setAttribute('marker-end','url(#flow-tether-arrowhead-'+pViewIdentifier+')');tmpElement.setAttribute('data-element-type','tether');tmpElement.setAttribute('data-panel-hash',pPanelHash);return tmpElement;}/**
753
+ * Create a tether hit area SVG element.
754
+ * @param {string} pPath - The SVG path d-string
755
+ * @param {string} pPanelHash
756
+ * @returns {SVGPathElement}
757
+ */},{key:"createTetherHitAreaElement",value:function createTetherHitAreaElement(pPath,pPanelHash){var tmpConfig=this._DefaultShapes['tether-hitarea'];var tmpElement=this._FlowView._SVGHelperProvider.createSVGElement(tmpConfig.ElementType);tmpElement.setAttribute('class',tmpConfig.ClassName);tmpElement.setAttribute('d',pPath);tmpElement.setAttribute('data-element-type','tether-hitarea');tmpElement.setAttribute('data-panel-hash',pPanelHash);return tmpElement;}/**
758
+ * Generate SVG marker definition markup for all arrowhead types.
759
+ * Returns raw SVG markup to be injected into the <defs> section.
760
+ * @param {string} pViewIdentifier
761
+ * @returns {string}
762
+ */},{key:"generateMarkerDefs",value:function generateMarkerDefs(pViewIdentifier){var tmpConnectionMarker=this._DefaultShapes['arrowhead-connection'];var tmpSelectedMarker=this._DefaultShapes['arrowhead-connection-selected'];var tmpTetherMarker=this._DefaultShapes['arrowhead-tether'];var tmpMarkup='';// Normal connection arrowhead (default gray)
763
+ tmpMarkup+='<marker id="flow-arrowhead-'+pViewIdentifier+'"'+' markerWidth="'+tmpConnectionMarker.MarkerWidth+'"'+' markerHeight="'+tmpConnectionMarker.MarkerHeight+'"'+' refX="'+tmpConnectionMarker.RefX+'"'+' refY="'+tmpConnectionMarker.RefY+'"'+' orient="auto" markerUnits="strokeWidth">'+'<polygon points="'+tmpConnectionMarker.Points+'" fill="'+tmpConnectionMarker.Fill+'" />'+'</marker>';// Per-port-type connection arrowheads
764
+ var tmpPortTypeColors={'event-in':'#3498db','event-out':'#2ecc71','setting':'#e67e22','value':'#f1c40f','error':'#e74c3c'};for(var tmpType in tmpPortTypeColors){tmpMarkup+='<marker id="flow-arrowhead-'+tmpType+'-'+pViewIdentifier+'"'+' markerWidth="'+tmpConnectionMarker.MarkerWidth+'"'+' markerHeight="'+tmpConnectionMarker.MarkerHeight+'"'+' refX="'+tmpConnectionMarker.RefX+'"'+' refY="'+tmpConnectionMarker.RefY+'"'+' orient="auto" markerUnits="strokeWidth">'+'<polygon points="'+tmpConnectionMarker.Points+'" fill="'+tmpPortTypeColors[tmpType]+'" />'+'</marker>';}// Selected connection arrowhead
765
+ tmpMarkup+='<marker id="flow-arrowhead-selected-'+pViewIdentifier+'"'+' markerWidth="'+tmpSelectedMarker.MarkerWidth+'"'+' markerHeight="'+tmpSelectedMarker.MarkerHeight+'"'+' refX="'+tmpSelectedMarker.RefX+'"'+' refY="'+tmpSelectedMarker.RefY+'"'+' orient="auto" markerUnits="strokeWidth">'+'<polygon points="'+tmpSelectedMarker.Points+'" fill="'+tmpSelectedMarker.Fill+'" />'+'</marker>';// Tether arrowhead
766
+ tmpMarkup+='<marker id="flow-tether-arrowhead-'+pViewIdentifier+'"'+' markerWidth="'+tmpTetherMarker.MarkerWidth+'"'+' markerHeight="'+tmpTetherMarker.MarkerHeight+'"'+' refX="'+tmpTetherMarker.RefX+'"'+' refY="'+tmpTetherMarker.RefY+'"'+' orient="auto" markerUnits="strokeWidth">'+'<polygon points="'+tmpTetherMarker.Points+'" fill="'+tmpTetherMarker.Fill+'" />'+'</marker>';return tmpMarkup;}}]);}(libFableServiceProviderBase);module.exports=PictProviderFlowConnectorShapes;},{"fable-serviceproviderbase":4}],18:[function(require,module,exports){var libPictProvider=require('pict-provider');var _ProviderConfiguration={ProviderIdentifier:'PictProviderFlowEventHandler'};/**
767
+ * Event handler provider for the flow diagram.
768
+ * Provides hook points for extensibility - consumers can register handlers
769
+ * for flow events like node selection, movement, connection creation, etc.
770
+ *
771
+ * Supported events:
772
+ * - onNodeSelected(node) - A node was selected (or null for deselection)
773
+ * - onNodeAdded(node) - A new node was added
774
+ * - onNodeRemoved(node) - A node was removed
775
+ * - onNodeMoved(node) - A node was moved to a new position
776
+ * - onConnectionSelected(conn) - A connection was selected
777
+ * - onConnectionCreated(conn) - A new connection was created
778
+ * - onConnectionRemoved(conn) - A connection was removed
779
+ * - onConnectionHandleMoved(conn) - A connection's drag handle was repositioned
780
+ * - onConnectionModeChanged(conn) - A connection's line mode was toggled (bezier/orthogonal)
781
+ * - onPanelOpened(panelData) - A properties panel was opened
782
+ * - onPanelClosed(panelData) - A properties panel was closed
783
+ * - onPanelMoved(panelData) - A properties panel was moved
784
+ * - onTetherSelected(panelData) - A tether line was selected (or null for deselection)
785
+ * - onTetherHandleMoved(panelData) - A tether's drag handle was repositioned
786
+ * - onTetherModeChanged(panelData) - A tether's line mode was toggled (bezier/orthogonal)
787
+ * - onLayoutSaved(layoutData) - A layout snapshot was saved
788
+ * - onLayoutRestored(layoutData) - A saved layout was restored
789
+ * - onLayoutDeleted(layoutData) - A saved layout was deleted
790
+ * - onFlowChanged(flowData) - The flow data changed (catch-all)
791
+ */var PictProviderFlowEventHandler=/*#__PURE__*/function(_libPictProvider){function PictProviderFlowEventHandler(pFable,pOptions,pServiceHash){var _this21;_classCallCheck(this,PictProviderFlowEventHandler);var tmpOptions=Object.assign({},_ProviderConfiguration,pOptions);_this21=_callSuper(this,PictProviderFlowEventHandler,[pFable,tmpOptions,pServiceHash]);_this21.serviceType='PictProviderFlowEventHandler';_this21._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;// Event handler registry
792
+ _this21._Handlers={};return _this21;}/**
793
+ * Register an event handler
794
+ * @param {string} pEventName - The event name (e.g., 'onNodeSelected')
795
+ * @param {Function} pHandler - The handler function
796
+ * @param {string} [pHandlerHash] - Optional unique identifier for this handler (for later removal)
797
+ * @returns {string} The handler hash
798
+ */_inherits(PictProviderFlowEventHandler,_libPictProvider);return _createClass(PictProviderFlowEventHandler,[{key:"registerHandler",value:function registerHandler(pEventName,pHandler,pHandlerHash){if(typeof pHandler!=='function'){this.log.warn("PictProviderFlowEventHandler registerHandler: handler for '".concat(pEventName,"' is not a function"));return null;}if(!this._Handlers[pEventName]){this._Handlers[pEventName]=[];}var tmpHash=pHandlerHash||"handler-".concat(this.fable.getUUID());this._Handlers[pEventName].push({Hash:tmpHash,Handler:pHandler});this.log.trace("PictProviderFlowEventHandler registered handler '".concat(tmpHash,"' for event '").concat(pEventName,"'"));return tmpHash;}/**
799
+ * Remove a specific event handler
800
+ * @param {string} pEventName - The event name
801
+ * @param {string} pHandlerHash - The handler hash to remove
802
+ * @returns {boolean}
803
+ */},{key:"removeHandler",value:function removeHandler(pEventName,pHandlerHash){if(!this._Handlers[pEventName])return false;var tmpIndex=this._Handlers[pEventName].findIndex(function(pH){return pH.Hash===pHandlerHash;});if(tmpIndex>=0){this._Handlers[pEventName].splice(tmpIndex,1);return true;}return false;}/**
804
+ * Remove all handlers for a specific event
805
+ * @param {string} pEventName
806
+ */},{key:"removeAllHandlers",value:function removeAllHandlers(pEventName){if(pEventName){this._Handlers[pEventName]=[];}else{this._Handlers={};}}/**
807
+ * Fire an event, calling all registered handlers
808
+ * @param {string} pEventName - The event name
809
+ * @param {*} pEventData - The event data to pass to handlers
810
+ */},{key:"fireEvent",value:function fireEvent(pEventName,pEventData){this.log.trace("PictProviderFlowEventHandler firing event '".concat(pEventName,"'"));if(!this._Handlers[pEventName]||this._Handlers[pEventName].length===0){return;}for(var i=0;i<this._Handlers[pEventName].length;i++){var tmpEntry=this._Handlers[pEventName][i];try{tmpEntry.Handler(pEventData,this._FlowView);}catch(pError){this.log.error("PictProviderFlowEventHandler error in handler '".concat(tmpEntry.Hash,"' for event '").concat(pEventName,"': ").concat(pError.message));}}}/**
811
+ * Check if any handlers are registered for a specific event
812
+ * @param {string} pEventName
813
+ * @returns {boolean}
814
+ */},{key:"hasHandlers",value:function hasHandlers(pEventName){return!!(this._Handlers[pEventName]&&this._Handlers[pEventName].length>0);}/**
815
+ * Get the count of handlers for a specific event
816
+ * @param {string} pEventName
817
+ * @returns {number}
818
+ */},{key:"getHandlerCount",value:function getHandlerCount(pEventName){if(!this._Handlers[pEventName])return 0;return this._Handlers[pEventName].length;}}]);}(libPictProvider);module.exports=PictProviderFlowEventHandler;module.exports.default_configuration=_ProviderConfiguration;},{"pict-provider":8}],19:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
819
+ * PictProvider-Flow-Geometry
820
+ *
821
+ * Shared geometry utilities for the flow diagram.
822
+ * Provides direction vectors and edge center calculations used by
823
+ * connections, tethers, and other flow components.
824
+ *
825
+ * Port Side values (12 positions):
826
+ *
827
+ * Top edge: 'top-left' 'top' 'top-right'
828
+ * Left edge: 'left-top' 'left' 'left-bottom'
829
+ * Right edge: 'right-top' 'right' 'right-bottom'
830
+ * Bottom edge: 'bottom-left' 'bottom' 'bottom-right'
831
+ *
832
+ * The old 4-value sides ('left', 'right', 'top', 'bottom') map to
833
+ * the middle position on each edge for backward compatibility.
834
+ */var PictProviderFlowGeometry=/*#__PURE__*/function(_libFableServiceProvi5){function PictProviderFlowGeometry(pFable,pOptions,pServiceHash){var _this22;_classCallCheck(this,PictProviderFlowGeometry);_this22=_callSuper(this,PictProviderFlowGeometry,[pFable,pOptions,pServiceHash]);_this22.serviceType='PictProviderFlowGeometry';return _this22;}/**
835
+ * Extract the edge name from a Side value.
836
+ *
837
+ * Maps all 12 positions (and the 4 legacy values) back to
838
+ * the edge they sit on: 'left', 'right', 'top', or 'bottom'.
839
+ *
840
+ * @param {string} pSide - Any valid Side value
841
+ * @returns {string} The edge: 'left', 'right', 'top', or 'bottom'
842
+ */_inherits(PictProviderFlowGeometry,_libFableServiceProvi5);return _createClass(PictProviderFlowGeometry,[{key:"getEdgeFromSide",value:function getEdgeFromSide(pSide){switch(pSide){case'left-top':case'left':case'left-bottom':return'left';case'right-top':case'right':case'right-bottom':return'right';case'top-left':case'top':case'top-right':return'top';case'bottom-left':case'bottom':case'bottom-right':return'bottom';default:return'right';}}/**
843
+ * Get the outward unit direction vector for a given side.
844
+ *
845
+ * All positions on the same edge share the same direction vector.
846
+ *
847
+ * @param {string} pSide - Any valid Side value (12 positions or 4 legacy)
848
+ * @returns {{dx: number, dy: number}}
849
+ */},{key:"sideDirection",value:function sideDirection(pSide){switch(this.getEdgeFromSide(pSide)){case'left':return{dx:-1,dy:0};case'right':return{dx:1,dy:0};case'top':return{dx:0,dy:-1};case'bottom':return{dx:0,dy:1};default:return{dx:1,dy:0};}}/**
850
+ * Get the center point of a rectangle's edge.
851
+ * Works for any object with X, Y, Width, Height properties
852
+ * (nodes, panels, or any rectangular element).
853
+ *
854
+ * @param {Object} pRectData - Object with X, Y, Width, Height
855
+ * @param {string} pSide - 'left', 'right', 'top', 'bottom'
856
+ * @returns {{x: number, y: number}}
857
+ */},{key:"getEdgeCenter",value:function getEdgeCenter(pRectData,pSide){switch(pSide){case'left':return{x:pRectData.X,y:pRectData.Y+pRectData.Height/2};case'right':return{x:pRectData.X+pRectData.Width,y:pRectData.Y+pRectData.Height/2};case'top':return{x:pRectData.X+pRectData.Width/2,y:pRectData.Y};case'bottom':return{x:pRectData.X+pRectData.Width/2,y:pRectData.Y+pRectData.Height};default:return{x:pRectData.X+pRectData.Width,y:pRectData.Y+pRectData.Height/2};}}/**
858
+ * Calculate a port's local position relative to node origin.
859
+ *
860
+ * Supports 12 positions (3 zones per edge). For left/right edges,
861
+ * the body area below the title bar is divided into vertical zones.
862
+ * For top/bottom edges, the full width is divided into horizontal zones.
863
+ *
864
+ * When pPortCountsBySide is provided, zone fractions are computed
865
+ * proportionally based on actual port counts (adaptive zones).
866
+ * Otherwise, fixed 1/3 zones are used for backward compatibility.
867
+ *
868
+ * Multiple ports sharing the same Side value distribute evenly within
869
+ * their zone.
870
+ *
871
+ * @param {string} pSide - Side value (any of 12 positions or 4 legacy)
872
+ * @param {number} pIndex - Index of this port within its Side group
873
+ * @param {number} pTotal - Total ports with this Side value
874
+ * @param {number} pWidth - Node width
875
+ * @param {number} pHeight - Node height
876
+ * @param {number} pTitleBarHeight - Height of the node title bar
877
+ * @param {Object} [pPortCountsBySide] - Optional map of Side → port count
878
+ * for all ports on the node. Enables adaptive zone sizing.
879
+ * @returns {{x: number, y: number}}
880
+ */},{key:"getPortLocalPosition",value:function getPortLocalPosition(pSide,pIndex,pTotal,pWidth,pHeight,pTitleBarHeight,pPortCountsBySide){var tmpEdge=this.getEdgeFromSide(pSide);var tmpZone=pPortCountsBySide?this._computeAdaptiveZone(pSide,pPortCountsBySide):this._getZoneFromSide(pSide);// Use the fixed zone to decide alignment intent (start/center/end)
881
+ // because adaptive zones shift boundaries when neighbouring zones
882
+ // are empty, which would break alignment decisions.
883
+ var tmpFixedZone=this._getZoneFromSide(pSide);// Minimum spacing between port centers (px)
884
+ var tmpMinSpacing=16;// Reserve space at the bottom of the body so that port badges
885
+ // never overlap the panel-indicator icon (10×10 rect at bottom-right)
886
+ // and always leave a visible gap above the node bottom edge.
887
+ var tmpBottomPad=16;// Determine alignment from the fixed zone position:
888
+ // start zone (0.000 – 0.333) → start-align (offset 0)
889
+ // middle zone (0.333 – 0.667) → center
890
+ // end zone (0.667 – 1.000) → end-align
891
+ var tmpAlignment='start';if(tmpFixedZone.start>=0.5){tmpAlignment='end';}else if(tmpFixedZone.start>=0.17){tmpAlignment='center';}if(tmpEdge==='left'||tmpEdge==='right'){var _tmpX=tmpEdge==='left'?0:pWidth;var tmpBodyHeight=pHeight-pTitleBarHeight-tmpBottomPad;var _tmpZoneStart=pTitleBarHeight+tmpBodyHeight*tmpZone.start;var tmpZoneHeight=tmpBodyHeight*(tmpZone.end-tmpZone.start);// Use fixed spacing so port gaps stay consistent across cards
892
+ // even when one edge drives the card height beyond what the
893
+ // other needs.
894
+ var _tmpSpacing=tmpMinSpacing;var tmpGroupHeight=_tmpSpacing*(pTotal+1);var _tmpSlack=tmpZoneHeight-tmpGroupHeight;if(_tmpSlack<0){_tmpSlack=0;}var _tmpAlignOffset=0;if(tmpAlignment==='end'){_tmpAlignOffset=_tmpSlack;}else if(tmpAlignment==='center'){_tmpAlignOffset=_tmpSlack/2;}var _tmpY=_tmpZoneStart+_tmpAlignOffset+_tmpSpacing*(pIndex+1);return{x:_tmpX,y:_tmpY};}// top or bottom
895
+ var tmpY=tmpEdge==='top'?0:pHeight;var tmpZoneStart=pWidth*tmpZone.start;var tmpZoneWidth=pWidth*(tmpZone.end-tmpZone.start);var tmpSpacing=tmpMinSpacing;var tmpGroupWidth=tmpSpacing*(pTotal+1);var tmpSlack=tmpZoneWidth-tmpGroupWidth;if(tmpSlack<0){tmpSlack=0;}var tmpAlignOffset=0;if(tmpAlignment==='end'){tmpAlignOffset=tmpSlack;}else if(tmpAlignment==='center'){tmpAlignOffset=tmpSlack/2;}var tmpX=tmpZoneStart+tmpAlignOffset+tmpSpacing*(pIndex+1);return{x:tmpX,y:tmpY};}/**
896
+ * Get the zone fraction (start, end) for a Side value.
897
+ *
898
+ * Each edge is divided into three zones of equal size:
899
+ * start: 0.0 — 0.333
900
+ * middle: 0.333 — 0.667
901
+ * end: 0.667 — 1.0
902
+ *
903
+ * Used as fallback when adaptive zones are not available.
904
+ *
905
+ * @param {string} pSide
906
+ * @returns {{start: number, end: number}}
907
+ */},{key:"_getZoneFromSide",value:function _getZoneFromSide(pSide){switch(pSide){// Left edge: top, middle, bottom
908
+ case'left-top':return{start:0.0,end:0.333};case'left':return{start:0.333,end:0.667};case'left-bottom':return{start:0.667,end:1.0};// Right edge: top, middle, bottom
909
+ case'right-top':return{start:0.0,end:0.333};case'right':return{start:0.333,end:0.667};case'right-bottom':return{start:0.667,end:1.0};// Top edge: left, middle, right
910
+ case'top-left':return{start:0.0,end:0.333};case'top':return{start:0.333,end:0.667};case'top-right':return{start:0.667,end:1.0};// Bottom edge: left, middle, right
911
+ case'bottom-left':return{start:0.0,end:0.333};case'bottom':return{start:0.333,end:0.667};case'bottom-right':return{start:0.667,end:1.0};// Fallback: full range (legacy behavior)
912
+ default:return{start:0.0,end:1.0};}}/**
913
+ * Get the three zone Side keys for a given edge, in order.
914
+ *
915
+ * @param {string} pEdge - 'left', 'right', 'top', or 'bottom'
916
+ * @returns {Array<string>} Three Side keys in start-to-end order
917
+ */},{key:"_getZoneKeysForEdge",value:function _getZoneKeysForEdge(pEdge){switch(pEdge){case'left':return['left-top','left','left-bottom'];case'right':return['right-top','right','right-bottom'];case'top':return['top-left','top','top-right'];case'bottom':return['bottom-left','bottom','bottom-right'];default:return['right-top','right','right-bottom'];}}/**
918
+ * Compute an adaptive zone fraction for a Side value based on the
919
+ * actual port distribution across all zones on the same edge.
920
+ *
921
+ * Instead of fixed 1/3 splits, zones are sized proportionally to the
922
+ * space each zone needs (minSpacing * (portCount + 1)). Zones with
923
+ * zero ports collapse to zero, giving occupied zones more room.
924
+ *
925
+ * @param {string} pSide - The Side value to compute a zone for
926
+ * @param {Object} pPortCountsBySide - Map of Side → number of ports
927
+ * @returns {{start: number, end: number}}
928
+ */},{key:"_computeAdaptiveZone",value:function _computeAdaptiveZone(pSide,pPortCountsBySide){var tmpEdge=this.getEdgeFromSide(pSide);var tmpZoneKeys=this._getZoneKeysForEdge(tmpEdge);var tmpMinSpacing=16;// Compute the space each zone needs: minSpacing * (count + 1)
929
+ // The +1 provides padding at both ends of the zone.
930
+ var tmpTotalSpace=0;var tmpSpaceByZone={};for(var i=0;i<tmpZoneKeys.length;i++){var tmpKey=tmpZoneKeys[i];var tmpCount=pPortCountsBySide[tmpKey]||0;var tmpSpace=tmpCount>0?tmpMinSpacing*(tmpCount+1):0;tmpSpaceByZone[tmpKey]=tmpSpace;tmpTotalSpace+=tmpSpace;}// If no ports on this edge at all, fall back to fixed zones
931
+ if(tmpTotalSpace===0){return this._getZoneFromSide(pSide);}// Compute proportional start/end for the requested zone
932
+ var tmpCumulativeStart=0;for(var _i25=0;_i25<tmpZoneKeys.length;_i25++){var _tmpKey=tmpZoneKeys[_i25];var tmpFraction=tmpSpaceByZone[_tmpKey]/tmpTotalSpace;if(_tmpKey===pSide){return{start:tmpCumulativeStart,end:tmpCumulativeStart+tmpFraction};}tmpCumulativeStart+=tmpFraction;}// Should not reach here; fall back to fixed zones
933
+ return this._getZoneFromSide(pSide);}/**
934
+ * Build a map of Side → port count from an array of port objects.
935
+ *
936
+ * Convenience method for callers that need to pass port counts
937
+ * to getPortLocalPosition or computeMinimumNodeHeight.
938
+ *
939
+ * @param {Array} pPorts - Array of port objects with Side, Direction
940
+ * @returns {Object} Map of Side value → count
941
+ */},{key:"buildPortCountsBySide",value:function buildPortCountsBySide(pPorts){var tmpCounts={};if(!pPorts||!Array.isArray(pPorts)){return tmpCounts;}for(var i=0;i<pPorts.length;i++){var tmpSide=pPorts[i].Side||(pPorts[i].Direction==='input'?'left':'right');if(!tmpCounts[tmpSide]){tmpCounts[tmpSide]=0;}tmpCounts[tmpSide]++;}return tmpCounts;}/**
942
+ * Compute the minimum node height required so that all ports
943
+ * (with their badges) fit within the node boundary.
944
+ *
945
+ * Uses adaptive zone sizing: instead of assuming each zone gets
946
+ * a fixed 1/3 of the body, sums the space needed by all occupied
947
+ * zones on each left/right edge. This produces compact cards
948
+ * whose height scales linearly with total port count.
949
+ *
950
+ * @param {Array} pPorts - Array of port objects with Side, Direction
951
+ * @param {number} pTitleBarHeight - Height of the title bar
952
+ * @returns {number} Minimum node height in pixels (0 if no ports)
953
+ */},{key:"computeMinimumNodeHeight",value:function computeMinimumNodeHeight(pPorts,pTitleBarHeight){if(!pPorts||!Array.isArray(pPorts)||pPorts.length===0){return 0;}var tmpMinSpacing=16;var tmpBottomPad=16;// Count ports per Side value
954
+ var tmpCountBySide=this.buildPortCountsBySide(pPorts);// Sum the space needed per edge (left, right) across all zones.
955
+ // Each zone needs minSpacing * (count + 1) pixels.
956
+ var tmpSpacePerEdge={};for(var tmpSide in tmpCountBySide){var tmpEdge=this.getEdgeFromSide(tmpSide);// Only left/right edge zones affect required height
957
+ if(tmpEdge!=='left'&&tmpEdge!=='right'){continue;}var tmpCount=tmpCountBySide[tmpSide];var tmpZoneSpace=tmpMinSpacing*(tmpCount+1);if(!tmpSpacePerEdge[tmpEdge]){tmpSpacePerEdge[tmpEdge]=0;}tmpSpacePerEdge[tmpEdge]+=tmpZoneSpace;}// The minimum height is titleBar + bottomPad + max edge space
958
+ var tmpMinHeight=0;for(var _tmpEdge in tmpSpacePerEdge){var tmpRequired=pTitleBarHeight+tmpBottomPad+tmpSpacePerEdge[_tmpEdge];if(tmpRequired>tmpMinHeight){tmpMinHeight=tmpRequired;}}return Math.ceil(tmpMinHeight);}}]);}(libFableServiceProviderBase);module.exports=PictProviderFlowGeometry;},{"fable-serviceproviderbase":4}],20:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
959
+ * PictProvider-Flow-Icons
960
+ *
961
+ * Centralized SVG icon provider for the flow diagram.
962
+ * All icons use a duotone style: 2px outline (#2c3e50) with
963
+ * subtle filled accent shapes (#d5e8f7).
964
+ *
965
+ * Each icon is registered as a pict template with hash `Flow-Icon-{key}`,
966
+ * making them individually overridable by consumers.
967
+ */var _ProviderConfiguration={ProviderIdentifier:'PictProviderFlowIcons'};// ── Default Icon SVG Markup ────────────────────────────────────────────────
968
+ // All icons: viewBox="0 0 24 24", duotone style
969
+ // Accent fill: #d5e8f7, Stroke: #2c3e50, Stroke-width: 2
970
+ //
971
+ // The {FlowIconSize} placeholder is replaced at render time with the
972
+ // requested pixel size. Each template is a self-contained <svg> element.
973
+ var _DefaultIcons={// ── FlowCard Icons ─────────────────────────────────────────────────────
974
+ 'ITE':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="6" r="3" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><circle cx="6" cy="18" r="2.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><circle cx="18" cy="18" r="2.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M12 9v2M9.5 12.5L6 15.5M14.5 12.5L18 15.5" stroke="#2c3e50" stroke-width="2"/></svg>','SW':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M3 12h5M16 12h5M14.8 9.2l3.7-5.2M14.8 14.8l3.7 5.2" stroke="#2c3e50" stroke-width="2"/></svg>','EACH':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><rect x="14" y="3" width="7" height="7" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><rect x="3" y="14" width="7" height="7" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><rect x="14" y="14" width="7" height="7" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/></svg>','FREAD':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9l-7-7z" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M13 2v7h7" stroke="#2c3e50" stroke-width="2"/><path d="M9 13h6M9 17h4" stroke="#2c3e50" stroke-width="2"/></svg>','FWRITE':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9l-7-7z" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M13 2v7h7" stroke="#2c3e50" stroke-width="2"/><path d="M12 13v5M9.5 15.5L12 13l2.5 2.5" stroke="#2c3e50" stroke-width="2"/></svg>','LOG':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="3" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><circle cx="7.5" cy="8" r="1" fill="#2c3e50"/><circle cx="7.5" cy="12" r="1" fill="#2c3e50"/><circle cx="7.5" cy="16" r="1" fill="#2c3e50"/><path d="M11 8h5.5M11 12h5.5M11 16h3.5" stroke="#2c3e50" stroke-width="2"/></svg>','GET':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><circle cx="10.5" cy="10.5" r="6.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M21 21l-5.15-5.15" stroke="#2c3e50" stroke-width="2"/></svg>','SET':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4.5 1.5L4 16Z" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M14 6l3 3" stroke="#2c3e50" stroke-width="2"/></svg>',// ── UI Icons ───────────────────────────────────────────────────────────
975
+ 'fullscreen':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke="#2c3e50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg>','exit-fullscreen':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke="#2c3e50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 14h6v6"/><path d="M20 10h-6V4"/><path d="M14 10l7-7"/><path d="M3 21l7-7"/></svg>','close':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke="#2c3e50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>','chevron-down':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke="#2c3e50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>',// ── Toolbar & Popup Icons ─────────────────────────────────────────────
976
+ 'search':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M21 21l-4.35-4.35" stroke="#2c3e50" stroke-width="2"/></svg>','cards':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="7" width="16" height="12" rx="2" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M6 7V5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-2" stroke="#2c3e50" stroke-width="2"/></svg>','layout':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="8" height="10" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><rect x="13" y="3" width="8" height="6" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><rect x="3" y="15" width="8" height="6" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><rect x="13" y="11" width="8" height="10" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/></svg>','collapse':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="3" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M8 12h8" stroke="#2c3e50" stroke-width="2"/></svg>','expand':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="3" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M12 8v8M8 12h8" stroke="#2c3e50" stroke-width="2"/></svg>','grip':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="#2c3e50"><circle cx="9" cy="5" r="1.5"/><circle cx="15" cy="5" r="1.5"/><circle cx="9" cy="12" r="1.5"/><circle cx="15" cy="12" r="1.5"/><circle cx="9" cy="19" r="1.5"/><circle cx="15" cy="19" r="1.5"/></svg>','settings':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke="#2c3e50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3" fill="#d5e8f7"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>','plus':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M12 8v8M8 12h8" stroke="#2c3e50" stroke-width="2"/></svg>','trash':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18" stroke="#2c3e50" stroke-width="2"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" stroke="#2c3e50" stroke-width="2"/><rect x="5" y="6" width="14" height="14" rx="2" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M10 11v6M14 11v6" stroke="#2c3e50" stroke-width="2"/></svg>','save':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M17 21v-8H7v8" stroke="#2c3e50" stroke-width="2"/><path d="M7 3v5h8" stroke="#2c3e50" stroke-width="2"/></svg>','auto-layout':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="8" y="2" width="8" height="6" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><rect x="2" y="16" width="8" height="6" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><rect x="14" y="16" width="8" height="6" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M12 8v4M6 16v-4h12v4" stroke="#2c3e50" stroke-width="2"/></svg>','zoom-in':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M21 21l-4.35-4.35" stroke="#2c3e50" stroke-width="2"/><path d="M11 8v6M8 11h6" stroke="#2c3e50" stroke-width="2"/></svg>','zoom-out':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="7" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M21 21l-4.35-4.35" stroke="#2c3e50" stroke-width="2"/><path d="M8 11h6" stroke="#2c3e50" stroke-width="2"/></svg>','zoom-fit':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke="#2c3e50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7V3h4"/><path d="M17 3h4v4"/><path d="M21 17v4h-4"/><path d="M7 21H3v-4"/><rect x="7" y="7" width="10" height="10" rx="1.5" fill="#d5e8f7"/></svg>','dock':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="4" rx="1.5" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M12 20V11M8 14l4-4 4 4" stroke="#2c3e50" stroke-width="2"/></svg>','restore':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke="#2c3e50" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg>','delete-node':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18" stroke="#2c3e50" stroke-width="2"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" stroke="#2c3e50" stroke-width="2"/><rect x="5" y="6" width="14" height="14" rx="2" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><path d="M10 11v6M14 11v6" stroke="#2c3e50" stroke-width="2"/></svg>',// ── Fallback ───────────────────────────────────────────────────────────
977
+ 'default':'<svg xmlns="http://www.w3.org/2000/svg" width="{FlowIconSize}" height="{FlowIconSize}" viewBox="0 0 24 24" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="4" fill="#d5e8f7" stroke="#2c3e50" stroke-width="2"/><circle cx="12" cy="12" r="2.5" fill="#2c3e50"/></svg>'};var PictProviderFlowIcons=/*#__PURE__*/function(_libFableServiceProvi6){function PictProviderFlowIcons(pFable,pOptions,pServiceHash){var _this23;_classCallCheck(this,PictProviderFlowIcons);var tmpOptions=Object.assign({},_ProviderConfiguration,pOptions);_this23=_callSuper(this,PictProviderFlowIcons,[pFable,tmpOptions,pServiceHash]);_this23.serviceType='PictProviderFlowIcons';_this23._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;// Deep copy the default icons
978
+ _this23._Icons=JSON.parse(JSON.stringify(_DefaultIcons));// Merge any additional icons passed via options
979
+ if(pOptions&&pOptions.AdditionalIcons&&_typeof(pOptions.AdditionalIcons)==='object'){var tmpKeys=Object.keys(pOptions.AdditionalIcons);for(var i=0;i<tmpKeys.length;i++){_this23._Icons[tmpKeys[i]]=pOptions.AdditionalIcons[tmpKeys[i]];}}return _this23;}/**
980
+ * Register all icons as pict templates with hash Flow-Icon-{key}.
981
+ * Consumers can override any icon by registering a template with
982
+ * the same hash before the flow view renders.
983
+ */_inherits(PictProviderFlowIcons,_libFableServiceProvi6);return _createClass(PictProviderFlowIcons,[{key:"registerIconTemplates",value:function registerIconTemplates(){if(!this.fable||!this.fable.TemplateProvider){this.log.warn('PictProviderFlowIcons: TemplateProvider not available; icon templates not registered.');return;}var tmpKeys=Object.keys(this._Icons);for(var i=0;i<tmpKeys.length;i++){var tmpHash='Flow-Icon-'+tmpKeys[i];// Only register if not already present (allow consumer overrides)
984
+ if(!this.fable.TemplateProvider.getTemplate(tmpHash)){this.fable.TemplateProvider.addTemplate(tmpHash,this._Icons[tmpKeys[i]]);}}}/**
985
+ * Determine if the given icon string is an emoji (legacy) or an icon key.
986
+ * Returns true if the string contains characters with code points above U+00FF,
987
+ * indicating emoji or Unicode symbol characters.
988
+ *
989
+ * @param {string} pIconValue - The icon value to check
990
+ * @returns {boolean}
991
+ */},{key:"isEmojiIcon",value:function isEmojiIcon(pIconValue){if(!pIconValue||typeof pIconValue!=='string'){return false;}for(var i=0;i<pIconValue.length;i++){if(pIconValue.charCodeAt(i)>255){return true;}}return false;}/**
992
+ * Resolve the icon key to use for a given CardMetadata object.
993
+ * Tries Icon field first, then Code field, then falls back to 'default'.
994
+ *
995
+ * @param {Object} pCardMetadata - The CardMetadata object
996
+ * @returns {string} The icon key
997
+ */},{key:"resolveIconKey",value:function resolveIconKey(pCardMetadata){if(!pCardMetadata){return'default';}// If Icon is a known key, use it
998
+ if(pCardMetadata.Icon&&this._Icons.hasOwnProperty(pCardMetadata.Icon)){return pCardMetadata.Icon;}// If Icon is a non-emoji string, check if it matches a registered template
999
+ if(pCardMetadata.Icon&&!this.isEmojiIcon(pCardMetadata.Icon)){return pCardMetadata.Icon;}// Fall back to Code field
1000
+ if(pCardMetadata.Code&&this._Icons.hasOwnProperty(pCardMetadata.Code)){return pCardMetadata.Code;}return'default';}/**
1001
+ * Get the raw SVG markup string for a given icon key, with size applied.
1002
+ *
1003
+ * @param {string} pIconKey - The icon key
1004
+ * @param {number} pSize - Pixel size (default 16)
1005
+ * @returns {string} The SVG markup string
1006
+ */},{key:"getIconSVGMarkup",value:function getIconSVGMarkup(pIconKey,pSize){var tmpSize=pSize||16;var tmpKey=pIconKey||'default';var tmpMarkup=this._Icons[tmpKey]||this._Icons['default'];// Replace the size placeholder
1007
+ return tmpMarkup.replace(/\{FlowIconSize\}/g,String(tmpSize));}/**
1008
+ * Render an icon into an SVG canvas context using createElementNS.
1009
+ * Creates a <g> element containing the icon paths, positioned at (pX, pY)
1010
+ * with the given size via a scale transform.
1011
+ *
1012
+ * @param {string} pIconKey - The icon key
1013
+ * @param {SVGElement} pParentGroup - The parent SVG group to append to
1014
+ * @param {number} pX - X position (top-left of icon bounding box)
1015
+ * @param {number} pY - Y position (top-left of icon bounding box)
1016
+ * @param {number} pSize - Pixel size (default 16)
1017
+ * @returns {SVGGElement|null} The created group element, or null on failure
1018
+ */},{key:"renderIconIntoSVGGroup",value:function renderIconIntoSVGGroup(pIconKey,pParentGroup,pX,pY,pSize){if(!pParentGroup){return null;}var tmpSize=pSize||16;var tmpScale=tmpSize/24;var tmpKey=pIconKey||'default';var tmpMarkup=this._Icons[tmpKey]||this._Icons['default'];// Replace size placeholder (for consistency, though we scale via transform)
1019
+ tmpMarkup=tmpMarkup.replace(/\{FlowIconSize\}/g,'24');try{// Create a temporary SVG element to parse the icon markup
1020
+ var tmpTempSVG=document.createElementNS('http://www.w3.org/2000/svg','svg');tmpTempSVG.innerHTML=tmpMarkup;// Find the inner SVG (the icon's root <svg> element)
1021
+ var tmpInnerSVG=tmpTempSVG.querySelector('svg');if(!tmpInnerSVG){return null;}// Create a group to hold the icon content
1022
+ var tmpGroup=document.createElementNS('http://www.w3.org/2000/svg','g');tmpGroup.setAttribute('transform','translate('+pX+','+pY+') scale('+tmpScale+')');tmpGroup.setAttribute('pointer-events','none');tmpGroup.setAttribute('class','pict-flow-icon-svg');// Move all children from the parsed SVG into the group
1023
+ while(tmpInnerSVG.childNodes.length>0){tmpGroup.appendChild(tmpInnerSVG.childNodes[0]);}pParentGroup.appendChild(tmpGroup);return tmpGroup;}catch(pError){this.log.warn('PictProviderFlowIcons renderIconIntoSVGGroup error: '+pError.message);return null;}}/**
1024
+ * Get all registered icon keys.
1025
+ * @returns {Array<string>}
1026
+ */},{key:"getIconKeys",value:function getIconKeys(){return Object.keys(this._Icons);}/**
1027
+ * Check if a given key has a registered icon.
1028
+ * @param {string} pIconKey
1029
+ * @returns {boolean}
1030
+ */},{key:"hasIcon",value:function hasIcon(pIconKey){return this._Icons.hasOwnProperty(pIconKey);}/**
1031
+ * Register a new icon or override an existing one.
1032
+ * @param {string} pIconKey - The icon key
1033
+ * @param {string} pSVGMarkup - The SVG markup string (must contain {FlowIconSize} placeholders)
1034
+ * @returns {boolean}
1035
+ */},{key:"registerIcon",value:function registerIcon(pIconKey,pSVGMarkup){if(!pIconKey||!pSVGMarkup){return false;}this._Icons[pIconKey]=pSVGMarkup;// Also update the pict template if TemplateProvider is available
1036
+ if(this.fable&&this.fable.TemplateProvider){this.fable.TemplateProvider.addTemplate('Flow-Icon-'+pIconKey,pSVGMarkup);}return true;}}]);}(libFableServiceProviderBase);module.exports=PictProviderFlowIcons;module.exports.default_configuration=_ProviderConfiguration;module.exports.DefaultIcons=_DefaultIcons;},{"fable-serviceproviderbase":4}],21:[function(require,module,exports){var libPictProvider=require('pict-provider');var _ProviderConfiguration={ProviderIdentifier:'PictProviderFlowLayouts'};/**
1037
+ * Provider for managing saved flow diagram layouts.
1038
+ *
1039
+ * Layouts capture the spatial arrangement of nodes and panels on the canvas
1040
+ * without storing any card content. When a layout is restored, nodes that
1041
+ * still exist are placed at their saved positions and any new nodes are
1042
+ * auto-laid-out to the right.
1043
+ *
1044
+ * ## Persistence
1045
+ *
1046
+ * By default, layouts are persisted to the browser's `localStorage` using a
1047
+ * key derived from the flow view identifier. This means layouts survive page
1048
+ * refreshes out of the box.
1049
+ *
1050
+ * Developers can override the storage backend (e.g., to use a REST API or
1051
+ * IndexedDB) by replacing the three storage hook methods on the instance or
1052
+ * in a subclass:
1053
+ *
1054
+ * - `storageWrite(pLayouts, fCallback)` — persist the full layout array
1055
+ * - `storageRead(fCallback)` — load the persisted layout array
1056
+ * - `storageDelete(fCallback)` — remove all persisted layouts
1057
+ *
1058
+ * Each callback follows the Node convention: `fCallback(pError, pResult)`.
1059
+ *
1060
+ * Saved layout data structure:
1061
+ * {
1062
+ * Hash: "layout-<UUID>",
1063
+ * Name: "My Layout",
1064
+ * CreatedAt: "2026-02-26T12:00:00.000Z",
1065
+ * NodePositions: { "node-hash": { X, Y, Width, Height } },
1066
+ * PanelPositions: { "node-hash": { X, Y, Width, Height } },
1067
+ * ViewState: { PanX, PanY, Zoom }
1068
+ * }
1069
+ */var PictProviderFlowLayouts=/*#__PURE__*/function(_libPictProvider2){function PictProviderFlowLayouts(pFable,pOptions,pServiceHash){var _this24;_classCallCheck(this,PictProviderFlowLayouts);var tmpOptions=Object.assign({},_ProviderConfiguration,pOptions);_this24=_callSuper(this,PictProviderFlowLayouts,[pFable,tmpOptions,pServiceHash]);_this24.serviceType='PictProviderFlowLayouts';_this24._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;// Storage key for localStorage persistence.
1070
+ // Defaults to a key derived from the FlowView identifier, or can be
1071
+ // set via options.StorageKey. Pass `false` to disable localStorage.
1072
+ if(pOptions&&pOptions.StorageKey!==undefined){_this24._StorageKey=pOptions.StorageKey;}else if(_this24._FlowView&&_this24._FlowView.options&&_this24._FlowView.options.ViewIdentifier){_this24._StorageKey="pict-flow-layouts-".concat(_this24._FlowView.options.ViewIdentifier);}else{_this24._StorageKey='pict-flow-layouts';}return _this24;}// ── Storage Hooks ─────────────────────────────────────────────────────
1073
+ // These three methods form the persistence contract. The default
1074
+ // implementation uses localStorage. Override them on the instance or
1075
+ // subclass to use a REST API, IndexedDB, or any other backend.
1076
+ //
1077
+ // All callbacks follow `fCallback(pError, pResult)`.
1078
+ /**
1079
+ * Persist the full array of layout objects.
1080
+ *
1081
+ * Default implementation writes JSON to `localStorage`.
1082
+ *
1083
+ * @param {Array} pLayouts - The array of layout objects to persist
1084
+ * @param {Function} fCallback - `function(pError)` called when done
1085
+ */_inherits(PictProviderFlowLayouts,_libPictProvider2);return _createClass(PictProviderFlowLayouts,[{key:"storageWrite",value:function storageWrite(pLayouts,fCallback){if(this._StorageKey===false){return fCallback(null);}try{if(typeof localStorage!=='undefined'){localStorage.setItem(this._StorageKey,JSON.stringify(pLayouts));}return fCallback(null);}catch(pError){this.log.warn("PictProviderFlowLayouts storageWrite error: ".concat(pError.message));return fCallback(pError);}}/**
1086
+ * Load the persisted array of layout objects.
1087
+ *
1088
+ * Default implementation reads JSON from `localStorage`.
1089
+ *
1090
+ * @param {Function} fCallback - `function(pError, pLayouts)` where
1091
+ * pLayouts is an Array (or null/empty if nothing stored)
1092
+ */},{key:"storageRead",value:function storageRead(fCallback){if(this._StorageKey===false){return fCallback(null,[]);}try{if(typeof localStorage!=='undefined'){var tmpRaw=localStorage.getItem(this._StorageKey);if(tmpRaw){var tmpParsed=JSON.parse(tmpRaw);if(Array.isArray(tmpParsed)){return fCallback(null,tmpParsed);}}}return fCallback(null,[]);}catch(pError){this.log.warn("PictProviderFlowLayouts storageRead error: ".concat(pError.message));return fCallback(pError,[]);}}/**
1093
+ * Remove all persisted layout data.
1094
+ *
1095
+ * Default implementation removes the key from `localStorage`.
1096
+ *
1097
+ * @param {Function} fCallback - `function(pError)` called when done
1098
+ */},{key:"storageDelete",value:function storageDelete(fCallback){if(this._StorageKey===false){return fCallback(null);}try{if(typeof localStorage!=='undefined'){localStorage.removeItem(this._StorageKey);}return fCallback(null);}catch(pError){this.log.warn("PictProviderFlowLayouts storageDelete error: ".concat(pError.message));return fCallback(pError);}}// ── Initialization ────────────────────────────────────────────────────
1099
+ /**
1100
+ * Load persisted layouts and merge them into _FlowData.SavedLayouts.
1101
+ * Layouts already present in _FlowData (e.g., from setFlowData) are
1102
+ * kept; persisted layouts with new hashes are appended.
1103
+ *
1104
+ * Call this after _FlowData is populated.
1105
+ */},{key:"loadPersistedLayouts",value:function loadPersistedLayouts(){var _this25=this;this.storageRead(function(pError,pLayouts){if(pError||!Array.isArray(pLayouts)||pLayouts.length===0){return;}if(!_this25._FlowView||!_this25._FlowView._FlowData){return;}var tmpExisting=_this25._FlowView._FlowData.SavedLayouts;var tmpExistingHashes={};for(var i=0;i<tmpExisting.length;i++){tmpExistingHashes[tmpExisting[i].Hash]=true;}var tmpAdded=0;for(var _i26=0;_i26<pLayouts.length;_i26++){if(!tmpExistingHashes[pLayouts[_i26].Hash]){tmpExisting.push(pLayouts[_i26]);tmpAdded++;}}if(tmpAdded>0){_this25.log.trace("PictProviderFlowLayouts loaded ".concat(tmpAdded," persisted layout(s)"));}});}// ── Public API ────────────────────────────────────────────────────────
1106
+ /**
1107
+ * Save the current node and panel positions as a named layout.
1108
+ * @param {string} pName - The display name for this layout
1109
+ * @returns {Object} The saved layout entry
1110
+ */},{key:"saveLayout",value:function saveLayout(pName){var _this26=this;if(!this._FlowView){this.log.warn('PictProviderFlowLayouts saveLayout: no FlowView reference');return null;}var tmpFlowData=this._FlowView._FlowData;var tmpLayoutHash="layout-".concat(this.fable.getUUID());var tmpNodePositions={};var tmpPanelPositions={};// Capture node positions and per-instance overrides (Title, Style)
1111
+ for(var i=0;i<tmpFlowData.Nodes.length;i++){var tmpNode=tmpFlowData.Nodes[i];tmpNodePositions[tmpNode.Hash]={X:tmpNode.X,Y:tmpNode.Y,Width:tmpNode.Width,Height:tmpNode.Height,Title:tmpNode.Title};// Only include Style if it has been customized
1112
+ if(tmpNode.Style&&Object.keys(tmpNode.Style).length>0){tmpNodePositions[tmpNode.Hash].Style=JSON.parse(JSON.stringify(tmpNode.Style));}}// Capture panel positions keyed by NodeHash (panels get new hashes on each open)
1113
+ for(var _i27=0;_i27<tmpFlowData.OpenPanels.length;_i27++){var tmpPanel=tmpFlowData.OpenPanels[_i27];tmpPanelPositions[tmpPanel.NodeHash]={X:tmpPanel.X,Y:tmpPanel.Y,Width:tmpPanel.Width,Height:tmpPanel.Height};}var tmpLayout={Hash:tmpLayoutHash,Name:pName||'Untitled Layout',CreatedAt:new Date().toISOString(),NodePositions:tmpNodePositions,PanelPositions:tmpPanelPositions,ViewState:{PanX:tmpFlowData.ViewState.PanX,PanY:tmpFlowData.ViewState.PanY,Zoom:tmpFlowData.ViewState.Zoom}};tmpFlowData.SavedLayouts.push(tmpLayout);this._FlowView.marshalFromView();// Persist to storage
1114
+ this.storageWrite(tmpFlowData.SavedLayouts,function(pError){if(pError){_this26.log.warn("PictProviderFlowLayouts: failed to persist after save: ".concat(pError.message));}});if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onLayoutSaved',tmpLayout);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',tmpFlowData);}this.log.trace("PictProviderFlowLayouts saved layout '".concat(tmpLayout.Name,"' (").concat(tmpLayout.Hash,")"));return tmpLayout;}/**
1115
+ * Restore a saved layout by hash.
1116
+ * Nodes present in the saved layout are placed at their saved positions.
1117
+ * Nodes not in the saved layout are auto-laid-out to the right of the
1118
+ * positioned nodes.
1119
+ * @param {string} pLayoutHash - The hash of the layout to restore
1120
+ * @returns {boolean} Whether the layout was restored
1121
+ */},{key:"restoreLayout",value:function restoreLayout(pLayoutHash){if(!this._FlowView){this.log.warn('PictProviderFlowLayouts restoreLayout: no FlowView reference');return false;}var tmpFlowData=this._FlowView._FlowData;var tmpLayout=tmpFlowData.SavedLayouts.find(function(pLayout){return pLayout.Hash===pLayoutHash;});if(!tmpLayout){this.log.warn("PictProviderFlowLayouts restoreLayout: layout '".concat(pLayoutHash,"' not found"));return false;}var tmpMatchedNodes=[];var tmpUnmatchedNodes=[];// Apply saved positions to matched nodes; collect unmatched ones
1122
+ for(var i=0;i<tmpFlowData.Nodes.length;i++){var tmpNode=tmpFlowData.Nodes[i];var tmpSaved=tmpLayout.NodePositions[tmpNode.Hash];if(tmpSaved){tmpNode.X=tmpSaved.X;tmpNode.Y=tmpSaved.Y;if(typeof tmpSaved.Width==='number')tmpNode.Width=tmpSaved.Width;if(typeof tmpSaved.Height==='number')tmpNode.Height=tmpSaved.Height;if(typeof tmpSaved.Title==='string')tmpNode.Title=tmpSaved.Title;if(tmpSaved.Style&&_typeof(tmpSaved.Style)==='object'){tmpNode.Style=JSON.parse(JSON.stringify(tmpSaved.Style));}tmpMatchedNodes.push(tmpNode);}else{tmpUnmatchedNodes.push(tmpNode);}}// Apply saved panel positions (keyed by NodeHash)
1123
+ if(tmpLayout.PanelPositions){for(var _i28=0;_i28<tmpFlowData.OpenPanels.length;_i28++){var tmpPanel=tmpFlowData.OpenPanels[_i28];var tmpSavedPanel=tmpLayout.PanelPositions[tmpPanel.NodeHash];if(tmpSavedPanel){tmpPanel.X=tmpSavedPanel.X;tmpPanel.Y=tmpSavedPanel.Y;if(typeof tmpSavedPanel.Width==='number')tmpPanel.Width=tmpSavedPanel.Width;if(typeof tmpSavedPanel.Height==='number')tmpPanel.Height=tmpSavedPanel.Height;}}}// Auto-layout unmatched nodes to the right of positioned nodes
1124
+ if(tmpUnmatchedNodes.length>0&&this._FlowView._LayoutService){this._FlowView._LayoutService.autoLayoutSubset(tmpUnmatchedNodes,tmpMatchedNodes,tmpFlowData.Connections);}// Restore view state (camera position)
1125
+ if(tmpLayout.ViewState){if(typeof tmpLayout.ViewState.PanX==='number'){tmpFlowData.ViewState.PanX=tmpLayout.ViewState.PanX;}if(typeof tmpLayout.ViewState.PanY==='number'){tmpFlowData.ViewState.PanY=tmpLayout.ViewState.PanY;}if(typeof tmpLayout.ViewState.Zoom==='number'){tmpFlowData.ViewState.Zoom=tmpLayout.ViewState.Zoom;}}this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onLayoutRestored',tmpLayout);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',tmpFlowData);}this.log.trace("PictProviderFlowLayouts restored layout '".concat(tmpLayout.Name,"' (").concat(tmpLayout.Hash,")"));return true;}/**
1126
+ * Delete a saved layout by hash.
1127
+ * @param {string} pLayoutHash - The hash of the layout to delete
1128
+ * @returns {boolean} Whether the layout was deleted
1129
+ */},{key:"deleteLayout",value:function deleteLayout(pLayoutHash){var _this27=this;if(!this._FlowView){this.log.warn('PictProviderFlowLayouts deleteLayout: no FlowView reference');return false;}var tmpFlowData=this._FlowView._FlowData;var tmpIndex=tmpFlowData.SavedLayouts.findIndex(function(pLayout){return pLayout.Hash===pLayoutHash;});if(tmpIndex<0){this.log.warn("PictProviderFlowLayouts deleteLayout: layout '".concat(pLayoutHash,"' not found"));return false;}var tmpRemovedLayout=tmpFlowData.SavedLayouts.splice(tmpIndex,1)[0];this._FlowView.marshalFromView();// Persist to storage (with the layout removed)
1130
+ this.storageWrite(tmpFlowData.SavedLayouts,function(pError){if(pError){_this27.log.warn("PictProviderFlowLayouts: failed to persist after delete: ".concat(pError.message));}});if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onLayoutDeleted',tmpRemovedLayout);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',tmpFlowData);}this.log.trace("PictProviderFlowLayouts deleted layout '".concat(tmpRemovedLayout.Name,"' (").concat(tmpRemovedLayout.Hash,")"));return true;}/**
1131
+ * Get the list of saved layouts.
1132
+ * @returns {Array} Array of saved layout objects
1133
+ */},{key:"getLayouts",value:function getLayouts(){if(!this._FlowView)return[];return this._FlowView._FlowData.SavedLayouts;}/**
1134
+ * Get a specific saved layout by hash.
1135
+ * @param {string} pLayoutHash
1136
+ * @returns {Object|null}
1137
+ */},{key:"getLayout",value:function getLayout(pLayoutHash){if(!this._FlowView)return null;return this._FlowView._FlowData.SavedLayouts.find(function(pLayout){return pLayout.Hash===pLayoutHash;})||null;}}]);}(libPictProvider);module.exports=PictProviderFlowLayouts;module.exports.default_configuration=_ProviderConfiguration;},{"pict-provider":8}],22:[function(require,module,exports){var libPictProvider=require('pict-provider');var _DefaultNodeTypes={'default':{Hash:'default',Label:'Default',DefaultWidth:180,DefaultHeight:80,DefaultPorts:[{Hash:null,Direction:'input',Side:'left',Label:'In'},{Hash:null,Direction:'output',Side:'right',Label:'Out'}],TitleBarColor:'#2c3e50',BodyStyle:{}},'start':{Hash:'start',Label:'Start',DefaultWidth:140,DefaultHeight:80,DefaultPorts:[{Hash:null,Direction:'output',Side:'right',Label:'Out'}],TitleBarColor:'#27ae60',BodyStyle:{'fill':'#eafaf1','stroke':'#27ae60'}},'end':{Hash:'end',Label:'End',DefaultWidth:140,DefaultHeight:80,DefaultPorts:[{Hash:null,Direction:'input',Side:'left',Label:'In'}],TitleBarColor:'#1abc9c',BodyStyle:{'fill':'#e8f8f5','stroke':'#1abc9c'}},'halt':{Hash:'halt',Label:'Halt',DefaultWidth:140,DefaultHeight:80,DefaultPorts:[{Hash:null,Direction:'input',Side:'left',Label:'In'}],TitleBarColor:'#e74c3c',BodyStyle:{'fill':'#fdedec','stroke':'#e74c3c'}},'decision':{Hash:'decision',Label:'Decision',DefaultWidth:200,DefaultHeight:100,DefaultPorts:[{Hash:null,Direction:'input',Side:'left',Label:'In'},{Hash:null,Direction:'output',Side:'right',Label:'Yes'},{Hash:null,Direction:'output',Side:'bottom',Label:'No'}],TitleBarColor:'#f39c12',BodyStyle:{'fill':'#fff9e6','stroke':'#f39c12'}}};var _ProviderConfiguration={ProviderIdentifier:'PictProviderFlowNodeTypes'};var PictProviderFlowNodeTypes=/*#__PURE__*/function(_libPictProvider3){function PictProviderFlowNodeTypes(pFable,pOptions,pServiceHash){var _this28;_classCallCheck(this,PictProviderFlowNodeTypes);var tmpOptions=Object.assign({},_ProviderConfiguration,pOptions);_this28=_callSuper(this,PictProviderFlowNodeTypes,[pFable,tmpOptions,pServiceHash]);_this28.serviceType='PictProviderFlowNodeTypes';_this28._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;// Initialize with default node types unless explicitly disabled
1138
+ if(pOptions&&pOptions.IncludeDefaultNodeTypes===false){_this28._NodeTypes={};}else{_this28._NodeTypes=JSON.parse(JSON.stringify(_DefaultNodeTypes));}// Merge any additional node types passed in via options
1139
+ if(pOptions&&pOptions.AdditionalNodeTypes&&_typeof(pOptions.AdditionalNodeTypes)==='object'){var tmpAdditionalKeys=Object.keys(pOptions.AdditionalNodeTypes);for(var i=0;i<tmpAdditionalKeys.length;i++){var tmpOriginal=pOptions.AdditionalNodeTypes[tmpAdditionalKeys[i]];_this28._NodeTypes[tmpAdditionalKeys[i]]=Object.assign({},_this28._NodeTypes[tmpAdditionalKeys[i]]||{},JSON.parse(JSON.stringify(tmpOriginal)));// Preserve BodyContent.RenderCallback (functions are stripped by JSON serialization)
1140
+ if(tmpOriginal.BodyContent&&typeof tmpOriginal.BodyContent.RenderCallback==='function'){if(!_this28._NodeTypes[tmpAdditionalKeys[i]].BodyContent){_this28._NodeTypes[tmpAdditionalKeys[i]].BodyContent={};}_this28._NodeTypes[tmpAdditionalKeys[i]].BodyContent.RenderCallback=tmpOriginal.BodyContent.RenderCallback;}}}return _this28;}/**
1141
+ * Get a node type configuration by hash
1142
+ * @param {string} pTypeHash - The node type hash
1143
+ * @returns {Object|null} The node type configuration
1144
+ */_inherits(PictProviderFlowNodeTypes,_libPictProvider3);return _createClass(PictProviderFlowNodeTypes,[{key:"getNodeType",value:function getNodeType(pTypeHash){return this._NodeTypes[pTypeHash]||this._NodeTypes['default'];}/**
1145
+ * Register a new node type or override an existing one
1146
+ * @param {Object} pNodeTypeConfig - The node type configuration
1147
+ * @returns {boolean}
1148
+ */},{key:"registerNodeType",value:function registerNodeType(pNodeTypeConfig){if(!pNodeTypeConfig||!pNodeTypeConfig.Hash){this.log.warn('PictProviderFlowNodeTypes registerNodeType: invalid config (missing Hash)');return false;}this._NodeTypes[pNodeTypeConfig.Hash]=Object.assign({},this._NodeTypes[pNodeTypeConfig.Hash]||{},pNodeTypeConfig);return true;}/**
1149
+ * Remove a node type
1150
+ * @param {string} pTypeHash
1151
+ * @returns {boolean}
1152
+ */},{key:"removeNodeType",value:function removeNodeType(pTypeHash){if(pTypeHash==='default'){this.log.warn('PictProviderFlowNodeTypes: cannot remove the default node type');return false;}if(this._NodeTypes[pTypeHash]){delete this._NodeTypes[pTypeHash];return true;}return false;}/**
1153
+ * Get all registered node types
1154
+ * @returns {Object} Map of type hash to type configuration
1155
+ */},{key:"getNodeTypes",value:function getNodeTypes(){return JSON.parse(JSON.stringify(this._NodeTypes));}/**
1156
+ * Get a list of node type hashes
1157
+ * @returns {Array<string>}
1158
+ */},{key:"getNodeTypeList",value:function getNodeTypeList(){return Object.keys(this._NodeTypes);}/**
1159
+ * Get all enabled node types that have FlowCard metadata.
1160
+ * Returns only types that are cards and whose Enabled flag is true.
1161
+ * @returns {Array<Object>} Array of node type configurations
1162
+ */},{key:"getEnabledCards",value:function getEnabledCards(){var tmpCards=[];var tmpKeys=Object.keys(this._NodeTypes);for(var i=0;i<tmpKeys.length;i++){var tmpType=this._NodeTypes[tmpKeys[i]];if(tmpType.CardMetadata){if(tmpType.CardMetadata.Enabled!==false){tmpCards.push(JSON.parse(JSON.stringify(tmpType)));}}}return tmpCards;}/**
1163
+ * Get all enabled cards grouped by category.
1164
+ * @returns {Object} Map of category name to array of node type configurations
1165
+ */},{key:"getCardsByCategory",value:function getCardsByCategory(){var tmpCards=this.getEnabledCards();var tmpCategories={};for(var i=0;i<tmpCards.length;i++){var tmpCategory=tmpCards[i].CardMetadata&&tmpCards[i].CardMetadata.Category?tmpCards[i].CardMetadata.Category:'General';if(!tmpCategories[tmpCategory]){tmpCategories[tmpCategory]=[];}tmpCategories[tmpCategory].push(tmpCards[i]);}return tmpCategories;}/**
1166
+ * Check whether a node type hash refers to a FlowCard (has CardMetadata).
1167
+ * @param {string} pTypeHash
1168
+ * @returns {boolean}
1169
+ */},{key:"isFlowCard",value:function isFlowCard(pTypeHash){var tmpType=this._NodeTypes[pTypeHash];return!!(tmpType&&tmpType.CardMetadata);}}]);}(libPictProvider);module.exports=PictProviderFlowNodeTypes;module.exports.default_configuration=_ProviderConfiguration;module.exports.DefaultNodeTypes=_DefaultNodeTypes;},{"pict-provider":8}],23:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');var _ProviderConfiguration={ProviderIdentifier:'PictProviderFlowNoise'};/**
1170
+ * PictProvider-Flow-Noise
1171
+ *
1172
+ * Deterministic noise/jitter generator for hand-drawn visual effects.
1173
+ *
1174
+ * Uses seeded pseudo-random number generation so that the same node or
1175
+ * connection always receives the same jitter values across re-renders,
1176
+ * preventing visual "jumping" while still looking organic.
1177
+ */var PictProviderFlowNoise=/*#__PURE__*/function(_libFableServiceProvi7){function PictProviderFlowNoise(pFable,pOptions,pServiceHash){var _this29;_classCallCheck(this,PictProviderFlowNoise);var tmpOptions=Object.assign({},_ProviderConfiguration,pOptions);_this29=_callSuper(this,PictProviderFlowNoise,[pFable,tmpOptions,pServiceHash]);_this29.serviceType='PictProviderFlowNoise';return _this29;}// ── Hashing / PRNG ────────────────────────────────────────────────────
1178
+ /**
1179
+ * Convert a string to a 32-bit integer hash (djb2 algorithm).
1180
+ * @param {string} pStr
1181
+ * @returns {number}
1182
+ */_inherits(PictProviderFlowNoise,_libFableServiceProvi7);return _createClass(PictProviderFlowNoise,[{key:"hashString",value:function hashString(pStr){var tmpHash=5381;for(var i=0;i<pStr.length;i++){tmpHash=(tmpHash<<5)+tmpHash+pStr.charCodeAt(i);tmpHash=tmpHash&tmpHash;// Convert to 32-bit integer
1183
+ }return tmpHash>>>0;// Ensure unsigned
1184
+ }/**
1185
+ * Create a seeded pseudo-random number generator (Mulberry32).
1186
+ * Returns a function that produces deterministic floats in [0, 1).
1187
+ * @param {number} pSeed - 32-bit integer seed
1188
+ * @returns {Function}
1189
+ */},{key:"seededRandom",value:function seededRandom(pSeed){var tmpSeed=pSeed|0;return function(){tmpSeed=tmpSeed+0x6D2B79F5|0;var t=Math.imul(tmpSeed^tmpSeed>>>15,1|tmpSeed);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296;};}// ── Point Jitter ──────────────────────────────────────────────────────
1190
+ /**
1191
+ * Apply random jitter to a point.
1192
+ * @param {number} pX
1193
+ * @param {number} pY
1194
+ * @param {number} pAmplitude - Maximum offset in pixels
1195
+ * @param {Function} pRNG - Seeded random function
1196
+ * @returns {{x: number, y: number}}
1197
+ */},{key:"jitterPoint",value:function jitterPoint(pX,pY,pAmplitude,pRNG){if(pAmplitude<=0){return{x:pX,y:pY};}return{x:pX+pAmplitude*(pRNG()-0.5)*2,y:pY+pAmplitude*(pRNG()-0.5)*2};}// ── Bracket Path Generation ───────────────────────────────────────────
1198
+ /**
1199
+ * Generate an SVG path `d` string for a bracket-shaped node border.
1200
+ *
1201
+ * Draws true bracket shapes — `[` on the left and `]` on the right —
1202
+ * with NO top/bottom connecting lines. The serifs (horizontal turns)
1203
+ * extend inward from each corner, giving a distinctive hand-drawn
1204
+ * technical-diagram look that is immediately distinguishable from a
1205
+ * regular rectangle at any zoom level.
1206
+ *
1207
+ * The bracket consists of:
1208
+ * - Left bracket `[`: top serif → vertical left side → bottom serif
1209
+ * - Right bracket `]`: top serif → vertical right side → bottom serif
1210
+ * - Optional title divider line across the full width
1211
+ *
1212
+ * @param {number} pWidth - Node width
1213
+ * @param {number} pHeight - Node height
1214
+ * @param {number} pSerifLength - Length of corner serifs in px
1215
+ * @param {number} pTitleBarHeight - Height of title bar (0 to skip divider)
1216
+ * @param {number} pAmplitude - Noise amplitude (0 = precise)
1217
+ * @param {string} pSeedString - Hash string for deterministic noise
1218
+ * @returns {string} SVG path d attribute
1219
+ */},{key:"generateBracketPath",value:function generateBracketPath(pWidth,pHeight,pSerifLength,pTitleBarHeight,pAmplitude,pSeedString){var _this30=this;var tmpRNG=this.seededRandom(this.hashString(pSeedString||'default'));var tmpS=pSerifLength||18;var tmpW=pWidth;var tmpH=pHeight;var tmpJ=function tmpJ(pX,pY){return _this30.jitterPoint(pX,pY,pAmplitude,tmpRNG);};// Left bracket `[`: top serif → down left side → bottom serif
1220
+ var tmpTL_serif=tmpJ(tmpS,0);var tmpTL_corner=tmpJ(0,0);var tmpBL_corner=tmpJ(0,tmpH);var tmpBL_serif=tmpJ(tmpS,tmpH);// Right bracket `]`: top serif → down right side → bottom serif
1221
+ var tmpTR_serif=tmpJ(tmpW-tmpS,0);var tmpTR_corner=tmpJ(tmpW,0);var tmpBR_corner=tmpJ(tmpW,tmpH);var tmpBR_serif=tmpJ(tmpW-tmpS,tmpH);var tmpPath='';// Left bracket `[`
1222
+ tmpPath+="M ".concat(tmpTL_serif.x.toFixed(1)," ").concat(tmpTL_serif.y.toFixed(1));tmpPath+=" L ".concat(tmpTL_corner.x.toFixed(1)," ").concat(tmpTL_corner.y.toFixed(1));tmpPath+=" L ".concat(tmpBL_corner.x.toFixed(1)," ").concat(tmpBL_corner.y.toFixed(1));tmpPath+=" L ".concat(tmpBL_serif.x.toFixed(1)," ").concat(tmpBL_serif.y.toFixed(1));// Right bracket `]`
1223
+ tmpPath+=" M ".concat(tmpTR_serif.x.toFixed(1)," ").concat(tmpTR_serif.y.toFixed(1));tmpPath+=" L ".concat(tmpTR_corner.x.toFixed(1)," ").concat(tmpTR_corner.y.toFixed(1));tmpPath+=" L ".concat(tmpBR_corner.x.toFixed(1)," ").concat(tmpBR_corner.y.toFixed(1));tmpPath+=" L ".concat(tmpBR_serif.x.toFixed(1)," ").concat(tmpBR_serif.y.toFixed(1));// No horizontal lines — the title bar fill rect provides visual
1224
+ // separation via its background color. The bracket outline is
1225
+ // purely the `[` and `]` shapes on the sides.
1226
+ return tmpPath;}// ── Path Jitter (for connections) ─────────────────────────────────────
1227
+ /**
1228
+ * Apply jitter to an existing SVG path string by offsetting coordinate
1229
+ * pairs. The first M and last coordinate pair receive reduced jitter
1230
+ * to keep connections aligned with their port anchors.
1231
+ *
1232
+ * @param {string} pPathString - SVG path d attribute
1233
+ * @param {number} pAmplitude - Noise amplitude (0 = no change)
1234
+ * @param {string} pSeedString - Hash string for deterministic noise
1235
+ * @returns {string} Modified path string
1236
+ */},{key:"jitterPath",value:function jitterPath(pPathString,pAmplitude,pSeedString){if(pAmplitude<=0||!pPathString){return pPathString;}var tmpRNG=this.seededRandom(this.hashString(pSeedString||'path'));// Parse path into tokens: commands and numbers
1237
+ var tmpTokens=pPathString.match(/[MLCQZmlcqz]|[-+]?[0-9]*\.?[0-9]+/g);if(!tmpTokens){return pPathString;}// Collect all numeric coordinate indices
1238
+ var tmpNumericIndices=[];for(var i=0;i<tmpTokens.length;i++){if(/^[-+]?[0-9]*\.?[0-9]+$/.test(tmpTokens[i])){tmpNumericIndices.push(i);}}// Process pairs of coordinates (x, y)
1239
+ for(var _i29=0;_i29<tmpNumericIndices.length-1;_i29+=2){var tmpXIdx=tmpNumericIndices[_i29];var tmpYIdx=tmpNumericIndices[_i29+1];// Reduce jitter for first and last coordinate pairs (port anchors)
1240
+ var tmpLocalAmplitude=pAmplitude;if(_i29===0||_i29>=tmpNumericIndices.length-2){tmpLocalAmplitude=pAmplitude*0.15;// Minimal anchor jitter
1241
+ }else if(_i29===2||_i29>=tmpNumericIndices.length-4){tmpLocalAmplitude=pAmplitude*0.5;// Reduced near anchors
1242
+ }var tmpX=parseFloat(tmpTokens[tmpXIdx]);var tmpY=parseFloat(tmpTokens[tmpYIdx]);var tmpJittered=this.jitterPoint(tmpX,tmpY,tmpLocalAmplitude,tmpRNG);tmpTokens[tmpXIdx]=tmpJittered.x.toFixed(1);tmpTokens[tmpYIdx]=tmpJittered.y.toFixed(1);}// Reassemble path string with spaces
1243
+ var tmpResult='';for(var _i30=0;_i30<tmpTokens.length;_i30++){if(_i30>0&&/^[MLCQZmlcqz]$/.test(tmpTokens[_i30])){tmpResult+=' '+tmpTokens[_i30];}else if(_i30>0){tmpResult+=' '+tmpTokens[_i30];}else{tmpResult+=tmpTokens[_i30];}}return tmpResult;}}]);}(libFableServiceProviderBase);module.exports=PictProviderFlowNoise;module.exports.default_configuration=_ProviderConfiguration;},{"fable-serviceproviderbase":4}],24:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1244
+ * PictProvider-Flow-PanelChrome
1245
+ *
1246
+ * Template-based provider for creating the panel chrome (the foreignObject
1247
+ * wrapper, title bar, close button, and body container) for properties panels.
1248
+ *
1249
+ * Replaces the raw DOM API approach with a configuration template
1250
+ * (Flow-PanelChrome-Template) registered in the FlowView's template set.
1251
+ */var PictProviderFlowPanelChrome=/*#__PURE__*/function(_libFableServiceProvi8){function PictProviderFlowPanelChrome(pFable,pOptions,pServiceHash){var _this31;_classCallCheck(this,PictProviderFlowPanelChrome);_this31=_callSuper(this,PictProviderFlowPanelChrome,[pFable,pOptions,pServiceHash]);_this31.serviceType='PictProviderFlowPanelChrome';_this31._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this31;}/**
1252
+ * Create a foreignObject containing the panel chrome and empty body container.
1253
+ *
1254
+ * Uses the Flow-PanelChrome-Template registered in the FlowView configuration
1255
+ * to render the inner HTML (title bar, close button, body container), then
1256
+ * attaches event isolation listeners so pointer and wheel events inside the
1257
+ * panel body do not propagate to the SVG interaction layer.
1258
+ *
1259
+ * @param {Object} pPanelData - Panel data from OpenPanels (Hash, NodeHash, X, Y, Width, Height, Title)
1260
+ * @param {SVGGElement} pPanelsLayer - The SVG <g> for panel foreignObjects
1261
+ * @returns {HTMLDivElement} The panel body container element for content rendering
1262
+ */_inherits(PictProviderFlowPanelChrome,_libFableServiceProvi8);return _createClass(PictProviderFlowPanelChrome,[{key:"createPanelForeignObject",value:function createPanelForeignObject(pPanelData,pPanelsLayer){var tmpSVGHelper=this._FlowView._SVGHelperProvider;// Create the SVG foreignObject wrapper
1263
+ var tmpFO=tmpSVGHelper.createSVGElement('foreignObject');tmpFO.setAttribute('class','pict-flow-panel-foreign-object');tmpFO.setAttribute('data-panel-hash',pPanelData.Hash);tmpFO.setAttribute('data-node-hash',pPanelData.NodeHash);tmpFO.setAttribute('x',String(pPanelData.X));tmpFO.setAttribute('y',String(pPanelData.Y));tmpFO.setAttribute('width',String(pPanelData.Width));tmpFO.setAttribute('height',String(pPanelData.Height));// Render the panel chrome from the configuration template
1264
+ var tmpPict=this._FlowView.pict||this._FlowView.fable;var tmpTitle=pPanelData.Title||'Properties';var tmpChromeHTML=tmpPict.parseTemplateByHash('Flow-PanelChrome-Template',{Hash:pPanelData.Hash,Title:tmpTitle});tmpFO.innerHTML=tmpChromeHTML;// Populate the close button icon
1265
+ var tmpCloseIcon=tmpFO.querySelector('.pict-flow-panel-close-icon');if(tmpCloseIcon&&this._FlowView&&this._FlowView._IconProvider){tmpCloseIcon.innerHTML=this._FlowView._IconProvider.getIconSVGMarkup('close',12);}else if(tmpCloseIcon){tmpCloseIcon.textContent="\u2715";}// Attach event isolation to the scrollable content area so
1266
+ // pointer/wheel events inside the panel do not trigger SVG interactions
1267
+ var tmpContent=tmpFO.querySelector('.pict-flow-panel-content');if(tmpContent){tmpContent.addEventListener('pointerdown',function(pEvent){pEvent.stopPropagation();});tmpContent.addEventListener('wheel',function(pEvent){pEvent.stopPropagation();});}// Isolate events on the tab bar
1268
+ var tmpTabbar=tmpFO.querySelector('.pict-flow-panel-tabbar');if(tmpTabbar){tmpTabbar.addEventListener('pointerdown',function(pEvent){pEvent.stopPropagation();});tmpTabbar.addEventListener('wheel',function(pEvent){pEvent.stopPropagation();});}pPanelsLayer.appendChild(tmpFO);// Return the properties tab pane as the body container for content rendering
1269
+ var tmpPropertiesPane=tmpFO.querySelector('.pict-flow-panel-tab-pane[data-tab="properties"]');return tmpPropertiesPane;}}]);}(libFableServiceProviderBase);module.exports=PictProviderFlowPanelChrome;},{"fable-serviceproviderbase":4}],25:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1270
+ * PictProvider-Flow-SVGHelpers
1271
+ *
1272
+ * Shared SVG element creation utility used by all flow components
1273
+ * that need to create SVG namespace elements (nodes, connections, tethers).
1274
+ */var PictProviderFlowSVGHelpers=/*#__PURE__*/function(_libFableServiceProvi9){function PictProviderFlowSVGHelpers(pFable,pOptions,pServiceHash){var _this32;_classCallCheck(this,PictProviderFlowSVGHelpers);_this32=_callSuper(this,PictProviderFlowSVGHelpers,[pFable,pOptions,pServiceHash]);_this32.serviceType='PictProviderFlowSVGHelpers';return _this32;}/**
1275
+ * Create an SVG namespace element.
1276
+ *
1277
+ * @param {string} pTagName - The SVG element tag name (e.g., 'path', 'circle', 'g', 'rect', 'text')
1278
+ * @returns {SVGElement}
1279
+ */_inherits(PictProviderFlowSVGHelpers,_libFableServiceProvi9);return _createClass(PictProviderFlowSVGHelpers,[{key:"createSVGElement",value:function createSVGElement(pTagName){return document.createElementNS('http://www.w3.org/2000/svg',pTagName);}}]);}(libFableServiceProviderBase);module.exports=PictProviderFlowSVGHelpers;},{"fable-serviceproviderbase":4}],26:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');var _ProviderConfiguration={ProviderIdentifier:'PictProviderFlowTheme'};/**
1280
+ * PictProvider-Flow-Theme
1281
+ *
1282
+ * Central orchestrator for the flow diagram theming system.
1283
+ *
1284
+ * Holds a registry of theme definitions, manages the active theme,
1285
+ * and provides hooks for node body rendering and path noise processing.
1286
+ *
1287
+ * ## Usage
1288
+ *
1289
+ * ```javascript
1290
+ * flowView.setTheme('sketch'); // Switch to hand-drawn style
1291
+ * flowView.setNoiseLevel(0.6); // Increase bracket/connection wobble
1292
+ * flowView.setTheme('default'); // Restore modern style
1293
+ * ```
1294
+ *
1295
+ * ## Custom Themes
1296
+ *
1297
+ * ```javascript
1298
+ * flowView._ThemeProvider.registerTheme('custom', {
1299
+ * Key: 'custom',
1300
+ * Label: 'My Custom Theme',
1301
+ * CSSVariables: { '--pf-canvas-bg': '#222' },
1302
+ * NodeBodyMode: 'rect',
1303
+ * NoiseConfig: { Enabled: false }
1304
+ * });
1305
+ * flowView.setTheme('custom');
1306
+ * ```
1307
+ */var PictProviderFlowTheme=/*#__PURE__*/function(_libFableServiceProvi0){function PictProviderFlowTheme(pFable,pOptions,pServiceHash){var _this33;_classCallCheck(this,PictProviderFlowTheme);var tmpOptions=Object.assign({},_ProviderConfiguration,pOptions);_this33=_callSuper(this,PictProviderFlowTheme,[pFable,tmpOptions,pServiceHash]);_this33.serviceType='PictProviderFlowTheme';_this33._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;_this33._ActiveThemeKey='default';_this33._NoiseLevel=0;_this33._Themes={};_this33._registerBuiltInThemes();return _this33;}// ── Theme Registry ────────────────────────────────────────────────────
1308
+ _inherits(PictProviderFlowTheme,_libFableServiceProvi0);return _createClass(PictProviderFlowTheme,[{key:"_registerBuiltInThemes",value:function _registerBuiltInThemes(){// ── 1. Default (Modern) ──────────────────────────────────────
1309
+ this._Themes['default']={Key:'default',Label:'Modern',CSSVariables:{},AdditionalCSS:'',NodeBodyMode:'rect',BracketConfig:null,ConnectionConfig:{StrokeDashArray:null,StrokeWidth:2,ArrowheadStyle:'triangle'},NoiseConfig:{Enabled:false,DefaultLevel:0,MaxJitterPx:0,AffectsNodes:false,AffectsConnections:false},ShapeOverrides:{}};// ── 2. Sketch (Hand-drawn) ───────────────────────────────────
1310
+ this._Themes['sketch']={Key:'sketch',Label:'Sketch',CSSVariables:{'--pf-node-body-fill':'#fffef5','--pf-node-body-stroke':'#444444','--pf-node-body-stroke-width':'1.5','--pf-node-body-radius':'0px','--pf-node-shadow':'none','--pf-node-shadow-hover':'none','--pf-node-shadow-selected':'none','--pf-node-shadow-dragging':'none','--pf-node-title-fill':'#333333','--pf-node-title-size':'12px','--pf-node-title-weight':'400','--pf-node-title-bar-color':'#f0ece0','--pf-node-type-label-fill':'#888888','--pf-node-selected-stroke':'#2255aa','--pf-port-input-fill':'#5577bb','--pf-port-output-fill':'#55aa77','--pf-port-stroke':'#fffef5','--pf-connection-stroke':'#555555','--pf-connection-selected-stroke':'#2255aa','--pf-canvas-bg':'#fffef5','--pf-grid-stroke':'#e8e4d8','--pf-panel-bg':'#fffef5','--pf-panel-border':'#ccccaa','--pf-panel-radius':'0px','--pf-panel-shadow':'2px 2px 0px rgba(0,0,0,0.08)','--pf-panel-titlebar-bg':'#f0ece0','--pf-panel-titlebar-border':'#ccccaa','--pf-panel-title-color':'#333333'},AdditionalCSS:"\n\t\t\t\t.pict-flow-node-title,\n\t\t\t\t.pict-flow-node-type-label,\n\t\t\t\t.pict-flow-port-label,\n\t\t\t\t.pict-flow-node-card-code {\n\t\t\t\t\tfont-family: \"Courier New\", \"Courier\", monospace !important;\n\t\t\t\t}\n\t\t\t\t.pict-flow-panel-title-text,\n\t\t\t\t.pict-flow-panel-node-props-title,\n\t\t\t\t.pict-flow-info-panel {\n\t\t\t\t\tfont-family: \"Courier New\", \"Courier\", monospace !important;\n\t\t\t\t}\n\t\t\t\t.pict-flow-node-title-icon {\n\t\t\t\t\tfilter: brightness(0) !important;\n\t\t\t\t}\n\t\t\t",NodeBodyMode:'bracket',BracketConfig:{SerifLength:20,TitleSeparator:true},ConnectionConfig:{StrokeDashArray:null,StrokeWidth:1.5,ArrowheadStyle:'triangle'},NoiseConfig:{Enabled:true,DefaultLevel:0.4,MaxJitterPx:4,AffectsNodes:true,AffectsConnections:true},ShapeOverrides:{'arrowhead-connection':{Fill:'#555555'},'arrowhead-connection-selected':{Fill:'#2255aa'}}};// ── 3. Blueprint (Technical) ─────────────────────────────────
1311
+ this._Themes['blueprint']={Key:'blueprint',Label:'Blueprint',CSSVariables:{'--pf-node-body-fill':'rgba(255,255,255,0.05)','--pf-node-body-stroke':'#ffffff','--pf-node-body-stroke-width':'1','--pf-node-body-radius':'0px','--pf-node-shadow':'none','--pf-node-shadow-hover':'none','--pf-node-shadow-selected':'none','--pf-node-shadow-dragging':'none','--pf-node-title-fill':'#ffffff','--pf-node-title-size':'11px','--pf-node-title-weight':'400','--pf-node-title-bar-color':'rgba(255,255,255,0.1)','--pf-node-type-label-fill':'rgba(255,255,255,0.5)','--pf-node-selected-stroke':'#ffdd44','--pf-port-input-fill':'#88bbff','--pf-port-output-fill':'#88ffbb','--pf-port-stroke':'#1a3a6a','--pf-connection-stroke':'rgba(255,255,255,0.6)','--pf-connection-selected-stroke':'#ffdd44','--pf-canvas-bg':'#1a3a6a','--pf-grid-stroke':'rgba(255,255,255,0.08)','--pf-panel-bg':'#1a3a6a','--pf-panel-border':'rgba(255,255,255,0.3)','--pf-panel-radius':'0px','--pf-panel-shadow':'none','--pf-panel-titlebar-bg':'rgba(255,255,255,0.05)','--pf-panel-titlebar-border':'rgba(255,255,255,0.15)','--pf-panel-title-color':'#ffffff'},AdditionalCSS:"\n\t\t\t\t.pict-flow-node-title,\n\t\t\t\t.pict-flow-node-type-label,\n\t\t\t\t.pict-flow-port-label,\n\t\t\t\t.pict-flow-node-card-code {\n\t\t\t\t\tfont-family: \"Courier New\", monospace !important;\n\t\t\t\t\ttext-transform: uppercase;\n\t\t\t\t\tletter-spacing: 1px;\n\t\t\t\t}\n\t\t\t\t.pict-flow-container {\n\t\t\t\t\tborder-color: #0d2244;\n\t\t\t\t}\n\t\t\t\t.pict-flow-node-title-icon {\n\t\t\t\t\tfilter: brightness(0) invert(1) !important;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar {\n\t\t\t\t\tbackground-color: #142e54;\n\t\t\t\t\tborder-bottom-color: rgba(255,255,255,0.15);\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar-btn {\n\t\t\t\t\tbackground-color: rgba(255,255,255,0.05);\n\t\t\t\t\tborder-color: rgba(255,255,255,0.2);\n\t\t\t\t\tcolor: #ffffff;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar-btn:hover {\n\t\t\t\t\tbackground-color: rgba(255,255,255,0.1);\n\t\t\t\t}\n\t\t\t",NodeBodyMode:'bracket',BracketConfig:{SerifLength:18,TitleSeparator:true},ConnectionConfig:{StrokeDashArray:'8 4',StrokeWidth:1,ArrowheadStyle:'triangle'},NoiseConfig:{Enabled:false,DefaultLevel:0,MaxJitterPx:0,AffectsNodes:false,AffectsConnections:false},ShapeOverrides:{'arrowhead-connection':{Fill:'rgba(255,255,255,0.6)'},'arrowhead-connection-selected':{Fill:'#ffdd44'}}};// ── 4. Mono (Black & White) ──────────────────────────────────
1312
+ this._Themes['mono']={Key:'mono',Label:'Monochrome',CSSVariables:{'--pf-node-body-fill':'#ffffff','--pf-node-body-stroke':'#000000','--pf-node-body-stroke-width':'1','--pf-node-body-radius':'0px','--pf-node-shadow':'none','--pf-node-shadow-hover':'none','--pf-node-shadow-selected':'none','--pf-node-shadow-dragging':'none','--pf-node-title-fill':'#ffffff','--pf-node-title-size':'11px','--pf-node-title-weight':'600','--pf-node-title-bar-color':'#000000','--pf-node-type-label-fill':'#888888','--pf-node-selected-stroke':'#444444','--pf-port-input-fill':'#000000','--pf-port-output-fill':'#666666','--pf-port-stroke':'#ffffff','--pf-connection-stroke':'#000000','--pf-connection-selected-stroke':'#444444','--pf-canvas-bg':'#ffffff','--pf-grid-stroke':'#eeeeee','--pf-panel-bg':'#ffffff','--pf-panel-border':'#000000','--pf-panel-radius':'0px','--pf-panel-shadow':'none','--pf-panel-titlebar-bg':'#f0f0f0','--pf-panel-titlebar-border':'#000000','--pf-panel-title-color':'#000000'},AdditionalCSS:"\n\t\t\t\t.pict-flow-node-title {\n\t\t\t\t\tfont-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif !important;\n\t\t\t\t}\n\t\t\t\t.pict-flow-node-title-icon {\n\t\t\t\t\tfilter: brightness(0) invert(1) !important;\n\t\t\t\t}\n\t\t\t",NodeBodyMode:'rect',BracketConfig:null,ConnectionConfig:{StrokeDashArray:null,StrokeWidth:1,ArrowheadStyle:'triangle'},NoiseConfig:{Enabled:false,DefaultLevel:0,MaxJitterPx:0,AffectsNodes:false,AffectsConnections:false},ShapeOverrides:{'arrowhead-connection':{Fill:'#000000'},'arrowhead-connection-selected':{Fill:'#444444'}}};// ── 5. Retro 80s (Neon) ──────────────────────────────────────
1313
+ this._Themes['retro-80s']={Key:'retro-80s',Label:'80s Retro',CSSVariables:{'--pf-node-body-fill':'#1a0a2e','--pf-node-body-stroke':'#ff00ff','--pf-node-body-stroke-width':'2','--pf-node-body-radius':'0px','--pf-node-shadow':'drop-shadow(0 0 8px rgba(255,0,255,0.4))','--pf-node-shadow-hover':'drop-shadow(0 0 12px rgba(255,0,255,0.6))','--pf-node-shadow-selected':'drop-shadow(0 0 16px rgba(0,255,255,0.5))','--pf-node-shadow-dragging':'drop-shadow(0 0 20px rgba(255,0,255,0.7))','--pf-node-title-fill':'#00ffff','--pf-node-title-size':'11px','--pf-node-title-weight':'700','--pf-node-title-bar-color':'#2a0a4e','--pf-node-type-label-fill':'#ff66ff','--pf-node-selected-stroke':'#00ffff','--pf-port-input-fill':'#ff00ff','--pf-port-output-fill':'#00ff66','--pf-port-stroke':'#1a0a2e','--pf-connection-stroke':'#ff00ff','--pf-connection-selected-stroke':'#00ffff','--pf-canvas-bg':'#0a0015','--pf-grid-stroke':'#1a0a2e','--pf-panel-bg':'#1a0a2e','--pf-panel-border':'#ff00ff','--pf-panel-radius':'0px','--pf-panel-shadow':'0 0 20px rgba(255,0,255,0.3)','--pf-panel-titlebar-bg':'#2a0a4e','--pf-panel-titlebar-border':'#ff00ff','--pf-panel-title-color':'#00ffff'},AdditionalCSS:"\n\t\t\t\t.pict-flow-node-title,\n\t\t\t\t.pict-flow-node-type-label,\n\t\t\t\t.pict-flow-port-label,\n\t\t\t\t.pict-flow-node-card-code {\n\t\t\t\t\tfont-family: \"Courier New\", monospace !important;\n\t\t\t\t\ttext-transform: uppercase;\n\t\t\t\t\tletter-spacing: 0.5px;\n\t\t\t\t}\n\t\t\t\t.pict-flow-connection {\n\t\t\t\t\tfilter: drop-shadow(0 0 3px rgba(255,0,255,0.4));\n\t\t\t\t}\n\t\t\t\t.pict-flow-node-title-icon {\n\t\t\t\t\tfilter: brightness(0) invert(1) hue-rotate(180deg) !important;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar {\n\t\t\t\t\tbackground-color: #1a0a2e;\n\t\t\t\t\tborder-bottom-color: #ff00ff;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar-btn {\n\t\t\t\t\tbackground-color: #1a0a2e;\n\t\t\t\t\tborder-color: #ff00ff;\n\t\t\t\t\tcolor: #00ffff;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar-btn:hover {\n\t\t\t\t\tbackground-color: #2a0a4e;\n\t\t\t\t}\n\t\t\t\t.pict-flow-container {\n\t\t\t\t\tborder-color: #ff00ff;\n\t\t\t\t}\n\t\t\t",NodeBodyMode:'rect',BracketConfig:null,ConnectionConfig:{StrokeDashArray:null,StrokeWidth:2,ArrowheadStyle:'triangle'},NoiseConfig:{Enabled:false,DefaultLevel:0,MaxJitterPx:0,AffectsNodes:false,AffectsConnections:false},ShapeOverrides:{'arrowhead-connection':{Fill:'#ff00ff'},'arrowhead-connection-selected':{Fill:'#00ffff'}}};// ── 6. Retro 90s (Windows) ───────────────────────────────────
1314
+ this._Themes['retro-90s']={Key:'retro-90s',Label:'90s Retro',CSSVariables:{'--pf-node-body-fill':'#c0c0c0','--pf-node-body-stroke':'#808080','--pf-node-body-stroke-width':'1','--pf-node-body-radius':'0px','--pf-node-shadow':'drop-shadow(2px 2px 0px #404040)','--pf-node-shadow-hover':'drop-shadow(3px 3px 0px #404040)','--pf-node-shadow-selected':'drop-shadow(2px 2px 0px #008080)','--pf-node-shadow-dragging':'drop-shadow(4px 4px 0px #404040)','--pf-node-title-fill':'#ffffff','--pf-node-title-size':'11px','--pf-node-title-weight':'700','--pf-node-title-bar-color':'#000080','--pf-node-type-label-fill':'#606060','--pf-node-selected-stroke':'#008080','--pf-port-input-fill':'#000080','--pf-port-output-fill':'#008000','--pf-port-stroke':'#c0c0c0','--pf-connection-stroke':'#808080','--pf-connection-selected-stroke':'#008080','--pf-canvas-bg':'#008080','--pf-grid-stroke':'rgba(0,0,0,0.06)','--pf-panel-bg':'#c0c0c0','--pf-panel-border':'#808080','--pf-panel-radius':'0px','--pf-panel-shadow':'2px 2px 0px #404040','--pf-panel-titlebar-bg':'#000080','--pf-panel-titlebar-border':'#c0c0c0','--pf-panel-title-color':'#ffffff'},AdditionalCSS:"\n\t\t\t\t.pict-flow-node-title,\n\t\t\t\t.pict-flow-node-type-label,\n\t\t\t\t.pict-flow-port-label,\n\t\t\t\t.pict-flow-node-card-code {\n\t\t\t\t\tfont-family: \"MS Sans Serif\", \"Arial\", sans-serif !important;\n\t\t\t\t}\n\t\t\t\t.pict-flow-node-title-icon {\n\t\t\t\t\tfilter: brightness(0) invert(1) !important;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar {\n\t\t\t\t\tbackground-color: #c0c0c0;\n\t\t\t\t\tborder-bottom: 2px solid #808080;\n\t\t\t\t\tborder-top: 1px solid #ffffff;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar-btn {\n\t\t\t\t\tbackground-color: #c0c0c0;\n\t\t\t\t\tborder: 2px outset #c0c0c0;\n\t\t\t\t\tborder-radius: 0;\n\t\t\t\t\tcolor: #000000;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar-btn:hover {\n\t\t\t\t\tbackground-color: #d0d0d0;\n\t\t\t\t}\n\t\t\t\t.pict-flow-toolbar-btn:active {\n\t\t\t\t\tborder-style: inset;\n\t\t\t\t}\n\t\t\t\t.pict-flow-container {\n\t\t\t\t\tborder: 2px outset #c0c0c0;\n\t\t\t\t\tborder-radius: 0;\n\t\t\t\t}\n\t\t\t",NodeBodyMode:'rect',BracketConfig:null,ConnectionConfig:{StrokeDashArray:null,StrokeWidth:2,ArrowheadStyle:'triangle'},NoiseConfig:{Enabled:false,DefaultLevel:0,MaxJitterPx:0,AffectsNodes:false,AffectsConnections:false},ShapeOverrides:{'arrowhead-connection':{Fill:'#808080'},'arrowhead-connection-selected':{Fill:'#008080'}}};// ── 7. Whiteboard (Minimal brackets, no fills) ──────────────
1315
+ this._Themes['whiteboard']={Key:'whiteboard',Label:'Whiteboard',CSSVariables:{'--pf-node-body-fill':'transparent','--pf-node-body-stroke':'#555555','--pf-node-body-stroke-width':'2','--pf-node-body-radius':'0px','--pf-node-shadow':'none','--pf-node-shadow-hover':'none','--pf-node-shadow-selected':'none','--pf-node-shadow-dragging':'none','--pf-node-title-fill':'#333333','--pf-node-title-size':'12px','--pf-node-title-weight':'600','--pf-node-title-bar-color':'transparent','--pf-node-type-label-fill':'#999999','--pf-node-selected-stroke':'#2255aa','--pf-port-input-fill':'#5577bb','--pf-port-output-fill':'#55aa77','--pf-port-stroke':'#ffffff','--pf-connection-stroke':'#888888','--pf-connection-selected-stroke':'#2255aa','--pf-canvas-bg':'#ffffff','--pf-grid-stroke':'#f0f0f0','--pf-panel-bg':'#ffffff','--pf-panel-border':'#cccccc','--pf-panel-radius':'0px','--pf-panel-shadow':'2px 2px 0px rgba(0,0,0,0.06)','--pf-panel-titlebar-bg':'#f8f8f8','--pf-panel-titlebar-border':'#e0e0e0','--pf-panel-title-color':'#333333'},AdditionalCSS:"\n\t\t\t\t.pict-flow-node-title,\n\t\t\t\t.pict-flow-node-type-label,\n\t\t\t\t.pict-flow-port-label,\n\t\t\t\t.pict-flow-node-card-code {\n\t\t\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif !important;\n\t\t\t\t}\n\t\t\t\t/* Node-type bracket colors \u2014 each type gets its own bracket color */\n\t\t\t\t.pict-flow-node-start .pict-flow-node-bracket { stroke: #27ae60; }\n\t\t\t\t.pict-flow-node-end .pict-flow-node-bracket { stroke: #1abc9c; }\n\t\t\t\t.pict-flow-node-halt .pict-flow-node-bracket { stroke: #e74c3c; }\n\t\t\t\t.pict-flow-node-decision .pict-flow-node-bracket { stroke: #f39c12; }\n\t\t\t\t.pict-flow-node-default .pict-flow-node-bracket { stroke: #3498db; }\n\t\t\t\t.pict-flow-node-action .pict-flow-node-bracket { stroke: #2c3e50; }\n\t\t\t\t/* Override variant rules: no fills/strokes on body rects in whiteboard */\n\t\t\t\t.pict-flow-node-decision .pict-flow-node-body,\n\t\t\t\t.pict-flow-node-start .pict-flow-node-body,\n\t\t\t\t.pict-flow-node-end .pict-flow-node-body,\n\t\t\t\t.pict-flow-node-halt .pict-flow-node-body {\n\t\t\t\t\tfill: transparent;\n\t\t\t\t\tstroke: transparent;\n\t\t\t\t\tstroke-width: 0;\n\t\t\t\t}\n\t\t\t\t/* Title bar fills transparent too */\n\t\t\t\t.pict-flow-node .pict-flow-node-bracket-title-fill {\n\t\t\t\t\tfill: transparent !important;\n\t\t\t\t}\n\t\t\t\t.pict-flow-node-title-icon {\n\t\t\t\t\tfilter: none !important;\n\t\t\t\t}\n\t\t\t",NodeBodyMode:'bracket',BracketConfig:{SerifLength:22,TitleSeparator:false},ConnectionConfig:{StrokeDashArray:null,StrokeWidth:1.5,ArrowheadStyle:'triangle'},NoiseConfig:{Enabled:true,DefaultLevel:0.3,MaxJitterPx:3,AffectsNodes:true,AffectsConnections:true},ShapeOverrides:{'arrowhead-connection':{Fill:'#888888'},'arrowhead-connection-selected':{Fill:'#2255aa'}}};}// ── Public API ────────────────────────────────────────────────────────
1316
+ /**
1317
+ * Get the active theme definition.
1318
+ * @returns {Object}
1319
+ */},{key:"getActiveTheme",value:function getActiveTheme(){return this._Themes[this._ActiveThemeKey]||this._Themes['default'];}/**
1320
+ * Get the active theme key.
1321
+ * @returns {string}
1322
+ */},{key:"getActiveThemeKey",value:function getActiveThemeKey(){return this._ActiveThemeKey;}/**
1323
+ * Switch the active theme.
1324
+ * This updates the internal key and applies shape overrides.
1325
+ * The caller (FlowView.setTheme) is responsible for re-registering
1326
+ * CSS and triggering a full re-render.
1327
+ *
1328
+ * @param {string} pThemeKey
1329
+ * @returns {boolean} Whether the theme was found and applied
1330
+ */},{key:"setTheme",value:function setTheme(pThemeKey){if(!this._Themes[pThemeKey]){this.log.warn("PictProviderFlowTheme: theme '".concat(pThemeKey,"' not found"));return false;}this._ActiveThemeKey=pThemeKey;var tmpTheme=this._Themes[pThemeKey];// Apply noise defaults from theme
1331
+ if(tmpTheme.NoiseConfig&&typeof tmpTheme.NoiseConfig.DefaultLevel==='number'){this._NoiseLevel=tmpTheme.NoiseConfig.DefaultLevel;}else{this._NoiseLevel=0;}// Apply shape overrides
1332
+ if(this._FlowView&&this._FlowView._ConnectorShapesProvider){this._FlowView._ConnectorShapesProvider.resetToDefaults();if(tmpTheme.ShapeOverrides&&Object.keys(tmpTheme.ShapeOverrides).length>0){this._FlowView._ConnectorShapesProvider.applyThemeOverrides(tmpTheme.ShapeOverrides);}}this.log.trace("PictProviderFlowTheme: switched to '".concat(pThemeKey,"'"));return true;}/**
1333
+ * Get the current noise level (0 to 1).
1334
+ * @returns {number}
1335
+ */},{key:"getNoiseLevel",value:function getNoiseLevel(){return this._NoiseLevel;}/**
1336
+ * Set the noise level (0 to 1).
1337
+ * @param {number} pLevel
1338
+ */},{key:"setNoiseLevel",value:function setNoiseLevel(pLevel){this._NoiseLevel=Math.max(0,Math.min(1,pLevel||0));}/**
1339
+ * Register a custom theme.
1340
+ * @param {string} pKey
1341
+ * @param {Object} pThemeDefinition
1342
+ */},{key:"registerTheme",value:function registerTheme(pKey,pThemeDefinition){if(!pKey||!pThemeDefinition){this.log.warn('PictProviderFlowTheme: registerTheme requires key and definition');return;}pThemeDefinition.Key=pKey;this._Themes[pKey]=pThemeDefinition;}/**
1343
+ * Get all registered theme keys.
1344
+ * @returns {Array<string>}
1345
+ */},{key:"getThemeKeys",value:function getThemeKeys(){return Object.keys(this._Themes);}// ── Rendering Hooks ───────────────────────────────────────────────────
1346
+ /**
1347
+ * Post-process an SVG path string to apply noise/jitter if the
1348
+ * active theme has noise enabled for connections.
1349
+ *
1350
+ * @param {string} pPathString - SVG path d attribute
1351
+ * @param {string} pSeedString - Hash for deterministic noise
1352
+ * @returns {string} Possibly-modified path string
1353
+ */},{key:"processPathString",value:function processPathString(pPathString,pSeedString){var tmpTheme=this.getActiveTheme();if(!tmpTheme||!tmpTheme.NoiseConfig||!tmpTheme.NoiseConfig.Enabled||!tmpTheme.NoiseConfig.AffectsConnections){return pPathString;}var tmpAmplitude=this._NoiseLevel*(tmpTheme.NoiseConfig.MaxJitterPx||3);if(tmpAmplitude<=0){return pPathString;}if(this._FlowView&&this._FlowView._NoiseProvider){return this._FlowView._NoiseProvider.jitterPath(pPathString,tmpAmplitude,pSeedString);}return pPathString;}/**
1354
+ * Get the noise amplitude for node bracket rendering.
1355
+ * Returns 0 if noise is not enabled for nodes in the active theme.
1356
+ * @returns {number}
1357
+ */},{key:"getNodeNoiseAmplitude",value:function getNodeNoiseAmplitude(){var tmpTheme=this.getActiveTheme();if(!tmpTheme||!tmpTheme.NoiseConfig||!tmpTheme.NoiseConfig.Enabled||!tmpTheme.NoiseConfig.AffectsNodes){return 0;}return this._NoiseLevel*(tmpTheme.NoiseConfig.MaxJitterPx||3);}}]);}(libFableServiceProviderBase);module.exports=PictProviderFlowTheme;module.exports.default_configuration=_ProviderConfiguration;},{"fable-serviceproviderbase":4}],27:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1358
+ * PictService-Flow-ConnectionHandleManager
1359
+ *
1360
+ * Manages connection handle lifecycle: dragging, adding, removing,
1361
+ * and resetting bezier/orthogonal handles on connections and tethers.
1362
+ *
1363
+ * Extracted from PictView-Flow.js to isolate handle CRUD operations
1364
+ * from the main view.
1365
+ */var PictServiceFlowConnectionHandleManager=/*#__PURE__*/function(_libFableServiceProvi1){function PictServiceFlowConnectionHandleManager(pFable,pOptions,pServiceHash){var _this34;_classCallCheck(this,PictServiceFlowConnectionHandleManager);_this34=_callSuper(this,PictServiceFlowConnectionHandleManager,[pFable,pOptions,pServiceHash]);_this34.serviceType='PictServiceFlowConnectionHandleManager';_this34._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this34;}/**
1366
+ * Update a connection handle position during drag (for real-time feedback).
1367
+ * @param {string} pConnectionHash
1368
+ * @param {string} pHandleType - 'bezier-midpoint', 'bezier-handle-N', 'ortho-corner1', 'ortho-corner2', 'ortho-midpoint'
1369
+ * @param {number} pX
1370
+ * @param {number} pY
1371
+ */_inherits(PictServiceFlowConnectionHandleManager,_libFableServiceProvi1);return _createClass(PictServiceFlowConnectionHandleManager,[{key:"updateConnectionHandle",value:function updateConnectionHandle(pConnectionHash,pHandleType,pX,pY){if(!this._FlowView)return;var tmpConnection=this._FlowView.getConnection(pConnectionHash);if(!tmpConnection)return;if(!tmpConnection.Data)tmpConnection.Data={};tmpConnection.Data.HandleCustomized=true;// Multi-handle bezier: handle type is 'bezier-handle-N'
1372
+ if(pHandleType&&pHandleType.startsWith('bezier-handle-')){var tmpIndex=parseInt(pHandleType.replace('bezier-handle-',''),10);if(!isNaN(tmpIndex)&&Array.isArray(tmpConnection.Data.BezierHandles)&&tmpIndex<tmpConnection.Data.BezierHandles.length){tmpConnection.Data.BezierHandles[tmpIndex].x=pX;tmpConnection.Data.BezierHandles[tmpIndex].y=pY;}this._FlowView._renderSingleConnection(pConnectionHash);return;}switch(pHandleType){case'bezier-midpoint':// Legacy single-handle: migrate to BezierHandles array
1373
+ if(!Array.isArray(tmpConnection.Data.BezierHandles)||tmpConnection.Data.BezierHandles.length===0){tmpConnection.Data.BezierHandles=[{x:pX,y:pY}];}else{tmpConnection.Data.BezierHandles[0].x=pX;tmpConnection.Data.BezierHandles[0].y=pY;}// Keep legacy fields in sync for backward compat
1374
+ tmpConnection.Data.BezierHandleX=pX;tmpConnection.Data.BezierHandleY=pY;break;case'ortho-corner1':tmpConnection.Data.OrthoCorner1X=pX;tmpConnection.Data.OrthoCorner1Y=pY;break;case'ortho-corner2':tmpConnection.Data.OrthoCorner2X=pX;tmpConnection.Data.OrthoCorner2Y=pY;break;case'ortho-midpoint':{// Midpoint drag shifts the corridor offset
1375
+ var tmpSourcePos=this._FlowView.getPortPosition(tmpConnection.SourceNodeHash,tmpConnection.SourcePortHash);var tmpTargetPos=this._FlowView.getPortPosition(tmpConnection.TargetNodeHash,tmpConnection.TargetPortHash);if(tmpSourcePos&&tmpTargetPos){var tmpGeom=this._FlowView._ConnectionRenderer._computeDirectionalGeometry(tmpSourcePos,tmpTargetPos);var tmpStartDir=tmpGeom.startDir;// Compute offset along the corridor axis
1376
+ if(Math.abs(tmpStartDir.dx)>Math.abs(tmpStartDir.dy)){// Horizontal departure — corridor is vertical, shift is along X
1377
+ var tmpAutoMidX=(tmpGeom.departX+tmpGeom.approachX)/2;tmpConnection.Data.OrthoMidOffset=pX-tmpAutoMidX;}else{// Vertical departure — corridor is horizontal, shift is along Y
1378
+ var tmpAutoMidY=(tmpGeom.departY+tmpGeom.approachY)/2;tmpConnection.Data.OrthoMidOffset=pY-tmpAutoMidY;}}break;}}this._FlowView._renderSingleConnection(pConnectionHash);}/**
1379
+ * Add a bezier handle to a connection at the specified position.
1380
+ * The handle is inserted at the correct index based on which
1381
+ * segment of the curve the click point is closest to.
1382
+ *
1383
+ * @param {string} pConnectionHash
1384
+ * @param {number} pX
1385
+ * @param {number} pY
1386
+ */},{key:"addConnectionHandle",value:function addConnectionHandle(pConnectionHash,pX,pY){if(!this._FlowView)return;var tmpConnection=this._FlowView.getConnection(pConnectionHash);if(!tmpConnection)return;if(!tmpConnection.Data)tmpConnection.Data={};// Ensure BezierHandles array exists (migrate from legacy if needed)
1387
+ if(!Array.isArray(tmpConnection.Data.BezierHandles)){tmpConnection.Data.BezierHandles=[];if(tmpConnection.Data.BezierHandleX!=null&&tmpConnection.Data.BezierHandleY!=null){tmpConnection.Data.BezierHandles.push({x:tmpConnection.Data.BezierHandleX,y:tmpConnection.Data.BezierHandleY});}}// Ensure bezier mode
1388
+ tmpConnection.Data.LineMode='bezier';var tmpSourcePos=this._FlowView.getPortPosition(tmpConnection.SourceNodeHash,tmpConnection.SourcePortHash);var tmpTargetPos=this._FlowView.getPortPosition(tmpConnection.TargetNodeHash,tmpConnection.TargetPortHash);var tmpInsertIndex=0;if(tmpSourcePos&&tmpTargetPos&&this._FlowView._ConnectionRenderer){tmpInsertIndex=this._FlowView._ConnectionRenderer.computeInsertionIndex(tmpConnection.Data.BezierHandles,{x:pX,y:pY},tmpSourcePos,tmpTargetPos);}tmpConnection.Data.BezierHandles.splice(tmpInsertIndex,0,{x:pX,y:pY});tmpConnection.Data.HandleCustomized=true;this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}}/**
1389
+ * Remove a bezier handle from a connection by index.
1390
+ *
1391
+ * @param {string} pConnectionHash
1392
+ * @param {number} pIndex - Index in the BezierHandles array
1393
+ */},{key:"removeConnectionHandle",value:function removeConnectionHandle(pConnectionHash,pIndex){if(!this._FlowView)return;var tmpConnection=this._FlowView.getConnection(pConnectionHash);if(!tmpConnection||!tmpConnection.Data)return;if(!Array.isArray(tmpConnection.Data.BezierHandles))return;if(pIndex<0||pIndex>=tmpConnection.Data.BezierHandles.length)return;tmpConnection.Data.BezierHandles.splice(pIndex,1);if(tmpConnection.Data.BezierHandles.length===0){tmpConnection.Data.HandleCustomized=false;tmpConnection.Data.BezierHandleX=null;tmpConnection.Data.BezierHandleY=null;}this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}}/**
1394
+ * Reset handle positions for all connections/tethers involving a node.
1395
+ * Called when a node moves. Preserves LineMode but resets handle coordinates to auto.
1396
+ * @param {string} pNodeHash
1397
+ */},{key:"resetHandlesForNode",value:function resetHandlesForNode(pNodeHash){if(!this._FlowView)return;// Reset connection handles
1398
+ for(var i=0;i<this._FlowView._FlowData.Connections.length;i++){var tmpConn=this._FlowView._FlowData.Connections[i];if(tmpConn.SourceNodeHash===pNodeHash||tmpConn.TargetNodeHash===pNodeHash){if(tmpConn.Data&&tmpConn.Data.HandleCustomized){tmpConn.Data.HandleCustomized=false;// Clear multi-handle array (current format)
1399
+ tmpConn.Data.BezierHandles=[];// Clear legacy single-handle fields
1400
+ tmpConn.Data.BezierHandleX=null;tmpConn.Data.BezierHandleY=null;tmpConn.Data.OrthoCorner1X=null;tmpConn.Data.OrthoCorner1Y=null;tmpConn.Data.OrthoCorner2X=null;tmpConn.Data.OrthoCorner2Y=null;tmpConn.Data.OrthoMidOffset=0;}}}// Reset tether handles for panels attached to this node
1401
+ if(this._FlowView._TetherService){this._FlowView._TetherService.resetHandlesForNode(this._FlowView._FlowData.OpenPanels,pNodeHash);}}/**
1402
+ * Reset tether handle positions for a specific panel.
1403
+ * Called when a panel is dragged.
1404
+ * @param {string} pPanelHash
1405
+ */},{key:"resetHandlesForPanel",value:function resetHandlesForPanel(pPanelHash){if(!this._FlowView)return;var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===pPanelHash;});if(!tmpPanel)return;if(this._FlowView._TetherService){this._FlowView._TetherService.resetHandlePositions(tmpPanel);}}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowConnectionHandleManager;},{"fable-serviceproviderbase":4}],28:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');var PictServiceFlowConnectionRenderer=/*#__PURE__*/function(_libFableServiceProvi10){function PictServiceFlowConnectionRenderer(pFable,pOptions,pServiceHash){var _this35;_classCallCheck(this,PictServiceFlowConnectionRenderer);_this35=_callSuper(this,PictServiceFlowConnectionRenderer,[pFable,pOptions,pServiceHash]);_this35.serviceType='PictServiceFlowConnectionRenderer';_this35._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this35;}/**
1406
+ * Render a connection as an SVG path with hit area and optional handles.
1407
+ * @param {Object} pConnection - The connection data
1408
+ * @param {SVGGElement} pConnectionsLayer - The SVG group to append to
1409
+ * @param {boolean} pIsSelected - Whether this connection is selected
1410
+ */_inherits(PictServiceFlowConnectionRenderer,_libFableServiceProvi10);return _createClass(PictServiceFlowConnectionRenderer,[{key:"renderConnection",value:function renderConnection(pConnection,pConnectionsLayer,pIsSelected){if(!this._FlowView)return;var tmpSourcePos=this._FlowView.getPortPosition(pConnection.SourceNodeHash,pConnection.SourcePortHash);var tmpTargetPos=this._FlowView.getPortPosition(pConnection.TargetNodeHash,pConnection.TargetPortHash);// Look up the source port's PortType for connection coloring
1411
+ var tmpSourcePortType=null;var tmpSourceNode=this._FlowView.getNode(pConnection.SourceNodeHash);if(tmpSourceNode&&tmpSourceNode.Ports){for(var i=0;i<tmpSourceNode.Ports.length;i++){if(tmpSourceNode.Ports[i].Hash===pConnection.SourcePortHash){tmpSourcePortType=tmpSourceNode.Ports[i].PortType||null;break;}}}if(!tmpSourcePos||!tmpTargetPos)return;var tmpData=pConnection.Data||{};var tmpLineMode=tmpData.LineMode||'bezier';var tmpPath;if(tmpLineMode==='orthogonal'){var tmpCorners=null;if(tmpData.HandleCustomized&&tmpData.OrthoCorner1X!=null){tmpCorners={corner1:{x:tmpData.OrthoCorner1X,y:tmpData.OrthoCorner1Y},corner2:{x:tmpData.OrthoCorner2X,y:tmpData.OrthoCorner2Y}};}tmpPath=this._generateOrthogonalPath(tmpSourcePos,tmpTargetPos,tmpCorners,tmpData.OrthoMidOffset||0);}else{var tmpHandles=this._getBezierHandles(tmpData);if(tmpHandles.length>0){tmpPath=this._generateMultiHandleBezierPath(tmpSourcePos,tmpTargetPos,tmpHandles);}else{tmpPath=this._generateDirectionalPath(tmpSourcePos,tmpTargetPos);}}// Apply theme noise post-processing to the path
1412
+ if(this._FlowView._ThemeProvider){tmpPath=this._FlowView._ThemeProvider.processPathString(tmpPath,pConnection.Hash);}// Apply stroke-dasharray from theme's ConnectionConfig
1413
+ var tmpStrokeDashArray=null;if(this._FlowView._ThemeProvider){var tmpActiveTheme=this._FlowView._ThemeProvider.getActiveTheme();if(tmpActiveTheme&&tmpActiveTheme.ConnectionConfig&&tmpActiveTheme.ConnectionConfig.StrokeDashArray){tmpStrokeDashArray=tmpActiveTheme.ConnectionConfig.StrokeDashArray;}}var tmpViewIdentifier=this._FlowView.options.ViewIdentifier;// Build the port-type CSS class suffix for connection coloring
1414
+ var tmpConnTypeClass=tmpSourcePortType?' conn-type-'+tmpSourcePortType:'';// Determine the arrowhead marker based on port type
1415
+ var tmpArrowMarkerId;if(pIsSelected){tmpArrowMarkerId='flow-arrowhead-selected-'+tmpViewIdentifier;}else if(tmpSourcePortType){tmpArrowMarkerId='flow-arrowhead-'+tmpSourcePortType+'-'+tmpViewIdentifier;}else{tmpArrowMarkerId='flow-arrowhead-'+tmpViewIdentifier;}// Hit area (wider invisible path for easier selection)
1416
+ var tmpShapeProvider=this._FlowView._ConnectorShapesProvider;if(tmpShapeProvider){var tmpHitArea=tmpShapeProvider.createConnectionHitAreaElement(tmpPath,pConnection.Hash);pConnectionsLayer.appendChild(tmpHitArea);var tmpPathElement=tmpShapeProvider.createConnectionPathElement(tmpPath,pConnection.Hash,pIsSelected,tmpViewIdentifier);if(tmpConnTypeClass){tmpPathElement.setAttribute('class',(tmpPathElement.getAttribute('class')||'')+tmpConnTypeClass);}// Override the default arrowhead with the typed one
1417
+ tmpPathElement.setAttribute('marker-end','url(#'+tmpArrowMarkerId+')');if(tmpStrokeDashArray){tmpPathElement.setAttribute('stroke-dasharray',tmpStrokeDashArray);}pConnectionsLayer.appendChild(tmpPathElement);}else{var _tmpHitArea=this._FlowView._SVGHelperProvider.createSVGElement('path');_tmpHitArea.setAttribute('class','pict-flow-connection-hitarea');_tmpHitArea.setAttribute('d',tmpPath);_tmpHitArea.setAttribute('data-connection-hash',pConnection.Hash);_tmpHitArea.setAttribute('data-element-type','connection-hitarea');pConnectionsLayer.appendChild(_tmpHitArea);var _tmpPathElement=this._FlowView._SVGHelperProvider.createSVGElement('path');_tmpPathElement.setAttribute('class',"pict-flow-connection".concat(tmpConnTypeClass," ").concat(pIsSelected?'selected':''));_tmpPathElement.setAttribute('d',tmpPath);_tmpPathElement.setAttribute('data-connection-hash',pConnection.Hash);_tmpPathElement.setAttribute('data-element-type','connection');_tmpPathElement.setAttribute('marker-end','url(#'+tmpArrowMarkerId+')');if(tmpStrokeDashArray){_tmpPathElement.setAttribute('stroke-dasharray',tmpStrokeDashArray);}pConnectionsLayer.appendChild(_tmpPathElement);}// Render drag handles when selected
1418
+ if(pIsSelected){this._renderHandles(pConnection,pConnectionsLayer,tmpSourcePos,tmpTargetPos);}}/**
1419
+ * Compute the departure and approach points plus control points
1420
+ * for a direction-aware bezier between two ports.
1421
+ *
1422
+ * This extracts the intermediate geometry from _generateDirectionalPath
1423
+ * so it can be reused by _getAutoMidpoint and _generateBezierPathWithHandle.
1424
+ *
1425
+ * @param {{x: number, y: number, side: string}} pStart
1426
+ * @param {{x: number, y: number, side: string}} pEnd
1427
+ * @returns {{departX, departY, approachX, approachY, cp1X, cp1Y, cp2X, cp2Y, startDir, endDir}}
1428
+ */},{key:"_computeDirectionalGeometry",value:function _computeDirectionalGeometry(pStart,pEnd){return this._FlowView._PathGenerator.computeDirectionalGeometry(pStart,pEnd);}/**
1429
+ * Generate a direction-aware path between two ports.
1430
+ *
1431
+ * The path is composed of three segments:
1432
+ * 1. A short straight "departure" segment leaving the source port
1433
+ * in its outward direction.
1434
+ * 2. A cubic bezier curve connecting the departure point to an
1435
+ * "approach" point near the target port.
1436
+ * 3. A short straight "approach" segment arriving at the target
1437
+ * port aligned with its inward direction.
1438
+ *
1439
+ * @param {{x: number, y: number, side: string}} pStart - Start port position + side
1440
+ * @param {{x: number, y: number, side: string}} pEnd - End port position + side
1441
+ * @returns {string} SVG path d attribute
1442
+ */},{key:"_generateDirectionalPath",value:function _generateDirectionalPath(pStart,pEnd){var tmpGeo=this._computeDirectionalGeometry(pStart,pEnd);return this._FlowView._PathGenerator.buildBezierPathString({x:pStart.x,y:pStart.y},{x:tmpGeo.departX,y:tmpGeo.departY},{x:tmpGeo.cp1X,y:tmpGeo.cp1Y},{x:tmpGeo.cp2X,y:tmpGeo.cp2Y},{x:tmpGeo.approachX,y:tmpGeo.approachY},{x:pEnd.x,y:pEnd.y});}/**
1443
+ * Get the bezier handles array from connection data, with backward
1444
+ * compatibility for the legacy BezierHandleX/Y single-handle format.
1445
+ *
1446
+ * @param {Object} pData - Connection.Data
1447
+ * @returns {Array<{x: number, y: number}>} Ordered handle waypoints (may be empty)
1448
+ */},{key:"_getBezierHandles",value:function _getBezierHandles(pData){if(!pData||!pData.HandleCustomized){return[];}// New multi-handle format
1449
+ if(Array.isArray(pData.BezierHandles)&&pData.BezierHandles.length>0){return pData.BezierHandles;}// Legacy single-handle format
1450
+ if(pData.BezierHandleX!=null&&pData.BezierHandleY!=null){return[{x:pData.BezierHandleX,y:pData.BezierHandleY}];}return[];}/**
1451
+ * Generate a multi-handle bezier path between two ports.
1452
+ * Delegates to PathGenerator.buildMultiBezierPathString for the
1453
+ * actual SVG path assembly with Catmull-Rom tangent continuity.
1454
+ *
1455
+ * @param {{x: number, y: number, side: string}} pStart
1456
+ * @param {{x: number, y: number, side: string}} pEnd
1457
+ * @param {Array<{x: number, y: number}>} pHandles - Ordered waypoints
1458
+ * @returns {string} SVG path d attribute
1459
+ */},{key:"_generateMultiHandleBezierPath",value:function _generateMultiHandleBezierPath(pStart,pEnd,pHandles){var tmpGeo=this._computeDirectionalGeometry(pStart,pEnd);return this._FlowView._PathGenerator.buildMultiBezierPathString({x:pStart.x,y:pStart.y},{x:tmpGeo.departX,y:tmpGeo.departY},pHandles,{x:tmpGeo.approachX,y:tmpGeo.approachY},{x:pEnd.x,y:pEnd.y},tmpGeo.startDir,tmpGeo.endDir);}/**
1460
+ * Find which segment of the multi-handle bezier the given click point
1461
+ * is closest to, returning the index at which a new handle should be
1462
+ * inserted into the BezierHandles array.
1463
+ *
1464
+ * Segments are: depart→handle[0], handle[0]→handle[1], ..., handle[N-1]→approach.
1465
+ * Returns 0 for before handle[0], 1 for between handle[0] and handle[1], etc.
1466
+ *
1467
+ * @param {Array<{x: number, y: number}>} pHandles - Current handles
1468
+ * @param {{x: number, y: number}} pClickPoint - Where the user right-clicked
1469
+ * @param {{x: number, y: number, side: string}} pStart - Source port position
1470
+ * @param {{x: number, y: number, side: string}} pEnd - Target port position
1471
+ * @returns {number} Insertion index
1472
+ */},{key:"computeInsertionIndex",value:function computeInsertionIndex(pHandles,pClickPoint,pStart,pEnd){var tmpGeo=this._computeDirectionalGeometry(pStart,pEnd);// Build the waypoint chain: depart, handle[0..N-1], approach
1473
+ var tmpWaypoints=[{x:tmpGeo.departX,y:tmpGeo.departY}];for(var i=0;i<pHandles.length;i++){tmpWaypoints.push(pHandles[i]);}tmpWaypoints.push({x:tmpGeo.approachX,y:tmpGeo.approachY});var tmpBestDist=Infinity;var tmpBestIndex=0;for(var _i31=0;_i31<tmpWaypoints.length-1;_i31++){var tmpDist=this._distanceToSegment(pClickPoint.x,pClickPoint.y,tmpWaypoints[_i31].x,tmpWaypoints[_i31].y,tmpWaypoints[_i31+1].x,tmpWaypoints[_i31+1].y);if(tmpDist<tmpBestDist){tmpBestDist=tmpDist;tmpBestIndex=_i31;}}return tmpBestIndex;}/**
1474
+ * Distance from point (px,py) to line segment (ax,ay)-(bx,by).
1475
+ */},{key:"_distanceToSegment",value:function _distanceToSegment(pPX,pPY,pAX,pAY,pBX,pBY){return this._FlowView._PathGenerator.distanceToSegment(pPX,pPY,pAX,pAY,pBX,pBY);}/**
1476
+ * Get the auto-calculated midpoint of the default bezier curve between two ports.
1477
+ * Evaluates the cubic bezier at t=0.5.
1478
+ *
1479
+ * @param {{x: number, y: number, side: string}} pStart
1480
+ * @param {{x: number, y: number, side: string}} pEnd
1481
+ * @returns {{x: number, y: number}}
1482
+ */},{key:"getAutoMidpoint",value:function getAutoMidpoint(pStart,pEnd){return this._FlowView._PathGenerator.getAutoMidpoint(pStart,pEnd);}/**
1483
+ * Generate an orthogonal (90-degree angles only) path between two ports.
1484
+ *
1485
+ * Path format: M start L depart L corner1 L corner2 L approach L end
1486
+ *
1487
+ * @param {{x: number, y: number, side: string}} pStart
1488
+ * @param {{x: number, y: number, side: string}} pEnd
1489
+ * @param {Object|null} pCorners - { corner1: {x,y}, corner2: {x,y} } or null for auto
1490
+ * @param {number} pMidOffset - Offset for the auto-calculated corridor position
1491
+ * @returns {string} SVG path d attribute
1492
+ */},{key:"_generateOrthogonalPath",value:function _generateOrthogonalPath(pStart,pEnd,pCorners,pMidOffset){var tmpDA=this._FlowView._PathGenerator.computeDepartApproach(pStart,pEnd,20);var tmpCorner1,tmpCorner2;if(pCorners&&pCorners.corner1&&pCorners.corner2){tmpCorner1=pCorners.corner1;tmpCorner2=pCorners.corner2;}else{var tmpAutoCorners=this._FlowView._PathGenerator.computeAutoOrthogonalCorners(tmpDA.departX,tmpDA.departY,tmpDA.approachX,tmpDA.approachY,tmpDA.fromDir,tmpDA.toDir,pMidOffset||0);tmpCorner1=tmpAutoCorners.corner1;tmpCorner2=tmpAutoCorners.corner2;}return this._FlowView._PathGenerator.buildOrthogonalPathString({x:pStart.x,y:pStart.y},{x:tmpDA.departX,y:tmpDA.departY},tmpCorner1,tmpCorner2,{x:tmpDA.approachX,y:tmpDA.approachY},{x:pEnd.x,y:pEnd.y});}/**
1493
+ * Get the full orthogonal geometry for a connection (for handle positioning).
1494
+ *
1495
+ * @param {{x: number, y: number, side: string}} pStart
1496
+ * @param {{x: number, y: number, side: string}} pEnd
1497
+ * @param {Object} pData - Connection.Data
1498
+ * @returns {{corner1: {x,y}, corner2: {x,y}, midpoint: {x,y}}}
1499
+ */},{key:"getOrthogonalGeometry",value:function getOrthogonalGeometry(pStart,pEnd,pData){var tmpDA=this._FlowView._PathGenerator.computeDepartApproach(pStart,pEnd,20);if(pData&&pData.HandleCustomized&&pData.OrthoCorner1X!=null){var tmpCorner1={x:pData.OrthoCorner1X,y:pData.OrthoCorner1Y};var tmpCorner2={x:pData.OrthoCorner2X,y:pData.OrthoCorner2Y};var tmpMidpoint={x:(tmpCorner1.x+tmpCorner2.x)/2,y:(tmpCorner1.y+tmpCorner2.y)/2};return{corner1:tmpCorner1,corner2:tmpCorner2,midpoint:tmpMidpoint};}return this._FlowView._PathGenerator.computeAutoOrthogonalCorners(tmpDA.departX,tmpDA.departY,tmpDA.approachX,tmpDA.approachY,tmpDA.fromDir,tmpDA.toDir,pData&&pData.OrthoMidOffset||0);}/**
1500
+ * Render drag handles for the selected connection.
1501
+ *
1502
+ * @param {Object} pConnection
1503
+ * @param {SVGGElement} pLayer
1504
+ * @param {{x, y, side}} pStart - Source port position
1505
+ * @param {{x, y, side}} pEnd - Target port position
1506
+ */},{key:"_renderHandles",value:function _renderHandles(pConnection,pLayer,pStart,pEnd){var tmpData=pConnection.Data||{};var tmpLineMode=tmpData.LineMode||'bezier';if(tmpLineMode==='orthogonal'){var tmpGeometry=this.getOrthogonalGeometry(pStart,pEnd,tmpData);// Corner 1 handle
1507
+ this._createHandle(pLayer,pConnection.Hash,'ortho-corner1',tmpGeometry.corner1.x,tmpGeometry.corner1.y,'pict-flow-connection-handle');// Midpoint handle (between corners)
1508
+ this._createHandle(pLayer,pConnection.Hash,'ortho-midpoint',tmpGeometry.midpoint.x,tmpGeometry.midpoint.y,'pict-flow-connection-handle-midpoint');// Corner 2 handle
1509
+ this._createHandle(pLayer,pConnection.Hash,'ortho-corner2',tmpGeometry.corner2.x,tmpGeometry.corner2.y,'pict-flow-connection-handle');}else{// Bezier handles — show one handle per waypoint, or a
1510
+ // single auto-midpoint when no custom handles exist.
1511
+ var tmpHandles=this._getBezierHandles(tmpData);if(tmpHandles.length>0){for(var i=0;i<tmpHandles.length;i++){this._createHandle(pLayer,pConnection.Hash,'bezier-handle-'+i,tmpHandles[i].x,tmpHandles[i].y,'pict-flow-connection-handle');}}else{var tmpMidpoint=this.getAutoMidpoint(pStart,pEnd);this._createHandle(pLayer,pConnection.Hash,'bezier-midpoint',tmpMidpoint.x,tmpMidpoint.y,'pict-flow-connection-handle');}}}/**
1512
+ * Create a single SVG circle handle element.
1513
+ *
1514
+ * @param {SVGGElement} pLayer
1515
+ * @param {string} pConnectionHash
1516
+ * @param {string} pHandleType
1517
+ * @param {number} pX
1518
+ * @param {number} pY
1519
+ * @param {string} pClassName
1520
+ */},{key:"_createHandle",value:function _createHandle(pLayer,pConnectionHash,pHandleType,pX,pY,pClassName){if(!this._FlowView._ConnectorShapesProvider)return;var tmpShapeKey=pClassName==='pict-flow-connection-handle-midpoint'?'connection-handle-midpoint':'connection-handle';this._FlowView._ConnectorShapesProvider.createFullHandle(pLayer,pConnectionHash,pHandleType,pX,pY,tmpShapeKey,'connection-handle','data-connection-hash');}/**
1521
+ * Legacy bezier path for drag connections where we don't have side info.
1522
+ * @param {{x: number, y: number}} pStart
1523
+ * @param {{x: number, y: number}} pEnd
1524
+ * @returns {string}
1525
+ */},{key:"_generateBezierPath",value:function _generateBezierPath(pStart,pEnd){// During drag operations we may not have side info; default to right->left
1526
+ var tmpStart={x:pStart.x,y:pStart.y,side:pStart.side||'right'};var tmpEnd={x:pEnd.x,y:pEnd.y,side:pEnd.side||'left'};return this._generateDirectionalPath(tmpStart,tmpEnd);}/**
1527
+ * Render a temporary drag connection line (used during connection creation)
1528
+ * @param {number} pStartX
1529
+ * @param {number} pStartY
1530
+ * @param {number} pEndX
1531
+ * @param {number} pEndY
1532
+ * @param {SVGGElement} pLayer - The layer to render into
1533
+ * @param {string} [pStartSide] - The side the source port is on
1534
+ * @returns {SVGPathElement} The created path element
1535
+ */},{key:"renderDragConnection",value:function renderDragConnection(pStartX,pStartY,pEndX,pEndY,pLayer,pStartSide){var tmpPath=this._generateDirectionalPath({x:pStartX,y:pStartY,side:pStartSide||'right'},{x:pEndX,y:pEndY,side:'left'});var tmpShapeProvider=this._FlowView._ConnectorShapesProvider;var tmpPathElement;if(tmpShapeProvider){tmpPathElement=tmpShapeProvider.createDragConnectionElement(tmpPath);}else{tmpPathElement=this._FlowView._SVGHelperProvider.createSVGElement('path');tmpPathElement.setAttribute('class','pict-flow-drag-connection');tmpPathElement.setAttribute('d',tmpPath);}pLayer.appendChild(tmpPathElement);return tmpPathElement;}/**
1536
+ * Update a drag connection path
1537
+ * @param {SVGPathElement} pPathElement
1538
+ * @param {number} pStartX
1539
+ * @param {number} pStartY
1540
+ * @param {number} pEndX
1541
+ * @param {number} pEndY
1542
+ * @param {string} [pStartSide] - The side the source port is on
1543
+ */},{key:"updateDragConnection",value:function updateDragConnection(pPathElement,pStartX,pStartY,pEndX,pEndY,pStartSide){if(!pPathElement)return;var tmpPath=this._generateDirectionalPath({x:pStartX,y:pStartY,side:pStartSide||'right'},{x:pEndX,y:pEndY,side:'left'});pPathElement.setAttribute('d',tmpPath);}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowConnectionRenderer;},{"fable-serviceproviderbase":4}],29:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1544
+ * PictService-Flow-DataManager
1545
+ *
1546
+ * Manages flow data lifecycle: serialization, deserialization, and CRUD
1547
+ * operations for nodes and connections.
1548
+ *
1549
+ * Extracted from PictView-Flow.js to keep the view focused on
1550
+ * coordination and lifecycle rather than data manipulation.
1551
+ */var PictServiceFlowDataManager=/*#__PURE__*/function(_libFableServiceProvi11){function PictServiceFlowDataManager(pFable,pOptions,pServiceHash){var _this36;_classCallCheck(this,PictServiceFlowDataManager);_this36=_callSuper(this,PictServiceFlowDataManager,[pFable,pOptions,pServiceHash]);_this36.serviceType='PictServiceFlowDataManager';_this36._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this36;}// ---- Marshaling ----
1552
+ /**
1553
+ * Marshal data from AppData into the flow view
1554
+ */_inherits(PictServiceFlowDataManager,_libFableServiceProvi11);return _createClass(PictServiceFlowDataManager,[{key:"marshalToView",value:function marshalToView(){if(!this._FlowView)return;if(this._FlowView.options.FlowDataAddress){var tmpAddressSpace={Fable:this._FlowView.fable,Pict:this._FlowView.pict||this._FlowView.fable,AppData:this._FlowView.pict?this._FlowView.pict.AppData:this._FlowView.fable.AppData,Bundle:this._FlowView.Bundle,Options:this._FlowView.options};var tmpData=this._FlowView.fable.manifest.getValueByHash(tmpAddressSpace,this._FlowView.options.FlowDataAddress);if(_typeof(tmpData)==='object'&&tmpData!==null){this.setFlowData(tmpData);}}}/**
1555
+ * Marshal data from the flow view back to AppData
1556
+ */},{key:"marshalFromView",value:function marshalFromView(){if(!this._FlowView)return;if(this._FlowView.options.FlowDataAddress){var tmpAddressSpace={Fable:this._FlowView.fable,Pict:this._FlowView.pict||this._FlowView.fable,AppData:this._FlowView.pict?this._FlowView.pict.AppData:this._FlowView.fable.AppData,Bundle:this._FlowView.Bundle,Options:this._FlowView.options};this._FlowView.fable.manifest.setValueByHash(tmpAddressSpace,this._FlowView.options.FlowDataAddress,JSON.parse(JSON.stringify(this._FlowView._FlowData)));}}// ---- Flow Data Get/Set ----
1557
+ /**
1558
+ * Get the complete flow data object
1559
+ * @returns {Object} The flow data including nodes, connections, and view state
1560
+ */},{key:"getFlowData",value:function getFlowData(){if(!this._FlowView)return{};return JSON.parse(JSON.stringify(this._FlowView._FlowData));}/**
1561
+ * Set the complete flow data object and re-render
1562
+ * @param {Object} pFlowData - The flow data to set
1563
+ */},{key:"setFlowData",value:function setFlowData(pFlowData){if(!this._FlowView)return;if(_typeof(pFlowData)!=='object'||pFlowData===null){this._FlowView.log.warn('PictSectionFlow setFlowData received invalid data');return;}this._FlowView._FlowData={Nodes:Array.isArray(pFlowData.Nodes)?pFlowData.Nodes:[],Connections:Array.isArray(pFlowData.Connections)?pFlowData.Connections:[],OpenPanels:Array.isArray(pFlowData.OpenPanels)?pFlowData.OpenPanels:[],SavedLayouts:Array.isArray(pFlowData.SavedLayouts)?pFlowData.SavedLayouts:[],ViewState:Object.assign({PanX:0,PanY:0,Zoom:1,SelectedNodeHash:null,SelectedConnectionHash:null,SelectedTetherHash:null},pFlowData.ViewState||{})};// Merge any browser-persisted layouts into the newly loaded data
1564
+ if(this._FlowView._LayoutProvider){this._FlowView._LayoutProvider.loadPersistedLayouts();}if(this._FlowView.initialRenderComplete){this._FlowView.renderFlow();}}// ---- Node CRUD ----
1565
+ /**
1566
+ * Add a new node to the flow
1567
+ * @param {string} pType - The node type hash
1568
+ * @param {number} pX - X position
1569
+ * @param {number} pY - Y position
1570
+ * @param {string} [pTitle] - Optional title
1571
+ * @param {Object} [pData] - Optional additional data
1572
+ * @returns {Object} The created node
1573
+ */},{key:"addNode",value:function addNode(pType,pX,pY,pTitle,pData){if(!this._FlowView)return null;var tmpType=pType||this._FlowView.options.DefaultNodeType;var tmpNodeTypeConfig=this._FlowView._NodeTypeProvider.getNodeType(tmpType);var tmpNodeHash="node-".concat(this._FlowView.fable.getUUID());var tmpNode={Hash:tmpNodeHash,Type:tmpType,X:pX||100,Y:pY||100,Width:tmpNodeTypeConfig&&tmpNodeTypeConfig.DefaultWidth||this._FlowView.options.DefaultNodeWidth,Height:tmpNodeTypeConfig&&tmpNodeTypeConfig.DefaultHeight||this._FlowView.options.DefaultNodeHeight,Title:pTitle||tmpNodeTypeConfig&&tmpNodeTypeConfig.Label||'New Node',Ports:tmpNodeTypeConfig&&tmpNodeTypeConfig.DefaultPorts?JSON.parse(JSON.stringify(tmpNodeTypeConfig.DefaultPorts)):[{Hash:"port-in-".concat(this._FlowView.fable.getUUID()),Direction:'input',Side:'left',Label:'In'},{Hash:"port-out-".concat(this._FlowView.fable.getUUID()),Direction:'output',Side:'right',Label:'Out'}],Data:pData||{}};// Ensure each port has a unique hash
1574
+ for(var i=0;i<tmpNode.Ports.length;i++){if(!tmpNode.Ports[i].Hash){tmpNode.Ports[i].Hash="port-".concat(tmpNode.Ports[i].Direction,"-").concat(this._FlowView.fable.getUUID());}}this._FlowView._FlowData.Nodes.push(tmpNode);this._FlowView.renderFlow();this.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onNodeAdded',tmpNode);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}return tmpNode;}/**
1575
+ * Remove a node and all its connections
1576
+ * @param {string} pNodeHash - The hash of the node to remove
1577
+ * @returns {boolean} Whether the node was removed
1578
+ */},{key:"removeNode",value:function removeNode(pNodeHash){if(!this._FlowView)return false;var tmpNodeIndex=this._FlowView._FlowData.Nodes.findIndex(function(pNode){return pNode.Hash===pNodeHash;});if(tmpNodeIndex<0){this._FlowView.log.warn("PictSectionFlow removeNode: node ".concat(pNodeHash," not found"));return false;}var tmpRemovedNode=this._FlowView._FlowData.Nodes.splice(tmpNodeIndex,1)[0];// Remove all connections involving this node
1579
+ this._FlowView._FlowData.Connections=this._FlowView._FlowData.Connections.filter(function(pConnection){return pConnection.SourceNodeHash!==pNodeHash&&pConnection.TargetNodeHash!==pNodeHash;});// Close any open panels for this node
1580
+ this._FlowView.closePanelForNode(pNodeHash);// Clear selection if this node was selected
1581
+ if(this._FlowView._FlowData.ViewState.SelectedNodeHash===pNodeHash){this._FlowView._FlowData.ViewState.SelectedNodeHash=null;}this._FlowView.renderFlow();this.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onNodeRemoved',tmpRemovedNode);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}return true;}// ---- Connection CRUD ----
1582
+ /**
1583
+ * Add a connection between two ports
1584
+ * @param {string} pSourceNodeHash
1585
+ * @param {string} pSourcePortHash
1586
+ * @param {string} pTargetNodeHash
1587
+ * @param {string} pTargetPortHash
1588
+ * @param {Object} [pData] - Optional additional data
1589
+ * @returns {Object|false} The created connection, or false if invalid
1590
+ */},{key:"addConnection",value:function addConnection(pSourceNodeHash,pSourcePortHash,pTargetNodeHash,pTargetPortHash,pData){if(!this._FlowView)return false;// Validate that both nodes and ports exist
1591
+ var tmpSourceNode=this._FlowView._FlowData.Nodes.find(function(pNode){return pNode.Hash===pSourceNodeHash;});var tmpTargetNode=this._FlowView._FlowData.Nodes.find(function(pNode){return pNode.Hash===pTargetNodeHash;});if(!tmpSourceNode||!tmpTargetNode){this._FlowView.log.warn('PictSectionFlow addConnection: source or target node not found');return false;}var tmpSourcePort=tmpSourceNode.Ports.find(function(pPort){return pPort.Hash===pSourcePortHash;});var tmpTargetPort=tmpTargetNode.Ports.find(function(pPort){return pPort.Hash===pTargetPortHash;});if(!tmpSourcePort||!tmpTargetPort){this._FlowView.log.warn('PictSectionFlow addConnection: source or target port not found');return false;}// Prevent self-connections
1592
+ if(pSourceNodeHash===pTargetNodeHash){this._FlowView.log.warn('PictSectionFlow addConnection: cannot connect a node to itself');return false;}// Check for duplicate connections
1593
+ var tmpDuplicate=this._FlowView._FlowData.Connections.find(function(pConn){return pConn.SourceNodeHash===pSourceNodeHash&&pConn.SourcePortHash===pSourcePortHash&&pConn.TargetNodeHash===pTargetNodeHash&&pConn.TargetPortHash===pTargetPortHash;});if(tmpDuplicate){this._FlowView.log.warn('PictSectionFlow addConnection: duplicate connection');return false;}var tmpConnection={Hash:"conn-".concat(this._FlowView.fable.getUUID()),SourceNodeHash:pSourceNodeHash,SourcePortHash:pSourcePortHash,TargetNodeHash:pTargetNodeHash,TargetPortHash:pTargetPortHash,Data:pData||{}};this._FlowView._FlowData.Connections.push(tmpConnection);this._FlowView.renderFlow();this.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onConnectionCreated',tmpConnection);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}return tmpConnection;}/**
1594
+ * Remove a connection
1595
+ * @param {string} pConnectionHash - The hash of the connection to remove
1596
+ * @returns {boolean} Whether the connection was removed
1597
+ */},{key:"removeConnection",value:function removeConnection(pConnectionHash){if(!this._FlowView)return false;var tmpConnectionIndex=this._FlowView._FlowData.Connections.findIndex(function(pConn){return pConn.Hash===pConnectionHash;});if(tmpConnectionIndex<0){this._FlowView.log.warn("PictSectionFlow removeConnection: connection ".concat(pConnectionHash," not found"));return false;}var tmpRemovedConnection=this._FlowView._FlowData.Connections.splice(tmpConnectionIndex,1)[0];if(this._FlowView._FlowData.ViewState.SelectedConnectionHash===pConnectionHash){this._FlowView._FlowData.ViewState.SelectedConnectionHash=null;}this._FlowView.renderFlow();this.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onConnectionRemoved',tmpRemovedConnection);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}return true;}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowDataManager;},{"fable-serviceproviderbase":4}],30:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1598
+ * Interaction states for the flow diagram
1599
+ */var INTERACTION_STATES={IDLE:'idle',DRAGGING_NODE:'dragging-node',DRAGGING_PANEL:'dragging-panel',DRAGGING_HANDLE:'dragging-handle',CONNECTING:'connecting',PANNING:'panning',RESIZING_PANEL:'resizing-panel'};var PictServiceFlowInteractionManager=/*#__PURE__*/function(_libFableServiceProvi12){function PictServiceFlowInteractionManager(pFable,pOptions,pServiceHash){var _this37;_classCallCheck(this,PictServiceFlowInteractionManager);_this37=_callSuper(this,PictServiceFlowInteractionManager,[pFable,pOptions,pServiceHash]);_this37.serviceType='PictServiceFlowInteractionManager';_this37._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;_this37._SVGElement=null;_this37._ViewportElement=null;// Interaction state
1600
+ _this37._State=INTERACTION_STATES.IDLE;// Drag state
1601
+ _this37._DragNodeHash=null;_this37._DragStartX=0;_this37._DragStartY=0;_this37._DragNodeStartX=0;_this37._DragNodeStartY=0;// Panel drag state
1602
+ _this37._DragPanelHash=null;_this37._DragPanelStartX=0;_this37._DragPanelStartY=0;_this37._DragPanelDataStartX=0;_this37._DragPanelDataStartY=0;// Handle drag state
1603
+ _this37._DragHandleConnectionHash=null;_this37._DragHandlePanelHash=null;_this37._DragHandleType=null;_this37._DragHandleIsTether=false;// Pan state
1604
+ _this37._PanStartX=0;_this37._PanStartY=0;_this37._PanStartPanX=0;_this37._PanStartPanY=0;// Connection drag state
1605
+ _this37._ConnectSourceNodeHash=null;_this37._ConnectSourcePortHash=null;_this37._ConnectDragLine=null;// Double-click detection
1606
+ _this37._LastClickTime=0;_this37._LastClickNodeHash=null;_this37._DoubleClickThreshold=400;// Panel resize state
1607
+ _this37._ResizePanelHash=null;_this37._ResizeStartY=0;_this37._ResizePanelStartHeight=0;// Double-click detection for connections
1608
+ _this37._LastConnectionClickTime=0;_this37._LastConnectionClickHash=null;// Double-click detection for tethers
1609
+ _this37._LastTetherClickTime=0;_this37._LastTetherClickHash=null;// Double-click detection for handles
1610
+ _this37._LastHandleClickTime=0;_this37._LastHandleClickHash=null;_this37._LastHandleClickType=null;// Bound event handlers (for removeEventListener)
1611
+ _this37._boundOnPointerDown=_this37._onPointerDown.bind(_this37);_this37._boundOnPointerMove=_this37._onPointerMove.bind(_this37);_this37._boundOnPointerUp=_this37._onPointerUp.bind(_this37);_this37._boundOnWheel=_this37._onWheel.bind(_this37);_this37._boundOnKeyDown=_this37._onKeyDown.bind(_this37);return _this37;}/**
1612
+ * Initialize event listeners on the SVG element
1613
+ * @param {SVGSVGElement} pSVGElement
1614
+ * @param {SVGGElement} pViewportElement
1615
+ */_inherits(PictServiceFlowInteractionManager,_libFableServiceProvi12);return _createClass(PictServiceFlowInteractionManager,[{key:"initialize",value:function initialize(pSVGElement,pViewportElement){var _this38=this;this._SVGElement=pSVGElement;this._ViewportElement=pViewportElement;if(!this._SVGElement)return;// Use pointer events for unified mouse/touch handling
1616
+ this._SVGElement.addEventListener('pointerdown',this._boundOnPointerDown);this._SVGElement.addEventListener('pointermove',this._boundOnPointerMove);this._SVGElement.addEventListener('pointerup',this._boundOnPointerUp);this._SVGElement.addEventListener('pointerleave',this._boundOnPointerUp);this._SVGElement.addEventListener('wheel',this._boundOnWheel,{passive:false});// Keyboard events for delete
1617
+ document.addEventListener('keydown',this._boundOnKeyDown);// Handle right-click: add/remove bezier handles on connections
1618
+ this._SVGElement.addEventListener('contextmenu',function(pEvent){pEvent.preventDefault();var tmpTarget=pEvent.target;var tmpElementType=_this38._getElementType(tmpTarget);switch(tmpElementType){case'connection':case'connection-hitarea':_this38._addBezierHandle(tmpTarget,pEvent);break;case'connection-handle':_this38._removeBezierHandle(tmpTarget);break;case'tether':case'tether-hitarea':_this38._addTetherBezierHandle(tmpTarget,pEvent);break;case'tether-handle':_this38._removeTetherBezierHandle(tmpTarget);break;}});}/**
1619
+ * Remove all event listeners
1620
+ */},{key:"destroy",value:function destroy(){if(this._SVGElement){this._SVGElement.removeEventListener('pointerdown',this._boundOnPointerDown);this._SVGElement.removeEventListener('pointermove',this._boundOnPointerMove);this._SVGElement.removeEventListener('pointerup',this._boundOnPointerUp);this._SVGElement.removeEventListener('pointerleave',this._boundOnPointerUp);this._SVGElement.removeEventListener('wheel',this._boundOnWheel);}document.removeEventListener('keydown',this._boundOnKeyDown);}/**
1621
+ * Handle pointer down event
1622
+ * @param {PointerEvent} pEvent
1623
+ */},{key:"_onPointerDown",value:function _onPointerDown(pEvent){if(!this._FlowView)return;var tmpTarget=pEvent.target;var tmpElementType=this._getElementType(tmpTarget);// Check if click is inside a panel content area — let HTML handle its own events
1624
+ if(tmpTarget.closest&&tmpTarget.closest('.pict-flow-panel-content')){return;}// Capture pointer for smooth dragging (left-click only — right-click
1625
+ // needs the real target for contextmenu handle add/remove)
1626
+ if(pEvent.button===0){this._SVGElement.setPointerCapture(pEvent.pointerId);}switch(tmpElementType){case'port':this._startConnection(pEvent,tmpTarget);break;case'node':case'node-body':case'panel-indicator':{var tmpNodeHash=this._getNodeHash(tmpTarget);var tmpNow=Date.now();// Check for double-click on same node
1627
+ if(tmpNodeHash&&tmpNodeHash===this._LastClickNodeHash&&tmpNow-this._LastClickTime<this._DoubleClickThreshold){// Double-click: toggle panel
1628
+ this._LastClickTime=0;this._LastClickNodeHash=null;this._FlowView.togglePanel(tmpNodeHash);}else{// Single click: start node drag
1629
+ this._LastClickTime=tmpNow;this._LastClickNodeHash=tmpNodeHash;this._startNodeDrag(pEvent,tmpTarget);}break;}case'panel-titlebar':this._startPanelDrag(pEvent,tmpTarget);break;case'panel-resize':this._startPanelResize(pEvent,tmpTarget);break;case'panel-close':{var tmpPanelHash=this._getPanelHash(tmpTarget);if(tmpPanelHash){this._FlowView.closePanel(tmpPanelHash);}break;}case'connection-handle':{var tmpConnectionHash=this._getConnectionHash(tmpTarget);var tmpHandleType=tmpTarget.getAttribute('data-handle-type');var _tmpNow=Date.now();// Check for double-click on handle to toggle mode
1630
+ if(tmpConnectionHash===this._LastHandleClickHash&&tmpHandleType===this._LastHandleClickType&&_tmpNow-this._LastHandleClickTime<this._DoubleClickThreshold){this._toggleConnectionLineMode(tmpConnectionHash);this._LastHandleClickTime=0;this._LastHandleClickHash=null;this._LastHandleClickType=null;}else{this._LastHandleClickTime=_tmpNow;this._LastHandleClickHash=tmpConnectionHash;this._LastHandleClickType=tmpHandleType;this._startHandleDrag(pEvent,tmpConnectionHash,null,tmpHandleType,false);}pEvent.stopPropagation();break;}case'tether':case'tether-hitarea':{var _tmpPanelHash=this._getPanelHash(tmpTarget);var _tmpNow2=Date.now();// Check for double-click on same tether to add a handle
1631
+ if(_tmpPanelHash&&_tmpPanelHash===this._LastTetherClickHash&&_tmpNow2-this._LastTetherClickTime<this._DoubleClickThreshold){this._LastTetherClickTime=0;this._LastTetherClickHash=null;this._addTetherBezierHandle(tmpTarget,pEvent);}else{this._LastTetherClickTime=_tmpNow2;this._LastTetherClickHash=_tmpPanelHash;this._selectTether(tmpTarget);}break;}case'tether-handle':{var _tmpPanelHash2=this._getPanelHash(tmpTarget);var _tmpHandleType=tmpTarget.getAttribute('data-handle-type');var _tmpNow3=Date.now();// Check for double-click on tether handle to toggle mode
1632
+ if(_tmpPanelHash2===this._LastHandleClickHash&&_tmpHandleType===this._LastHandleClickType&&_tmpNow3-this._LastHandleClickTime<this._DoubleClickThreshold){this._toggleTetherLineMode(_tmpPanelHash2);this._LastHandleClickTime=0;this._LastHandleClickHash=null;this._LastHandleClickType=null;}else{this._LastHandleClickTime=_tmpNow3;this._LastHandleClickHash=_tmpPanelHash2;this._LastHandleClickType=_tmpHandleType;this._startHandleDrag(pEvent,null,_tmpPanelHash2,_tmpHandleType,true);}pEvent.stopPropagation();break;}case'connection':case'connection-hitarea':{var _tmpConnectionHash=this._getConnectionHash(tmpTarget);var _tmpNow4=Date.now();// Check for double-click on same connection to add a handle
1633
+ if(_tmpConnectionHash&&_tmpConnectionHash===this._LastConnectionClickHash&&_tmpNow4-this._LastConnectionClickTime<this._DoubleClickThreshold){this._LastConnectionClickTime=0;this._LastConnectionClickHash=null;this._addBezierHandle(tmpTarget,pEvent);}else{this._LastConnectionClickTime=_tmpNow4;this._LastConnectionClickHash=_tmpConnectionHash;this._selectConnection(tmpTarget);}break;}default:// Click on background - start panning or deselect
1634
+ if(pEvent.button===0&&this._FlowView.options.EnablePanning){this._startPanning(pEvent);}break;}}/**
1635
+ * Handle pointer move event
1636
+ * @param {PointerEvent} pEvent
1637
+ */},{key:"_onPointerMove",value:function _onPointerMove(pEvent){if(!this._FlowView)return;switch(this._State){case INTERACTION_STATES.DRAGGING_NODE:this._onNodeDrag(pEvent);break;case INTERACTION_STATES.DRAGGING_PANEL:this._onPanelDrag(pEvent);break;case INTERACTION_STATES.DRAGGING_HANDLE:this._onHandleDrag(pEvent);break;case INTERACTION_STATES.CONNECTING:this._onConnectionDrag(pEvent);break;case INTERACTION_STATES.RESIZING_PANEL:this._onPanelResize(pEvent);break;case INTERACTION_STATES.PANNING:this._onPan(pEvent);break;}}/**
1638
+ * Handle pointer up event
1639
+ * @param {PointerEvent} pEvent
1640
+ */},{key:"_onPointerUp",value:function _onPointerUp(pEvent){if(!this._FlowView)return;// Release pointer capture
1641
+ if(this._SVGElement.hasPointerCapture&&this._SVGElement.hasPointerCapture(pEvent.pointerId)){this._SVGElement.releasePointerCapture(pEvent.pointerId);}switch(this._State){case INTERACTION_STATES.DRAGGING_NODE:this._endNodeDrag(pEvent);break;case INTERACTION_STATES.DRAGGING_PANEL:this._endPanelDrag(pEvent);break;case INTERACTION_STATES.DRAGGING_HANDLE:this._endHandleDrag(pEvent);break;case INTERACTION_STATES.RESIZING_PANEL:this._endPanelResize(pEvent);break;case INTERACTION_STATES.CONNECTING:this._endConnection(pEvent);break;case INTERACTION_STATES.PANNING:this._endPanning(pEvent);break;}}/**
1642
+ * Handle mouse wheel for zoom
1643
+ * @param {WheelEvent} pEvent
1644
+ */},{key:"_onWheel",value:function _onWheel(pEvent){if(!this._FlowView||!this._FlowView.options.EnableZooming)return;pEvent.preventDefault();var tmpDelta=pEvent.deltaY>0?-this._FlowView.options.ZoomStep:this._FlowView.options.ZoomStep;var tmpNewZoom=this._FlowView.viewState.Zoom+tmpDelta;// Zoom toward mouse position
1645
+ var tmpRect=this._SVGElement.getBoundingClientRect();var tmpMouseX=pEvent.clientX-tmpRect.left;var tmpMouseY=pEvent.clientY-tmpRect.top;this._FlowView.setZoom(tmpNewZoom,tmpMouseX,tmpMouseY);}/**
1646
+ * Handle keyboard events
1647
+ * @param {KeyboardEvent} pEvent
1648
+ */},{key:"_onKeyDown",value:function _onKeyDown(pEvent){if(!this._FlowView)return;// Only handle events when the flow is focused/visible
1649
+ if(pEvent.key==='Delete'||pEvent.key==='Backspace'){// Don't delete if user is typing in an input or inside a panel
1650
+ if(pEvent.target&&(pEvent.target.tagName==='INPUT'||pEvent.target.tagName==='TEXTAREA'||pEvent.target.tagName==='SELECT')){return;}if(pEvent.target&&pEvent.target.closest&&pEvent.target.closest('.pict-flow-panel')){return;}this._FlowView.deleteSelected();pEvent.preventDefault();}else if(pEvent.key==='Escape'){if(this._State===INTERACTION_STATES.CONNECTING){this._cancelConnection();}// Exit fullscreen if currently in fullscreen mode
1651
+ if(this._FlowView._IsFullscreen){this._FlowView.exitFullscreen();// Update the toolbar button text
1652
+ if(this._FlowView._ToolbarView){var tmpFlowViewIdentifier=this._FlowView.options.ViewIdentifier;var tmpBtnElements=this._FlowView.pict.ContentAssignment.getElement("#Flow-Toolbar-Fullscreen-".concat(tmpFlowViewIdentifier));if(tmpBtnElements.length>0){tmpBtnElements[0].innerHTML='&#x26F6; Fullscreen';}}pEvent.preventDefault();return;}this._FlowView.deselectAll();}}// ---- Node Dragging ----
1653
+ },{key:"_startNodeDrag",value:function _startNodeDrag(pEvent,pTarget){if(!this._FlowView.options.EnableNodeDragging)return;var tmpNodeHash=this._getNodeHash(pTarget);if(!tmpNodeHash)return;this._FlowView.selectNode(tmpNodeHash);var tmpNode=this._FlowView.getNode(tmpNodeHash);if(!tmpNode)return;this._State=INTERACTION_STATES.DRAGGING_NODE;this._DragNodeHash=tmpNodeHash;this._DragStartX=pEvent.clientX;this._DragStartY=pEvent.clientY;this._DragNodeStartX=tmpNode.X;this._DragNodeStartY=tmpNode.Y;this._SVGElement.classList.add('panning');var tmpNodeGroup=this._FlowView._NodesLayer.querySelector("[data-node-hash=\"".concat(tmpNodeHash,"\"]"));if(tmpNodeGroup){tmpNodeGroup.classList.add('dragging');}}},{key:"_onNodeDrag",value:function _onNodeDrag(pEvent){if(!this._DragNodeHash)return;var tmpVS=this._FlowView.viewState;var tmpDX=(pEvent.clientX-this._DragStartX)/tmpVS.Zoom;var tmpDY=(pEvent.clientY-this._DragStartY)/tmpVS.Zoom;var tmpNewX=this._DragNodeStartX+tmpDX;var tmpNewY=this._DragNodeStartY+tmpDY;this._FlowView.updateNodePosition(this._DragNodeHash,tmpNewX,tmpNewY);}},{key:"_endNodeDrag",value:function _endNodeDrag(pEvent){this._SVGElement.classList.remove('panning');var tmpNodeGroup=this._FlowView._NodesLayer.querySelector("[data-node-hash=\"".concat(this._DragNodeHash,"\"]"));if(tmpNodeGroup){tmpNodeGroup.classList.remove('dragging');}this._FlowView.renderFlow();this._FlowView.marshalFromView();var tmpNode=this._FlowView.getNode(this._DragNodeHash);if(tmpNode&&this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onNodeMoved',tmpNode);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView.flowData);}this._State=INTERACTION_STATES.IDLE;this._DragNodeHash=null;}// ---- Panel Dragging ----
1654
+ },{key:"_startPanelDrag",value:function _startPanelDrag(pEvent,pTarget){var tmpPanelHash=this._getPanelHash(pTarget);if(!tmpPanelHash)return;var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===tmpPanelHash;});if(!tmpPanel)return;this._State=INTERACTION_STATES.DRAGGING_PANEL;this._DragPanelHash=tmpPanelHash;this._DragPanelStartX=pEvent.clientX;this._DragPanelStartY=pEvent.clientY;this._DragPanelDataStartX=tmpPanel.X;this._DragPanelDataStartY=tmpPanel.Y;this._SVGElement.classList.add('panning');}},{key:"_onPanelDrag",value:function _onPanelDrag(pEvent){if(!this._DragPanelHash)return;var tmpVS=this._FlowView.viewState;var tmpDX=(pEvent.clientX-this._DragPanelStartX)/tmpVS.Zoom;var tmpDY=(pEvent.clientY-this._DragPanelStartY)/tmpVS.Zoom;var tmpNewX=this._DragPanelDataStartX+tmpDX;var tmpNewY=this._DragPanelDataStartY+tmpDY;this._FlowView.updatePanelPosition(this._DragPanelHash,tmpNewX,tmpNewY);}},{key:"_endPanelDrag",value:function _endPanelDrag(pEvent){var _this39=this;this._SVGElement.classList.remove('panning');this._FlowView.marshalFromView();var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===_this39._DragPanelHash;});if(tmpPanel&&this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onPanelMoved',tmpPanel);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView.flowData);}this._State=INTERACTION_STATES.IDLE;this._DragPanelHash=null;}// ---- Panel Resizing ----
1655
+ },{key:"_startPanelResize",value:function _startPanelResize(pEvent,pTarget){var tmpPanelHash=this._getPanelHash(pTarget);if(!tmpPanelHash)return;var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===tmpPanelHash;});if(!tmpPanel)return;this._State=INTERACTION_STATES.RESIZING_PANEL;this._ResizePanelHash=tmpPanelHash;this._ResizeStartY=pEvent.clientY;this._ResizePanelStartHeight=tmpPanel.Height;this._SVGElement.classList.add('panning');}},{key:"_onPanelResize",value:function _onPanelResize(pEvent){var _this40=this;if(!this._ResizePanelHash)return;var tmpVS=this._FlowView.viewState;var tmpDY=(pEvent.clientY-this._ResizeStartY)/tmpVS.Zoom;var tmpNewHeight=Math.max(120,this._ResizePanelStartHeight+tmpDY);// Update the panel data
1656
+ var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===_this40._ResizePanelHash;});if(tmpPanel){tmpPanel.Height=tmpNewHeight;}// Update the foreignObject height directly for smooth resizing
1657
+ if(this._FlowView._PanelsLayer){var tmpFO=this._FlowView._PanelsLayer.querySelector('[data-panel-hash="'+this._ResizePanelHash+'"]');if(tmpFO){tmpFO.setAttribute('height',String(tmpNewHeight));}}}},{key:"_endPanelResize",value:function _endPanelResize(pEvent){this._SVGElement.classList.remove('panning');// Re-render to sync tethers
1658
+ this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView.flowData);}this._State=INTERACTION_STATES.IDLE;this._ResizePanelHash=null;}// ---- Handle Dragging ----
1659
+ },{key:"_startHandleDrag",value:function _startHandleDrag(pEvent,pConnectionHash,pPanelHash,pHandleType,pIsTether){this._State=INTERACTION_STATES.DRAGGING_HANDLE;this._DragHandleConnectionHash=pConnectionHash;this._DragHandlePanelHash=pPanelHash;this._DragHandleType=pHandleType;this._DragHandleIsTether=pIsTether;this._DragStartX=pEvent.clientX;this._DragStartY=pEvent.clientY;this._SVGElement.classList.add('panning');}},{key:"_onHandleDrag",value:function _onHandleDrag(pEvent){var tmpCoords=this._FlowView.screenToSVGCoords(pEvent.clientX,pEvent.clientY);if(this._DragHandleIsTether){this._FlowView.updateTetherHandle(this._DragHandlePanelHash,this._DragHandleType,tmpCoords.x,tmpCoords.y);}else{this._FlowView.updateConnectionHandle(this._DragHandleConnectionHash,this._DragHandleType,tmpCoords.x,tmpCoords.y);}}},{key:"_endHandleDrag",value:function _endHandleDrag(pEvent){var _this41=this;this._SVGElement.classList.remove('panning');this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView.flowData);if(this._DragHandleIsTether){var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===_this41._DragHandlePanelHash;});if(tmpPanel){this._FlowView._EventHandlerProvider.fireEvent('onTetherHandleMoved',tmpPanel);}}else{var tmpConnection=this._FlowView.getConnection(this._DragHandleConnectionHash);if(tmpConnection){this._FlowView._EventHandlerProvider.fireEvent('onConnectionHandleMoved',tmpConnection);}}}this._State=INTERACTION_STATES.IDLE;this._DragHandleConnectionHash=null;this._DragHandlePanelHash=null;this._DragHandleType=null;this._DragHandleIsTether=false;}// ---- Right-Click Handle Add/Remove ----
1660
+ /**
1661
+ * Add a bezier handle to a connection at the right-click position.
1662
+ * @param {Element} pTarget - The SVG element that was right-clicked
1663
+ * @param {MouseEvent} pEvent - The contextmenu event
1664
+ */},{key:"_addBezierHandle",value:function _addBezierHandle(pTarget,pEvent){var tmpConnectionHash=this._getConnectionHash(pTarget);if(!tmpConnectionHash)return;// Select the connection so handle circles are rendered after the re-render
1665
+ this._FlowView.selectConnection(tmpConnectionHash);var tmpCoords=this._FlowView.screenToSVGCoords(pEvent.clientX,pEvent.clientY);this._FlowView.addConnectionHandle(tmpConnectionHash,tmpCoords.x,tmpCoords.y);}/**
1666
+ * Remove a bezier handle from a connection.
1667
+ * @param {Element} pTarget - The handle SVG element that was right-clicked
1668
+ */},{key:"_removeBezierHandle",value:function _removeBezierHandle(pTarget){var tmpConnectionHash=this._getConnectionHash(pTarget);if(!tmpConnectionHash)return;var tmpHandleType=pTarget.getAttribute('data-handle-type');if(!tmpHandleType||!tmpHandleType.startsWith('bezier-handle-'))return;var tmpIndex=parseInt(tmpHandleType.replace('bezier-handle-',''),10);if(isNaN(tmpIndex))return;this._FlowView.removeConnectionHandle(tmpConnectionHash,tmpIndex);}/**
1669
+ * Add a bezier handle to a tether.
1670
+ * @param {Element} pTarget - The tether SVG element that was right-clicked or double-clicked
1671
+ * @param {Event} pEvent - The mouse event (for coordinate extraction)
1672
+ */},{key:"_addTetherBezierHandle",value:function _addTetherBezierHandle(pTarget,pEvent){var tmpPanelHash=this._getPanelHash(pTarget);if(!tmpPanelHash)return;// Select the tether so handles render after re-render
1673
+ this._FlowView.selectTether(tmpPanelHash);var tmpCoords=this._FlowView.screenToSVGCoords(pEvent.clientX,pEvent.clientY);this._FlowView.addTetherHandle(tmpPanelHash,tmpCoords.x,tmpCoords.y);}/**
1674
+ * Remove a bezier handle from a tether.
1675
+ * @param {Element} pTarget - The tether handle SVG element that was right-clicked
1676
+ */},{key:"_removeTetherBezierHandle",value:function _removeTetherBezierHandle(pTarget){var tmpPanelHash=this._getPanelHash(pTarget);if(!tmpPanelHash)return;var tmpHandleType=pTarget.getAttribute('data-handle-type');if(!tmpHandleType||!tmpHandleType.startsWith('bezier-handle-'))return;var tmpIndex=parseInt(tmpHandleType.replace('bezier-handle-',''),10);if(isNaN(tmpIndex))return;this._FlowView.removeTetherHandle(tmpPanelHash,tmpIndex);}// ---- Line Mode Toggling ----
1677
+ },{key:"_toggleConnectionLineMode",value:function _toggleConnectionLineMode(pConnectionHash){var tmpConnection=this._FlowView.getConnection(pConnectionHash);if(!tmpConnection)return;if(!tmpConnection.Data)tmpConnection.Data={};var tmpCurrentMode=tmpConnection.Data.LineMode||'bezier';tmpConnection.Data.LineMode=tmpCurrentMode==='bezier'?'orthogonal':'bezier';// Reset handle positions when switching modes
1678
+ tmpConnection.Data.HandleCustomized=false;tmpConnection.Data.BezierHandles=[];tmpConnection.Data.BezierHandleX=null;tmpConnection.Data.BezierHandleY=null;tmpConnection.Data.OrthoCorner1X=null;tmpConnection.Data.OrthoCorner1Y=null;tmpConnection.Data.OrthoCorner2X=null;tmpConnection.Data.OrthoCorner2Y=null;tmpConnection.Data.OrthoMidOffset=0;this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onConnectionModeChanged',tmpConnection);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView.flowData);}}},{key:"_toggleTetherLineMode",value:function _toggleTetherLineMode(pPanelHash){var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===pPanelHash;});if(!tmpPanel)return;if(this._FlowView._TetherService){this._FlowView._TetherService.toggleLineMode(tmpPanel);}this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onTetherModeChanged',tmpPanel);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView.flowData);}}// ---- Tether Selection ----
1679
+ },{key:"_selectTether",value:function _selectTether(pTarget){var tmpPanelHash=this._getPanelHash(pTarget);if(tmpPanelHash){this._FlowView.selectTether(tmpPanelHash);}}// ---- Connection Creation ----
1680
+ },{key:"_startConnection",value:function _startConnection(pEvent,pTarget){if(!this._FlowView.options.EnableConnectionCreation)return;var tmpNodeHash=pTarget.getAttribute('data-node-hash');var tmpPortHash=pTarget.getAttribute('data-port-hash');var tmpPortDirection=pTarget.getAttribute('data-port-direction');if(!tmpNodeHash||!tmpPortHash)return;if(tmpPortDirection!=='output'){return;}this._State=INTERACTION_STATES.CONNECTING;this._ConnectSourceNodeHash=tmpNodeHash;this._ConnectSourcePortHash=tmpPortHash;this._SVGElement.classList.add('connecting');var tmpPortPos=this._FlowView.getPortPosition(tmpNodeHash,tmpPortHash);if(tmpPortPos){this._ConnectDragLine=document.createElementNS('http://www.w3.org/2000/svg','path');this._ConnectDragLine.setAttribute('class','pict-flow-drag-connection');this._ConnectDragLine.setAttribute('d',"M ".concat(tmpPortPos.x," ").concat(tmpPortPos.y," L ").concat(tmpPortPos.x," ").concat(tmpPortPos.y));this._FlowView._ViewportElement.appendChild(this._ConnectDragLine);}pEvent.stopPropagation();}},{key:"_onConnectionDrag",value:function _onConnectionDrag(pEvent){if(!this._ConnectDragLine)return;var tmpSourcePos=this._FlowView.getPortPosition(this._ConnectSourceNodeHash,this._ConnectSourcePortHash);if(!tmpSourcePos)return;var tmpEndCoords=this._FlowView.screenToSVGCoords(pEvent.clientX,pEvent.clientY);var tmpDX=Math.abs(tmpEndCoords.x-tmpSourcePos.x)*0.5;var tmpPath="M ".concat(tmpSourcePos.x," ").concat(tmpSourcePos.y," C ").concat(tmpSourcePos.x+tmpDX," ").concat(tmpSourcePos.y,", ").concat(tmpEndCoords.x-tmpDX," ").concat(tmpEndCoords.y,", ").concat(tmpEndCoords.x," ").concat(tmpEndCoords.y);this._ConnectDragLine.setAttribute('d',tmpPath);}},{key:"_endConnection",value:function _endConnection(pEvent){if(this._ConnectDragLine&&this._ConnectDragLine.parentNode){this._ConnectDragLine.parentNode.removeChild(this._ConnectDragLine);}this._ConnectDragLine=null;this._SVGElement.classList.remove('connecting');var tmpTarget=document.elementFromPoint(pEvent.clientX,pEvent.clientY);if(tmpTarget){var tmpTargetPortHash=tmpTarget.getAttribute('data-port-hash');var tmpTargetNodeHash=tmpTarget.getAttribute('data-node-hash');var tmpTargetPortDirection=tmpTarget.getAttribute('data-port-direction');if(tmpTargetPortHash&&tmpTargetNodeHash&&tmpTargetPortDirection==='input'){this._FlowView.addConnection(this._ConnectSourceNodeHash,this._ConnectSourcePortHash,tmpTargetNodeHash,tmpTargetPortHash);}}this._State=INTERACTION_STATES.IDLE;this._ConnectSourceNodeHash=null;this._ConnectSourcePortHash=null;}},{key:"_cancelConnection",value:function _cancelConnection(){if(this._ConnectDragLine&&this._ConnectDragLine.parentNode){this._ConnectDragLine.parentNode.removeChild(this._ConnectDragLine);}this._ConnectDragLine=null;this._SVGElement.classList.remove('connecting');this._State=INTERACTION_STATES.IDLE;this._ConnectSourceNodeHash=null;this._ConnectSourcePortHash=null;}// ---- Panning ----
1681
+ },{key:"_startPanning",value:function _startPanning(pEvent){this._FlowView.deselectAll();this._State=INTERACTION_STATES.PANNING;this._PanStartX=pEvent.clientX;this._PanStartY=pEvent.clientY;this._PanStartPanX=this._FlowView.viewState.PanX;this._PanStartPanY=this._FlowView.viewState.PanY;this._SVGElement.classList.add('panning');}},{key:"_onPan",value:function _onPan(pEvent){var tmpDX=pEvent.clientX-this._PanStartX;var tmpDY=pEvent.clientY-this._PanStartY;this._FlowView.viewState.PanX=this._PanStartPanX+tmpDX;this._FlowView.viewState.PanY=this._PanStartPanY+tmpDY;this._FlowView.updateViewportTransform();}},{key:"_endPanning",value:function _endPanning(pEvent){this._SVGElement.classList.remove('panning');this._State=INTERACTION_STATES.IDLE;}// ---- Connection Selection ----
1682
+ },{key:"_selectConnection",value:function _selectConnection(pTarget){var tmpConnectionHash=this._getConnectionHash(pTarget);if(tmpConnectionHash){this._FlowView.selectConnection(tmpConnectionHash);}}// ---- Utilities ----
1683
+ },{key:"_getElementType",value:function _getElementType(pTarget){if(!pTarget)return'background';var tmpType=pTarget.getAttribute?pTarget.getAttribute('data-element-type'):null;if(tmpType)return tmpType;var tmpParent=pTarget.parentElement;var tmpDepth=0;while(tmpParent&&tmpDepth<5){tmpType=tmpParent.getAttribute?tmpParent.getAttribute('data-element-type'):null;if(tmpType)return tmpType;tmpParent=tmpParent.parentElement;tmpDepth++;}return'background';}},{key:"_getNodeHash",value:function _getNodeHash(pTarget){if(!pTarget)return null;var tmpHash=pTarget.getAttribute?pTarget.getAttribute('data-node-hash'):null;if(tmpHash)return tmpHash;var tmpParent=pTarget.parentElement;var tmpDepth=0;while(tmpParent&&tmpDepth<5){tmpHash=tmpParent.getAttribute?tmpParent.getAttribute('data-node-hash'):null;if(tmpHash)return tmpHash;tmpParent=tmpParent.parentElement;tmpDepth++;}return null;}},{key:"_getPanelHash",value:function _getPanelHash(pTarget){if(!pTarget)return null;var tmpHash=pTarget.getAttribute?pTarget.getAttribute('data-panel-hash'):null;if(tmpHash)return tmpHash;var tmpParent=pTarget.parentElement;var tmpDepth=0;while(tmpParent&&tmpDepth<5){tmpHash=tmpParent.getAttribute?tmpParent.getAttribute('data-panel-hash'):null;if(tmpHash)return tmpHash;tmpParent=tmpParent.parentElement;tmpDepth++;}return null;}},{key:"_getConnectionHash",value:function _getConnectionHash(pTarget){if(!pTarget)return null;var tmpHash=pTarget.getAttribute?pTarget.getAttribute('data-connection-hash'):null;if(tmpHash)return tmpHash;var tmpParent=pTarget.parentElement;var tmpDepth=0;while(tmpParent&&tmpDepth<5){tmpHash=tmpParent.getAttribute?tmpParent.getAttribute('data-connection-hash'):null;if(tmpHash)return tmpHash;tmpParent=tmpParent.parentElement;tmpDepth++;}return null;}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowInteractionManager;module.exports.INTERACTION_STATES=INTERACTION_STATES;},{"fable-serviceproviderbase":4}],31:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');var PictServiceFlowLayout=/*#__PURE__*/function(_libFableServiceProvi13){function PictServiceFlowLayout(pFable,pOptions,pServiceHash){var _this42;_classCallCheck(this,PictServiceFlowLayout);_this42=_callSuper(this,PictServiceFlowLayout,[pFable,pOptions,pServiceHash]);_this42.serviceType='PictServiceFlowLayout';_this42._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;// Layout configuration
1684
+ _this42._HorizontalSpacing=250;_this42._VerticalSpacing=120;_this42._StartX=100;_this42._StartY=100;return _this42;}/**
1685
+ * Snap a coordinate to the nearest grid point
1686
+ * @param {number} pValue - The coordinate value
1687
+ * @param {number} pGridSize - The grid size
1688
+ * @returns {number}
1689
+ */_inherits(PictServiceFlowLayout,_libFableServiceProvi13);return _createClass(PictServiceFlowLayout,[{key:"snapToGrid",value:function snapToGrid(pValue,pGridSize){if(!pGridSize||pGridSize<=0)return pValue;return Math.round(pValue/pGridSize)*pGridSize;}/**
1690
+ * Auto-layout nodes using a simple left-to-right topological approach
1691
+ * @param {Array} pNodes - Array of node data objects
1692
+ * @param {Array} pConnections - Array of connection data objects
1693
+ */},{key:"autoLayout",value:function autoLayout(pNodes,pConnections){if(!pNodes||pNodes.length===0)return;// Build adjacency information
1694
+ var tmpNodeMap={};var tmpInDegree={};var tmpOutEdges={};for(var i=0;i<pNodes.length;i++){var tmpNode=pNodes[i];tmpNodeMap[tmpNode.Hash]=tmpNode;tmpInDegree[tmpNode.Hash]=0;tmpOutEdges[tmpNode.Hash]=[];}for(var _i32=0;_i32<pConnections.length;_i32++){var tmpConn=pConnections[_i32];if(tmpInDegree.hasOwnProperty(tmpConn.TargetNodeHash)){tmpInDegree[tmpConn.TargetNodeHash]++;}if(tmpOutEdges.hasOwnProperty(tmpConn.SourceNodeHash)){tmpOutEdges[tmpConn.SourceNodeHash].push(tmpConn.TargetNodeHash);}}// Topological sort (Kahn's algorithm)
1695
+ var tmpLayers=[];var tmpQueue=[];var tmpAssigned={};// Start with nodes that have no incoming edges
1696
+ for(var tmpHash in tmpInDegree){if(tmpInDegree[tmpHash]===0){tmpQueue.push(tmpHash);}}while(tmpQueue.length>0){var tmpCurrentLayer=[];var tmpNextQueue=[];for(var _i33=0;_i33<tmpQueue.length;_i33++){var tmpNodeHash=tmpQueue[_i33];if(tmpAssigned[tmpNodeHash])continue;tmpAssigned[tmpNodeHash]=true;tmpCurrentLayer.push(tmpNodeHash);// Process outgoing edges
1697
+ var tmpEdges=tmpOutEdges[tmpNodeHash]||[];for(var j=0;j<tmpEdges.length;j++){var tmpTargetHash=tmpEdges[j];tmpInDegree[tmpTargetHash]--;if(tmpInDegree[tmpTargetHash]<=0&&!tmpAssigned[tmpTargetHash]){tmpNextQueue.push(tmpTargetHash);}}}if(tmpCurrentLayer.length>0){tmpLayers.push(tmpCurrentLayer);}tmpQueue=tmpNextQueue;}// Handle any remaining unassigned nodes (cycles or disconnected)
1698
+ var tmpRemainingNodes=[];for(var _i34=0;_i34<pNodes.length;_i34++){if(!tmpAssigned[pNodes[_i34].Hash]){tmpRemainingNodes.push(pNodes[_i34].Hash);}}if(tmpRemainingNodes.length>0){tmpLayers.push(tmpRemainingNodes);}// Assign positions based on layers
1699
+ var tmpCurrentX=this._StartX;for(var tmpLayerIndex=0;tmpLayerIndex<tmpLayers.length;tmpLayerIndex++){var tmpLayer=tmpLayers[tmpLayerIndex];var tmpMaxWidth=0;// Calculate the total height for this layer to center vertically
1700
+ var tmpTotalHeight=0;for(var _i35=0;_i35<tmpLayer.length;_i35++){var _tmpNode=tmpNodeMap[tmpLayer[_i35]];if(_tmpNode){tmpTotalHeight+=_tmpNode.Height||80;if(_i35<tmpLayer.length-1){tmpTotalHeight+=this._VerticalSpacing;}}}var tmpCurrentY=this._StartY;for(var _i36=0;_i36<tmpLayer.length;_i36++){var _tmpNode2=tmpNodeMap[tmpLayer[_i36]];if(!_tmpNode2)continue;_tmpNode2.X=tmpCurrentX;_tmpNode2.Y=tmpCurrentY;var tmpWidth=_tmpNode2.Width||180;var tmpHeight=_tmpNode2.Height||80;tmpMaxWidth=Math.max(tmpMaxWidth,tmpWidth);tmpCurrentY+=tmpHeight+this._VerticalSpacing;}tmpCurrentX+=tmpMaxWidth+this._HorizontalSpacing;}}/**
1701
+ * Auto-layout a subset of nodes, positioning them to the right of
1702
+ * any fixed (already-positioned) nodes.
1703
+ *
1704
+ * Uses the same topological sort approach as autoLayout, but only
1705
+ * repositions the nodes in pNodesToLayout. The pFixedNodes are used
1706
+ * to compute a bounding box that the new layout avoids.
1707
+ *
1708
+ * @param {Array} pNodesToLayout - Nodes that need new positions
1709
+ * @param {Array} pFixedNodes - Nodes that already have positions (read-only)
1710
+ * @param {Array} pConnections - All connections in the flow
1711
+ */},{key:"autoLayoutSubset",value:function autoLayoutSubset(pNodesToLayout,pFixedNodes,pConnections){if(!pNodesToLayout||pNodesToLayout.length===0)return;// Compute the starting X position to the right of all fixed nodes
1712
+ var tmpStartX=this._StartX;var tmpStartY=this._StartY;if(pFixedNodes&&pFixedNodes.length>0){var tmpMaxX=-Infinity;for(var i=0;i<pFixedNodes.length;i++){var tmpRight=pFixedNodes[i].X+(pFixedNodes[i].Width||180);if(tmpRight>tmpMaxX){tmpMaxX=tmpRight;}}// Place unmatched nodes to the right of all fixed nodes
1713
+ tmpStartX=tmpMaxX+this._HorizontalSpacing;}// Build a set of nodes we are laying out for quick lookup
1714
+ var tmpNodeSet={};for(var _i37=0;_i37<pNodesToLayout.length;_i37++){tmpNodeSet[pNodesToLayout[_i37].Hash]=true;}// Build adjacency information only for nodes in the subset
1715
+ var tmpNodeMap={};var tmpInDegree={};var tmpOutEdges={};for(var _i38=0;_i38<pNodesToLayout.length;_i38++){var tmpNode=pNodesToLayout[_i38];tmpNodeMap[tmpNode.Hash]=tmpNode;tmpInDegree[tmpNode.Hash]=0;tmpOutEdges[tmpNode.Hash]=[];}// Only count edges between nodes in the subset
1716
+ for(var _i39=0;_i39<pConnections.length;_i39++){var tmpConn=pConnections[_i39];var tmpSourceInSubset=tmpNodeSet[tmpConn.SourceNodeHash];var tmpTargetInSubset=tmpNodeSet[tmpConn.TargetNodeHash];if(tmpSourceInSubset&&tmpTargetInSubset){tmpInDegree[tmpConn.TargetNodeHash]++;tmpOutEdges[tmpConn.SourceNodeHash].push(tmpConn.TargetNodeHash);}}// Topological sort (Kahn's algorithm)
1717
+ var tmpLayers=[];var tmpQueue=[];var tmpAssigned={};for(var tmpHash in tmpInDegree){if(tmpInDegree[tmpHash]===0){tmpQueue.push(tmpHash);}}while(tmpQueue.length>0){var tmpCurrentLayer=[];var tmpNextQueue=[];for(var _i40=0;_i40<tmpQueue.length;_i40++){var tmpNodeHash=tmpQueue[_i40];if(tmpAssigned[tmpNodeHash])continue;tmpAssigned[tmpNodeHash]=true;tmpCurrentLayer.push(tmpNodeHash);var tmpEdges=tmpOutEdges[tmpNodeHash]||[];for(var j=0;j<tmpEdges.length;j++){var tmpTargetHash=tmpEdges[j];tmpInDegree[tmpTargetHash]--;if(tmpInDegree[tmpTargetHash]<=0&&!tmpAssigned[tmpTargetHash]){tmpNextQueue.push(tmpTargetHash);}}}if(tmpCurrentLayer.length>0){tmpLayers.push(tmpCurrentLayer);}tmpQueue=tmpNextQueue;}// Handle remaining unassigned nodes (cycles or disconnected)
1718
+ var tmpRemainingNodes=[];for(var _i41=0;_i41<pNodesToLayout.length;_i41++){if(!tmpAssigned[pNodesToLayout[_i41].Hash]){tmpRemainingNodes.push(pNodesToLayout[_i41].Hash);}}if(tmpRemainingNodes.length>0){tmpLayers.push(tmpRemainingNodes);}// Assign positions based on layers, starting from tmpStartX
1719
+ var tmpCurrentX=tmpStartX;for(var tmpLayerIndex=0;tmpLayerIndex<tmpLayers.length;tmpLayerIndex++){var tmpLayer=tmpLayers[tmpLayerIndex];var tmpMaxWidth=0;var tmpCurrentY=tmpStartY;for(var _i42=0;_i42<tmpLayer.length;_i42++){var _tmpNode3=tmpNodeMap[tmpLayer[_i42]];if(!_tmpNode3)continue;_tmpNode3.X=tmpCurrentX;_tmpNode3.Y=tmpCurrentY;var tmpWidth=_tmpNode3.Width||180;var tmpHeight=_tmpNode3.Height||80;tmpMaxWidth=Math.max(tmpMaxWidth,tmpWidth);tmpCurrentY+=tmpHeight+this._VerticalSpacing;}tmpCurrentX+=tmpMaxWidth+this._HorizontalSpacing;}}/**
1720
+ * Center all nodes around a given point
1721
+ * @param {Array} pNodes
1722
+ * @param {number} pCenterX
1723
+ * @param {number} pCenterY
1724
+ */},{key:"centerNodes",value:function centerNodes(pNodes,pCenterX,pCenterY){if(!pNodes||pNodes.length===0)return;var tmpMinX=Infinity,tmpMinY=Infinity;var tmpMaxX=-Infinity,tmpMaxY=-Infinity;for(var i=0;i<pNodes.length;i++){tmpMinX=Math.min(tmpMinX,pNodes[i].X);tmpMinY=Math.min(tmpMinY,pNodes[i].Y);tmpMaxX=Math.max(tmpMaxX,pNodes[i].X+(pNodes[i].Width||180));tmpMaxY=Math.max(tmpMaxY,pNodes[i].Y+(pNodes[i].Height||80));}var tmpCurrentCenterX=(tmpMinX+tmpMaxX)/2;var tmpCurrentCenterY=(tmpMinY+tmpMaxY)/2;var tmpOffsetX=pCenterX-tmpCurrentCenterX;var tmpOffsetY=pCenterY-tmpCurrentCenterY;for(var _i43=0;_i43<pNodes.length;_i43++){pNodes[_i43].X+=tmpOffsetX;pNodes[_i43].Y+=tmpOffsetY;}}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowLayout;},{"fable-serviceproviderbase":4}],32:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1725
+ * PictService-Flow-PanelManager
1726
+ *
1727
+ * Manages the lifecycle of properties panels in the flow diagram:
1728
+ * opening, closing, toggling, and position updates for panels
1729
+ * associated with flow nodes.
1730
+ */var PictServiceFlowPanelManager=/*#__PURE__*/function(_libFableServiceProvi14){function PictServiceFlowPanelManager(pFable,pOptions,pServiceHash){var _this43;_classCallCheck(this,PictServiceFlowPanelManager);_this43=_callSuper(this,PictServiceFlowPanelManager,[pFable,pOptions,pServiceHash]);_this43.serviceType='PictServiceFlowPanelManager';_this43._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this43;}/**
1731
+ * Open a properties panel for a node.
1732
+ * @param {string} pNodeHash - The hash of the node to open a panel for
1733
+ * @returns {Object|false} The panel data, or false if the node was not found
1734
+ */_inherits(PictServiceFlowPanelManager,_libFableServiceProvi14);return _createClass(PictServiceFlowPanelManager,[{key:"openPanel",value:function openPanel(pNodeHash){var tmpNode=this._FlowView.getNode(pNodeHash);if(!tmpNode)return false;var tmpNodeTypeConfig=this._FlowView._NodeTypeProvider.getNodeType(tmpNode.Type);if(!tmpNodeTypeConfig)return false;// Check if a panel is already open for this node
1735
+ var tmpExisting=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.NodeHash===pNodeHash;});if(tmpExisting)return tmpExisting;var tmpPanelConfig=tmpNodeTypeConfig.PropertiesPanel;var tmpPanelHash="panel-".concat(this.fable.getUUID());var tmpWidth,tmpHeight,tmpPanelType,tmpTitle;if(tmpPanelConfig){tmpWidth=tmpPanelConfig.DefaultWidth||300;tmpHeight=tmpPanelConfig.DefaultHeight||200;tmpPanelType=tmpPanelConfig.PanelType||'Base';tmpTitle=tmpPanelConfig.Title||tmpNodeTypeConfig.Label||'Properties';}else{// No PropertiesPanel configured — open an auto-generated info panel
1736
+ tmpWidth=240;tmpHeight=180;tmpPanelType='Info';tmpTitle=tmpNodeTypeConfig.Label||tmpNode.Title||'Node Info';}var tmpPanelData={Hash:tmpPanelHash,NodeHash:pNodeHash,PanelType:tmpPanelType,Title:tmpTitle,X:tmpNode.X+tmpNode.Width+30,Y:tmpNode.Y,Width:tmpWidth,Height:tmpHeight};this._FlowView._FlowData.OpenPanels.push(tmpPanelData);this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onPanelOpened',tmpPanelData);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}return tmpPanelData;}/**
1737
+ * Close a properties panel by panel hash.
1738
+ * @param {string} pPanelHash
1739
+ * @returns {boolean}
1740
+ */},{key:"closePanel",value:function closePanel(pPanelHash){var tmpIndex=this._FlowView._FlowData.OpenPanels.findIndex(function(pPanel){return pPanel.Hash===pPanelHash;});if(tmpIndex<0)return false;var tmpRemovedPanel=this._FlowView._FlowData.OpenPanels.splice(tmpIndex,1)[0];// Clean up the panel instance
1741
+ if(this._FlowView._PropertiesPanelView){this._FlowView._PropertiesPanelView.destroyPanel(pPanelHash);}this._FlowView.renderFlow();this._FlowView.marshalFromView();if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onPanelClosed',tmpRemovedPanel);this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}return true;}/**
1742
+ * Close all panels for a given node.
1743
+ * @param {string} pNodeHash
1744
+ * @returns {boolean}
1745
+ */},{key:"closePanelForNode",value:function closePanelForNode(pNodeHash){var tmpPanelsToClose=this._FlowView._FlowData.OpenPanels.filter(function(pPanel){return pPanel.NodeHash===pNodeHash;});if(tmpPanelsToClose.length===0)return false;for(var i=0;i<tmpPanelsToClose.length;i++){var tmpIndex=this._FlowView._FlowData.OpenPanels.indexOf(tmpPanelsToClose[i]);if(tmpIndex>=0){this._FlowView._FlowData.OpenPanels.splice(tmpIndex,1);}if(this._FlowView._PropertiesPanelView){this._FlowView._PropertiesPanelView.destroyPanel(tmpPanelsToClose[i].Hash);}}return true;}/**
1746
+ * Toggle a properties panel for a node (open if closed, close if open).
1747
+ * @param {string} pNodeHash
1748
+ * @returns {Object|false}
1749
+ */},{key:"togglePanel",value:function togglePanel(pNodeHash){var tmpExisting=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.NodeHash===pNodeHash;});if(tmpExisting){this.closePanel(tmpExisting.Hash);return false;}return this.openPanel(pNodeHash);}/**
1750
+ * Update a panel's position (for drag).
1751
+ * @param {string} pPanelHash
1752
+ * @param {number} pX
1753
+ * @param {number} pY
1754
+ */},{key:"updatePanelPosition",value:function updatePanelPosition(pPanelHash,pX,pY){var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===pPanelHash;});if(!tmpPanel)return;tmpPanel.X=pX;tmpPanel.Y=pY;// Reset tether handle positions when panel moves
1755
+ this._FlowView._resetHandlesForPanel(pPanelHash);// Update the foreignObject position directly for smooth dragging
1756
+ if(this._FlowView._PanelsLayer){var tmpFO=this._FlowView._PanelsLayer.querySelector("[data-panel-hash=\"".concat(pPanelHash,"\"]"));if(tmpFO){tmpFO.setAttribute('x',String(pX));tmpFO.setAttribute('y',String(pY));}}// Update the tether for this panel
1757
+ this._FlowView._renderTethersForNode(tmpPanel.NodeHash);}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowPanelManager;},{"fable-serviceproviderbase":4}],33:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1758
+ * PictService-Flow-PathGenerator
1759
+ *
1760
+ * Centralizes SVG path generation for the flow diagram.
1761
+ * Provides shared building blocks used by both the ConnectionRenderer
1762
+ * (port-to-port connections) and the TetherService (panel-to-node tethers).
1763
+ *
1764
+ * Responsibilities:
1765
+ * - Departure/approach point calculation from anchors
1766
+ * - Auto orthogonal corner computation for right-angle paths
1767
+ * - Cubic bezier evaluation at arbitrary parameter t
1768
+ * - SVG path string assembly (bezier, split-bezier, orthogonal)
1769
+ */var PictServiceFlowPathGenerator=/*#__PURE__*/function(_libFableServiceProvi15){function PictServiceFlowPathGenerator(pFable,pOptions,pServiceHash){var _this44;_classCallCheck(this,PictServiceFlowPathGenerator);_this44=_callSuper(this,PictServiceFlowPathGenerator,[pFable,pOptions,pServiceHash]);_this44.serviceType='PictServiceFlowPathGenerator';_this44._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this44;}// ---- Departure / Approach Calculation ----
1770
+ /**
1771
+ * Compute departure and approach points from start/end anchors.
1772
+ * The departure point extends outward from the start in its side direction,
1773
+ * and the approach point extends outward from the end in its side direction.
1774
+ *
1775
+ * @param {{x: number, y: number, side: string}} pFrom - Start anchor with side
1776
+ * @param {{x: number, y: number, side: string}} pTo - End anchor with side
1777
+ * @param {number} pDepartDist - Distance for departure/approach straight segments
1778
+ * @returns {{departX: number, departY: number, approachX: number, approachY: number, fromDir: {dx: number, dy: number}, toDir: {dx: number, dy: number}}}
1779
+ */_inherits(PictServiceFlowPathGenerator,_libFableServiceProvi15);return _createClass(PictServiceFlowPathGenerator,[{key:"computeDepartApproach",value:function computeDepartApproach(pFrom,pTo,pDepartDist){var tmpGeometry=this._FlowView._GeometryProvider;var tmpFromDir=tmpGeometry.sideDirection(pFrom.side||'right');var tmpToDir=tmpGeometry.sideDirection(pTo.side||'left');return{departX:pFrom.x+tmpFromDir.dx*pDepartDist,departY:pFrom.y+tmpFromDir.dy*pDepartDist,approachX:pTo.x+tmpToDir.dx*pDepartDist,approachY:pTo.y+tmpToDir.dy*pDepartDist,fromDir:tmpFromDir,toDir:tmpToDir};}// ---- Orthogonal Corner Calculation ----
1780
+ /**
1781
+ * Compute auto orthogonal corners for an L-shaped or Z-shaped path.
1782
+ * Determines corner placement based on departure/approach directions.
1783
+ *
1784
+ * Used by both connection and tether renderers for right-angle paths.
1785
+ *
1786
+ * @param {number} pDepartX
1787
+ * @param {number} pDepartY
1788
+ * @param {number} pApproachX
1789
+ * @param {number} pApproachY
1790
+ * @param {{dx: number, dy: number}} pFromDir - Departure direction vector
1791
+ * @param {{dx: number, dy: number}} pToDir - Approach direction vector
1792
+ * @param {number} pMidOffset - Offset for the corridor midpoint
1793
+ * @returns {{corner1: {x: number, y: number}, corner2: {x: number, y: number}, midpoint: {x: number, y: number}}}
1794
+ */},{key:"computeAutoOrthogonalCorners",value:function computeAutoOrthogonalCorners(pDepartX,pDepartY,pApproachX,pApproachY,pFromDir,pToDir,pMidOffset){var tmpOffset=pMidOffset||0;var tmpFromHoriz=Math.abs(pFromDir.dx)>0;var tmpToHoriz=Math.abs(pToDir.dx)>0;var tmpCorner1,tmpCorner2,tmpMidpoint;if(tmpFromHoriz&&tmpToHoriz){// Both horizontal departure/approach: corridor is vertical
1795
+ var tmpMidX=(pDepartX+pApproachX)/2+tmpOffset;tmpCorner1={x:tmpMidX,y:pDepartY};tmpCorner2={x:tmpMidX,y:pApproachY};tmpMidpoint={x:tmpMidX,y:(pDepartY+pApproachY)/2};}else if(!tmpFromHoriz&&!tmpToHoriz){// Both vertical: corridor is horizontal
1796
+ var tmpMidY=(pDepartY+pApproachY)/2+tmpOffset;tmpCorner1={x:pDepartX,y:tmpMidY};tmpCorner2={x:pApproachX,y:tmpMidY};tmpMidpoint={x:(pDepartX+pApproachX)/2,y:tmpMidY};}else if(tmpFromHoriz&&!tmpToHoriz){// Horizontal→Vertical: single L-bend
1797
+ tmpCorner1={x:pApproachX+tmpOffset,y:pDepartY};tmpCorner2={x:pApproachX+tmpOffset,y:pApproachY};tmpMidpoint={x:pApproachX+tmpOffset,y:(pDepartY+pApproachY)/2};}else{// Vertical→Horizontal: single L-bend
1798
+ tmpCorner1={x:pDepartX,y:pApproachY+tmpOffset};tmpCorner2={x:pApproachX,y:pApproachY+tmpOffset};tmpMidpoint={x:(pDepartX+pApproachX)/2,y:pApproachY+tmpOffset};}return{corner1:tmpCorner1,corner2:tmpCorner2,midpoint:tmpMidpoint};}// ---- Bezier Evaluation ----
1799
+ /**
1800
+ * Evaluate a cubic bezier curve at parameter t.
1801
+ * B(t) = (1-t)³P0 + 3(1-t)²tP1 + 3(1-t)t²P2 + t³P3
1802
+ *
1803
+ * @param {{x: number, y: number}} pP0 - Start point
1804
+ * @param {{x: number, y: number}} pP1 - First control point
1805
+ * @param {{x: number, y: number}} pP2 - Second control point
1806
+ * @param {{x: number, y: number}} pP3 - End point
1807
+ * @param {number} pT - Parameter in range [0, 1]
1808
+ * @returns {{x: number, y: number}}
1809
+ */},{key:"evaluateCubicBezier",value:function evaluateCubicBezier(pP0,pP1,pP2,pP3,pT){var tmpOMT=1-pT;var tmpOMT2=tmpOMT*tmpOMT;var tmpOMT3=tmpOMT2*tmpOMT;var tmpT2=pT*pT;var tmpT3=tmpT2*pT;return{x:tmpOMT3*pP0.x+3*tmpOMT2*pT*pP1.x+3*tmpOMT*tmpT2*pP2.x+tmpT3*pP3.x,y:tmpOMT3*pP0.y+3*tmpOMT2*pT*pP1.y+3*tmpOMT*tmpT2*pP2.y+tmpT3*pP3.y};}// ---- SVG Path String Assembly ----
1810
+ /**
1811
+ * Build an SVG bezier path string.
1812
+ * Pattern: M start L depart C cp1, cp2, approach L end
1813
+ *
1814
+ * @param {{x: number, y: number}} pStart - Start point
1815
+ * @param {{x: number, y: number}} pDepart - Departure point after straight segment
1816
+ * @param {{x: number, y: number}} pCP1 - First control point
1817
+ * @param {{x: number, y: number}} pCP2 - Second control point
1818
+ * @param {{x: number, y: number}} pApproach - Approach point before final straight segment
1819
+ * @param {{x: number, y: number}} pEnd - End point
1820
+ * @returns {string} SVG path d attribute
1821
+ */},{key:"buildBezierPathString",value:function buildBezierPathString(pStart,pDepart,pCP1,pCP2,pApproach,pEnd){return"M ".concat(pStart.x," ").concat(pStart.y," L ").concat(pDepart.x," ").concat(pDepart.y," C ").concat(pCP1.x," ").concat(pCP1.y,", ").concat(pCP2.x," ").concat(pCP2.y,", ").concat(pApproach.x," ").concat(pApproach.y," L ").concat(pEnd.x," ").concat(pEnd.y);}/**
1822
+ * Build an SVG split bezier path string (two cubic segments through a handle point).
1823
+ * Pattern: M start L depart C cp1a, cp1b, handle C cp2a, cp2b, approach L end
1824
+ *
1825
+ * @param {{x: number, y: number}} pStart
1826
+ * @param {{x: number, y: number}} pDepart
1827
+ * @param {{x: number, y: number}} pCP1a - First segment's first control point
1828
+ * @param {{x: number, y: number}} pCP1b - First segment's second control point
1829
+ * @param {{x: number, y: number}} pHandle - Handle point where the two segments meet
1830
+ * @param {{x: number, y: number}} pCP2a - Second segment's first control point
1831
+ * @param {{x: number, y: number}} pCP2b - Second segment's second control point
1832
+ * @param {{x: number, y: number}} pApproach
1833
+ * @param {{x: number, y: number}} pEnd
1834
+ * @returns {string} SVG path d attribute
1835
+ */},{key:"buildSplitBezierPathString",value:function buildSplitBezierPathString(pStart,pDepart,pCP1a,pCP1b,pHandle,pCP2a,pCP2b,pApproach,pEnd){return"M ".concat(pStart.x," ").concat(pStart.y," L ").concat(pDepart.x," ").concat(pDepart.y," C ").concat(pCP1a.x," ").concat(pCP1a.y,", ").concat(pCP1b.x," ").concat(pCP1b.y,", ").concat(pHandle.x," ").concat(pHandle.y," C ").concat(pCP2a.x," ").concat(pCP2a.y,", ").concat(pCP2b.x," ").concat(pCP2b.y,", ").concat(pApproach.x," ").concat(pApproach.y," L ").concat(pEnd.x," ").concat(pEnd.y);}/**
1836
+ * Build an SVG multi-segment bezier path string.
1837
+ * Generates N+1 cubic bezier segments through N handle points.
1838
+ *
1839
+ * Pattern: M start L depart C cp,cp,handle[0] C cp,cp,handle[1] ... C cp,cp,approach L end
1840
+ *
1841
+ * Control points are computed using Catmull-Rom-to-Bezier conversion
1842
+ * for C1 (smooth tangent) continuity at every handle.
1843
+ *
1844
+ * @param {{x: number, y: number}} pStart - Port anchor start
1845
+ * @param {{x: number, y: number}} pDepart - Departure point after straight segment
1846
+ * @param {Array<{x: number, y: number}>} pHandles - Ordered handle waypoints
1847
+ * @param {{x: number, y: number}} pApproach - Approach point before final straight segment
1848
+ * @param {{x: number, y: number}} pEnd - Port anchor end
1849
+ * @param {{dx: number, dy: number}} pStartDir - Departure direction unit vector
1850
+ * @param {{dx: number, dy: number}} pEndDir - Approach direction unit vector
1851
+ * @returns {string} SVG path d attribute
1852
+ */},{key:"buildMultiBezierPathString",value:function buildMultiBezierPathString(pStart,pDepart,pHandles,pApproach,pEnd,pStartDir,pEndDir){// Build the full list of waypoints: depart, handle[0..N-1], approach
1853
+ var tmpWaypoints=[pDepart];for(var i=0;i<pHandles.length;i++){tmpWaypoints.push(pHandles[i]);}tmpWaypoints.push(pApproach);var tmpPath="M ".concat(pStart.x," ").concat(pStart.y," L ").concat(pDepart.x," ").concat(pDepart.y);for(var _i44=0;_i44<tmpWaypoints.length-1;_i44++){var tmpFrom=tmpWaypoints[_i44];var tmpTo=tmpWaypoints[_i44+1];var tmpSegDX=tmpTo.x-tmpFrom.x;var tmpSegDY=tmpTo.y-tmpFrom.y;var tmpSegLen=Math.sqrt(tmpSegDX*tmpSegDX+tmpSegDY*tmpSegDY);if(tmpSegLen<1){tmpSegLen=1;}var tmpScale=tmpSegLen*0.35;// Tangent at tmpFrom
1854
+ var tmpTanFromX=void 0,tmpTanFromY=void 0;if(_i44===0){// First segment: use the port departure direction
1855
+ tmpTanFromX=pStartDir.dx;tmpTanFromY=pStartDir.dy;}else{// Interior handle: tangent points from previous toward next waypoint
1856
+ var tmpPrev=tmpWaypoints[_i44-1];var tmpNext=tmpWaypoints[_i44+1];tmpTanFromX=tmpNext.x-tmpPrev.x;tmpTanFromY=tmpNext.y-tmpPrev.y;var tmpTanLen=Math.sqrt(tmpTanFromX*tmpTanFromX+tmpTanFromY*tmpTanFromY);if(tmpTanLen<1)tmpTanLen=1;tmpTanFromX/=tmpTanLen;tmpTanFromY/=tmpTanLen;}// Tangent at tmpTo
1857
+ var tmpTanToX=void 0,tmpTanToY=void 0;if(_i44===tmpWaypoints.length-2){// Last segment: use the port approach direction (reversed for incoming)
1858
+ tmpTanToX=-pEndDir.dx;tmpTanToY=-pEndDir.dy;}else{// Interior handle: tangent points from previous toward next waypoint
1859
+ var _tmpPrev=tmpWaypoints[_i44];var _tmpNext=tmpWaypoints[_i44+2];tmpTanToX=_tmpNext.x-_tmpPrev.x;tmpTanToY=_tmpNext.y-_tmpPrev.y;var _tmpTanLen=Math.sqrt(tmpTanToX*tmpTanToX+tmpTanToY*tmpTanToY);if(_tmpTanLen<1)_tmpTanLen=1;tmpTanToX/=_tmpTanLen;tmpTanToY/=_tmpTanLen;}var tmpCP1X=tmpFrom.x+tmpTanFromX*tmpScale;var tmpCP1Y=tmpFrom.y+tmpTanFromY*tmpScale;var tmpCP2X=tmpTo.x-tmpTanToX*tmpScale;var tmpCP2Y=tmpTo.y-tmpTanToY*tmpScale;tmpPath+=" C ".concat(tmpCP1X," ").concat(tmpCP1Y,", ").concat(tmpCP2X," ").concat(tmpCP2Y,", ").concat(tmpTo.x," ").concat(tmpTo.y);}tmpPath+=" L ".concat(pEnd.x," ").concat(pEnd.y);return tmpPath;}/**
1860
+ * Build an SVG orthogonal (right-angle) path string.
1861
+ * Pattern: M start L depart L corner1 L corner2 L approach L end
1862
+ *
1863
+ * @param {{x: number, y: number}} pStart
1864
+ * @param {{x: number, y: number}} pDepart
1865
+ * @param {{x: number, y: number}} pCorner1
1866
+ * @param {{x: number, y: number}} pCorner2
1867
+ * @param {{x: number, y: number}} pApproach
1868
+ * @param {{x: number, y: number}} pEnd
1869
+ * @returns {string} SVG path d attribute
1870
+ */},{key:"buildOrthogonalPathString",value:function buildOrthogonalPathString(pStart,pDepart,pCorner1,pCorner2,pApproach,pEnd){return"M ".concat(pStart.x," ").concat(pStart.y," L ").concat(pDepart.x," ").concat(pDepart.y," L ").concat(pCorner1.x," ").concat(pCorner1.y," L ").concat(pCorner2.x," ").concat(pCorner2.y," L ").concat(pApproach.x," ").concat(pApproach.y," L ").concat(pEnd.x," ").concat(pEnd.y);}// ---- Directional Geometry ----
1871
+ /**
1872
+ * Compute full directional geometry between two port anchors, including
1873
+ * departure/approach points and bezier control points.
1874
+ *
1875
+ * Uses sophisticated facing detection: when ports face each other the
1876
+ * curve offset scales with inline distance; when ports are on the same
1877
+ * axis but not facing, a wider offset prevents the path from collapsing;
1878
+ * perpendicular exits use a moderate offset.
1879
+ *
1880
+ * @param {{x: number, y: number, side: string}} pStart
1881
+ * @param {{x: number, y: number, side: string}} pEnd
1882
+ * @returns {{departX: number, departY: number, approachX: number, approachY: number, cp1X: number, cp1Y: number, cp2X: number, cp2Y: number, startDir: {dx: number, dy: number}, endDir: {dx: number, dy: number}}}
1883
+ */},{key:"computeDirectionalGeometry",value:function computeDirectionalGeometry(pStart,pEnd){var tmpStartDir=this._FlowView._GeometryProvider.sideDirection(pStart.side||'right');var tmpEndDir=this._FlowView._GeometryProvider.sideDirection(pEnd.side||'left');var tmpStraightLen=20;var tmpDepartX=pStart.x+tmpStartDir.dx*tmpStraightLen;var tmpDepartY=pStart.y+tmpStartDir.dy*tmpStraightLen;var tmpApproachX=pEnd.x+tmpEndDir.dx*tmpStraightLen;var tmpApproachY=pEnd.y+tmpEndDir.dy*tmpStraightLen;var tmpDX=Math.abs(tmpApproachX-tmpDepartX);var tmpDY=Math.abs(tmpApproachY-tmpDepartY);var tmpDist=Math.sqrt(tmpDX*tmpDX+tmpDY*tmpDY);var tmpBaseOffset=Math.max(Math.min(tmpDist*0.4,180),30);var tmpSameAxis=tmpStartDir.dx!==0&&tmpEndDir.dx!==0||tmpStartDir.dy!==0&&tmpEndDir.dy!==0;var tmpFacingEachOther=false;if(tmpSameAxis){if(tmpStartDir.dx===1&&tmpEndDir.dx===-1&&pEnd.x>=pStart.x){tmpFacingEachOther=true;}else if(tmpStartDir.dx===-1&&tmpEndDir.dx===1&&pEnd.x<=pStart.x){tmpFacingEachOther=true;}else if(tmpStartDir.dy===1&&tmpEndDir.dy===-1&&pEnd.y>=pStart.y){tmpFacingEachOther=true;}else if(tmpStartDir.dy===-1&&tmpEndDir.dy===1&&pEnd.y<=pStart.y){tmpFacingEachOther=true;}}var tmpCurveOffset;if(tmpFacingEachOther){var tmpInlineDist=tmpStartDir.dx!==0?tmpDX:tmpDY;tmpCurveOffset=Math.max(tmpInlineDist*0.35,30);}else if(tmpSameAxis){tmpCurveOffset=Math.max(tmpBaseOffset,60);}else{tmpCurveOffset=Math.max(tmpBaseOffset*0.8,40);}var tmpCP1X=tmpDepartX+tmpStartDir.dx*tmpCurveOffset;var tmpCP1Y=tmpDepartY+tmpStartDir.dy*tmpCurveOffset;var tmpCP2X=tmpApproachX+tmpEndDir.dx*tmpCurveOffset;var tmpCP2Y=tmpApproachY+tmpEndDir.dy*tmpCurveOffset;return{departX:tmpDepartX,departY:tmpDepartY,approachX:tmpApproachX,approachY:tmpApproachY,cp1X:tmpCP1X,cp1Y:tmpCP1Y,cp2X:tmpCP2X,cp2Y:tmpCP2Y,startDir:tmpStartDir,endDir:tmpEndDir};}// ---- Distance Utilities ----
1884
+ /**
1885
+ * Distance from point (pPX, pPY) to line segment (pAX, pAY)-(pBX, pBY).
1886
+ * Pure math utility, no state.
1887
+ *
1888
+ * @param {number} pPX
1889
+ * @param {number} pPY
1890
+ * @param {number} pAX
1891
+ * @param {number} pAY
1892
+ * @param {number} pBX
1893
+ * @param {number} pBY
1894
+ * @returns {number}
1895
+ */},{key:"distanceToSegment",value:function distanceToSegment(pPX,pPY,pAX,pAY,pBX,pBY){var tmpDX=pBX-pAX;var tmpDY=pBY-pAY;var tmpLenSq=tmpDX*tmpDX+tmpDY*tmpDY;if(tmpLenSq<0.001){// Degenerate segment
1896
+ var tmpDPX=pPX-pAX;var tmpDPY=pPY-pAY;return Math.sqrt(tmpDPX*tmpDPX+tmpDPY*tmpDPY);}// Project point onto segment, clamped to [0, 1]
1897
+ var tmpT=((pPX-pAX)*tmpDX+(pPY-pAY)*tmpDY)/tmpLenSq;if(tmpT<0)tmpT=0;if(tmpT>1)tmpT=1;var tmpClosestX=pAX+tmpT*tmpDX;var tmpClosestY=pAY+tmpT*tmpDY;var tmpDistX=pPX-tmpClosestX;var tmpDistY=pPY-tmpClosestY;return Math.sqrt(tmpDistX*tmpDistX+tmpDistY*tmpDistY);}// ---- Auto Midpoint Calculation ----
1898
+ /**
1899
+ * Get the auto-calculated midpoint of the default bezier curve between
1900
+ * two port anchors, using the full directional geometry (facing detection,
1901
+ * adaptive curve offsets). Evaluates the cubic bezier at t=0.5.
1902
+ *
1903
+ * Used by ConnectionRenderer for connection midpoints.
1904
+ *
1905
+ * @param {{x: number, y: number, side: string}} pStart
1906
+ * @param {{x: number, y: number, side: string}} pEnd
1907
+ * @returns {{x: number, y: number}}
1908
+ */},{key:"getAutoMidpoint",value:function getAutoMidpoint(pStart,pEnd){var tmpGeo=this.computeDirectionalGeometry(pStart,pEnd);return this.evaluateCubicBezier({x:tmpGeo.departX,y:tmpGeo.departY},{x:tmpGeo.cp1X,y:tmpGeo.cp1Y},{x:tmpGeo.cp2X,y:tmpGeo.cp2Y},{x:tmpGeo.approachX,y:tmpGeo.approachY},0.5);}/**
1909
+ * Get the auto-calculated midpoint using simple span-based control points.
1910
+ * Uses computeDepartApproach for basic geometry, then span * 0.4 for
1911
+ * control point distance. Evaluates the cubic bezier at t=0.5.
1912
+ *
1913
+ * Used by TetherService for tether midpoints.
1914
+ *
1915
+ * @param {{x: number, y: number, side: string}} pFrom
1916
+ * @param {{x: number, y: number, side: string}} pTo
1917
+ * @param {number} pDepartDist - Departure/approach distance
1918
+ * @returns {{x: number, y: number}}
1919
+ */},{key:"getAutoMidpointSimple",value:function getAutoMidpointSimple(pFrom,pTo,pDepartDist){var tmpDA=this.computeDepartApproach(pFrom,pTo,pDepartDist);var tmpSpanX=Math.abs(tmpDA.approachX-tmpDA.departX);var tmpSpanY=Math.abs(tmpDA.approachY-tmpDA.departY);var tmpSpan=Math.max(tmpSpanX,tmpSpanY,40);var tmpCPDist=tmpSpan*0.4;var tmpP0={x:tmpDA.departX,y:tmpDA.departY};var tmpP1={x:tmpDA.departX+tmpDA.fromDir.dx*tmpCPDist,y:tmpDA.departY+tmpDA.fromDir.dy*tmpCPDist};var tmpP2={x:tmpDA.approachX+tmpDA.toDir.dx*tmpCPDist,y:tmpDA.approachY+tmpDA.toDir.dy*tmpCPDist};var tmpP3={x:tmpDA.approachX,y:tmpDA.approachY};return this.evaluateCubicBezier(tmpP0,tmpP1,tmpP2,tmpP3,0.5);}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowPathGenerator;},{"fable-serviceproviderbase":4}],34:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1920
+ * PictService-Flow-PortRenderer
1921
+ *
1922
+ * Renders port circles, labels, and badges for flow diagram nodes.
1923
+ *
1924
+ * Extracted from PictView-Flow-Node.js to isolate port rendering logic
1925
+ * from node body rendering and layout.
1926
+ *
1927
+ * Dependencies (all accessed via this._FlowView):
1928
+ * - _GeometryProvider — for getEdgeFromSide, getPortLocalPosition
1929
+ * - _ConnectorShapesProvider — for createPortElement
1930
+ * - _SVGHelperProvider — for createSVGElement
1931
+ */var PictServiceFlowPortRenderer=/*#__PURE__*/function(_libFableServiceProvi16){function PictServiceFlowPortRenderer(pFable,pOptions,pServiceHash){var _this45;_classCallCheck(this,PictServiceFlowPortRenderer);_this45=_callSuper(this,PictServiceFlowPortRenderer,[pFable,pOptions,pServiceHash]);_this45.serviceType='PictServiceFlowPortRenderer';_this45._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this45;}/**
1932
+ * Render ports for a node.
1933
+ * @param {Object} pNodeData
1934
+ * @param {SVGGElement} pGroup - The node's SVG group
1935
+ * @param {number} pWidth
1936
+ * @param {number} pHeight
1937
+ * @param {Object} [pNodeTypeConfig] - Node type configuration (for label display options)
1938
+ * @param {number} pNodeTitleBarHeight - Title bar height (for port position offset)
1939
+ */_inherits(PictServiceFlowPortRenderer,_libFableServiceProvi16);return _createClass(PictServiceFlowPortRenderer,[{key:"renderPorts",value:function renderPorts(pNodeData,pGroup,pWidth,pHeight,pNodeTypeConfig,pNodeTitleBarHeight){if(!this._FlowView)return;if(!pNodeData.Ports||!Array.isArray(pNodeData.Ports))return;var tmpPortLabelsVertical=pNodeTypeConfig&&pNodeTypeConfig.PortLabelsVertical;var tmpPortLabelPadding=pNodeTypeConfig&&pNodeTypeConfig.PortLabelPadding;var tmpPortLabelsOutside=pNodeTypeConfig&&pNodeTypeConfig.PortLabelsOutside;var tmpGeometryProvider=this._FlowView._GeometryProvider;// Group ports by their Side value (supports all 12 positions)
1940
+ var tmpPortsBySide={};for(var i=0;i<pNodeData.Ports.length;i++){var tmpPort=pNodeData.Ports[i];var tmpSide=tmpPort.Side||(tmpPort.Direction==='input'?'left':'right');if(!tmpPortsBySide[tmpSide]){tmpPortsBySide[tmpSide]=[];}tmpPortsBySide[tmpSide].push(tmpPort);}// Build port counts map for adaptive zone sizing
1941
+ var tmpPortCountsBySide={};for(var tmpKey in tmpPortsBySide){tmpPortCountsBySide[tmpKey]=tmpPortsBySide[tmpKey].length;}for(var _tmpSide in tmpPortsBySide){var tmpPorts=tmpPortsBySide[_tmpSide];// Determine the edge for label positioning
1942
+ var tmpEdge=tmpGeometryProvider?tmpGeometryProvider.getEdgeFromSide(_tmpSide):_tmpSide;for(var _i45=0;_i45<tmpPorts.length;_i45++){var _tmpPort=tmpPorts[_i45];var tmpPosition=this.getPortLocalPosition(_tmpSide,_i45,tmpPorts.length,pWidth,pHeight,pNodeTitleBarHeight,tmpPortCountsBySide);// Port label badge — flush against the node edge with no
1943
+ // border on the edge side; rendered before the port circle
1944
+ // so the circle visually sits on top of the badge
1945
+ var tmpLabelElement=null;if(_tmpPort.Label){var tmpPortTypeColorMap={'event-in':'#3498db','event-out':'#2ecc71','setting':'#e67e22','value':'#f1c40f','error':'#e74c3c'};var tmpBorderColor=_tmpPort.PortType?tmpPortTypeColorMap[_tmpPort.PortType]||'#95a5a6':'#95a5a6';var tmpBadgeHeight=12;var tmpBadgePadH=5;var tmpBadgeBorderW=2;var tmpEdgePad=1;var tmpPortRadius=5;var tmpTextLen=_tmpPort.Label.length*5;var tmpBadgeX=void 0,tmpBadgeY=void 0,tmpBadgeWidth=void 0;var tmpTextX=void 0,tmpTextAnchor=void 0;var tmpStripeX=void 0,tmpStripeY=void 0,tmpStripeW=void 0,tmpStripeH=void 0;var tmpBorderPath=void 0;if(tmpEdge==='left'){tmpBadgeWidth=tmpPortRadius+tmpBadgePadH+tmpTextLen+tmpBadgePadH+tmpBadgeBorderW;tmpBadgeX=tmpEdgePad;tmpBadgeY=tmpPosition.y-tmpBadgeHeight/2;tmpTextX=tmpBadgeX+tmpPortRadius+tmpBadgePadH;tmpTextAnchor='start';tmpStripeX=tmpBadgeX+tmpBadgeWidth-tmpBadgeBorderW;tmpStripeY=tmpBadgeY;tmpStripeW=tmpBadgeBorderW;tmpStripeH=tmpBadgeHeight;tmpBorderPath='M '+tmpBadgeX+' '+tmpBadgeY+' L '+(tmpBadgeX+tmpBadgeWidth)+' '+tmpBadgeY+' L '+(tmpBadgeX+tmpBadgeWidth)+' '+(tmpBadgeY+tmpBadgeHeight)+' L '+tmpBadgeX+' '+(tmpBadgeY+tmpBadgeHeight);}else if(tmpEdge==='right'){tmpBadgeWidth=tmpBadgeBorderW+tmpBadgePadH+tmpTextLen+tmpBadgePadH+tmpPortRadius;tmpBadgeX=pWidth-tmpBadgeWidth-tmpEdgePad;tmpBadgeY=tmpPosition.y-tmpBadgeHeight/2;tmpTextX=tmpBadgeX+tmpBadgeBorderW+tmpBadgePadH;tmpTextAnchor='start';tmpStripeX=tmpBadgeX;tmpStripeY=tmpBadgeY;tmpStripeW=tmpBadgeBorderW;tmpStripeH=tmpBadgeHeight;tmpBorderPath='M '+(tmpBadgeX+tmpBadgeWidth)+' '+tmpBadgeY+' L '+tmpBadgeX+' '+tmpBadgeY+' L '+tmpBadgeX+' '+(tmpBadgeY+tmpBadgeHeight)+' L '+(tmpBadgeX+tmpBadgeWidth)+' '+(tmpBadgeY+tmpBadgeHeight);}else if(tmpEdge==='top'){tmpBadgeWidth=tmpTextLen+tmpBadgePadH*2;tmpBadgeX=tmpPosition.x-tmpBadgeWidth/2;tmpBadgeY=tmpEdgePad;tmpTextX=tmpPosition.x;tmpTextAnchor='middle';tmpStripeX=tmpBadgeX;tmpStripeY=tmpBadgeY+tmpBadgeHeight-tmpBadgeBorderW;tmpStripeW=tmpBadgeWidth;tmpStripeH=tmpBadgeBorderW;tmpBorderPath='M '+tmpBadgeX+' '+tmpBadgeY+' L '+tmpBadgeX+' '+(tmpBadgeY+tmpBadgeHeight)+' L '+(tmpBadgeX+tmpBadgeWidth)+' '+(tmpBadgeY+tmpBadgeHeight)+' L '+(tmpBadgeX+tmpBadgeWidth)+' '+tmpBadgeY;}else{tmpBadgeWidth=tmpTextLen+tmpBadgePadH*2;tmpBadgeX=tmpPosition.x-tmpBadgeWidth/2;tmpBadgeY=pHeight-tmpBadgeHeight-tmpEdgePad;tmpTextX=tmpPosition.x;tmpTextAnchor='middle';tmpStripeX=tmpBadgeX;tmpStripeY=tmpBadgeY;tmpStripeW=tmpBadgeWidth;tmpStripeH=tmpBadgeBorderW;tmpBorderPath='M '+tmpBadgeX+' '+(tmpBadgeY+tmpBadgeHeight)+' L '+tmpBadgeX+' '+tmpBadgeY+' L '+(tmpBadgeX+tmpBadgeWidth)+' '+tmpBadgeY+' L '+(tmpBadgeX+tmpBadgeWidth)+' '+(tmpBadgeY+tmpBadgeHeight);}// Background rect (cream, no stroke — border drawn separately)
1946
+ var tmpBgRect=this._FlowView._SVGHelperProvider.createSVGElement('rect');tmpBgRect.setAttribute('class','pict-flow-port-label-bg');tmpBgRect.setAttribute('x',String(tmpBadgeX));tmpBgRect.setAttribute('y',String(tmpBadgeY));tmpBgRect.setAttribute('width',String(tmpBadgeWidth));tmpBgRect.setAttribute('height',String(tmpBadgeHeight));tmpBgRect.setAttribute('fill','var(--pf-port-label-bg, rgba(255, 253, 240, 0.5))');pGroup.appendChild(tmpBgRect);// 3-sided border path (open on the edge-facing side)
1947
+ var tmpBorderPathEl=this._FlowView._SVGHelperProvider.createSVGElement('path');tmpBorderPathEl.setAttribute('class','pict-flow-port-label-bg');tmpBorderPathEl.setAttribute('d',tmpBorderPath);tmpBorderPathEl.setAttribute('fill','none');tmpBorderPathEl.setAttribute('stroke',tmpBorderColor);tmpBorderPathEl.setAttribute('stroke-width','0.75');pGroup.appendChild(tmpBorderPathEl);// Colored stripe on the inner side
1948
+ var tmpStripe=this._FlowView._SVGHelperProvider.createSVGElement('rect');tmpStripe.setAttribute('class','pict-flow-port-label-bg');tmpStripe.setAttribute('x',String(tmpStripeX));tmpStripe.setAttribute('y',String(tmpStripeY));tmpStripe.setAttribute('width',String(tmpStripeW));tmpStripe.setAttribute('height',String(tmpStripeH));tmpStripe.setAttribute('fill',tmpBorderColor);pGroup.appendChild(tmpStripe);// Text label — appended after circle for z-order
1949
+ tmpLabelElement=this._FlowView._SVGHelperProvider.createSVGElement('text');tmpLabelElement.setAttribute('class','pict-flow-port-label');tmpLabelElement.setAttribute('fill','var(--pf-port-label-text, #2c3e50)');tmpLabelElement.textContent=_tmpPort.Label;tmpLabelElement.setAttribute('x',String(tmpTextX));tmpLabelElement.setAttribute('y',String(tmpBadgeY+tmpBadgeHeight/2));tmpLabelElement.setAttribute('text-anchor',tmpTextAnchor);tmpLabelElement.setAttribute('dominant-baseline','central');}// Port circle (rendered on top of badge background)
1950
+ var tmpShapeProvider=this._FlowView._ConnectorShapesProvider;var tmpCircle=void 0;if(tmpShapeProvider){tmpCircle=tmpShapeProvider.createPortElement(_tmpPort,tmpPosition,pNodeData.Hash);}else{tmpCircle=this._FlowView._SVGHelperProvider.createSVGElement('circle');var tmpPortClass="pict-flow-port ".concat(_tmpPort.Direction);if(_tmpPort.PortType){tmpPortClass+=" port-type-".concat(_tmpPort.PortType);}tmpCircle.setAttribute('class',tmpPortClass);tmpCircle.setAttribute('cx',String(tmpPosition.x));tmpCircle.setAttribute('cy',String(tmpPosition.y));tmpCircle.setAttribute('r','5');tmpCircle.setAttribute('data-port-hash',_tmpPort.Hash);tmpCircle.setAttribute('data-node-hash',pNodeData.Hash);tmpCircle.setAttribute('data-port-direction',_tmpPort.Direction);if(_tmpPort.PortType){tmpCircle.setAttribute('data-port-type',_tmpPort.PortType);}tmpCircle.setAttribute('data-element-type','port');}pGroup.appendChild(tmpCircle);// Port label text (on top of everything)
1951
+ if(tmpLabelElement){pGroup.appendChild(tmpLabelElement);}}}}/**
1952
+ * Calculate port position relative to node origin.
1953
+ *
1954
+ * Delegates to the geometry provider's getPortLocalPosition method.
1955
+ *
1956
+ * @param {string} pSide - 'left', 'right', 'top', 'bottom' (or compound sides)
1957
+ * @param {number} pIndex - Index of this port on its side
1958
+ * @param {number} pTotal - Total ports on this side
1959
+ * @param {number} pWidth - Node width
1960
+ * @param {number} pHeight - Node height
1961
+ * @param {number} pNodeTitleBarHeight - Title bar height
1962
+ * @param {Object} [pPortCountsBySide] - Optional map of Side → count for adaptive zones
1963
+ * @returns {{x: number, y: number}}
1964
+ */},{key:"getPortLocalPosition",value:function getPortLocalPosition(pSide,pIndex,pTotal,pWidth,pHeight,pNodeTitleBarHeight,pPortCountsBySide){return this._FlowView._GeometryProvider.getPortLocalPosition(pSide,pIndex,pTotal,pWidth,pHeight,pNodeTitleBarHeight,pPortCountsBySide);}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowPortRenderer;},{"fable-serviceproviderbase":4}],35:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
1965
+ * PictService-Flow-RenderManager
1966
+ *
1967
+ * Orchestrates rendering of the flow diagram: nodes, connections,
1968
+ * tethers, panels, SVG marker definitions, and node position updates.
1969
+ *
1970
+ * Extracted from PictView-Flow.js to isolate rendering orchestration
1971
+ * from data management and interaction handling.
1972
+ */var PictServiceFlowRenderManager=/*#__PURE__*/function(_libFableServiceProvi17){function PictServiceFlowRenderManager(pFable,pOptions,pServiceHash){var _this46;_classCallCheck(this,PictServiceFlowRenderManager);_this46=_callSuper(this,PictServiceFlowRenderManager,[pFable,pOptions,pServiceHash]);_this46.serviceType='PictServiceFlowRenderManager';_this46._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this46;}/**
1973
+ * Render the complete flow diagram
1974
+ */_inherits(PictServiceFlowRenderManager,_libFableServiceProvi17);return _createClass(PictServiceFlowRenderManager,[{key:"renderFlow",value:function renderFlow(){if(!this._FlowView)return;if(!this._FlowView._NodesLayer||!this._FlowView._ConnectionsLayer)return;// Clear existing SVG content
1975
+ while(this._FlowView._NodesLayer.firstChild){this._FlowView._NodesLayer.removeChild(this._FlowView._NodesLayer.firstChild);}while(this._FlowView._ConnectionsLayer.firstChild){this._FlowView._ConnectionsLayer.removeChild(this._FlowView._ConnectionsLayer.firstChild);}// Render connections first (behind nodes)
1976
+ for(var i=0;i<this._FlowView._FlowData.Connections.length;i++){var tmpConnection=this._FlowView._FlowData.Connections[i];var tmpIsSelected=this._FlowView._FlowData.ViewState.SelectedConnectionHash===tmpConnection.Hash;this._FlowView._ConnectionRenderer.renderConnection(tmpConnection,this._FlowView._ConnectionsLayer,tmpIsSelected);}// Render nodes
1977
+ for(var _i46=0;_i46<this._FlowView._FlowData.Nodes.length;_i46++){var tmpNode=this._FlowView._FlowData.Nodes[_i46];var _tmpIsSelected=this._FlowView._FlowData.ViewState.SelectedNodeHash===tmpNode.Hash;var tmpNodeTypeConfig=this._FlowView._NodeTypeProvider.getNodeType(tmpNode.Type);// Enrich saved port data with metadata from the node type's DefaultPorts.
1978
+ // Saved flow data may not include PortType or may have stale Side values,
1979
+ // so we match each port to its DefaultPort counterpart by Label and Direction,
1980
+ // then copy over PortType and Side from the authoritative node type definition.
1981
+ if(tmpNodeTypeConfig&&tmpNodeTypeConfig.DefaultPorts&&tmpNode.Ports){for(var p=0;p<tmpNode.Ports.length;p++){var tmpPort=tmpNode.Ports[p];for(var d=0;d<tmpNodeTypeConfig.DefaultPorts.length;d++){var tmpDefault=tmpNodeTypeConfig.DefaultPorts[d];if(tmpDefault.Label===tmpPort.Label&&tmpDefault.Direction===tmpPort.Direction){if(tmpDefault.PortType){tmpPort.PortType=tmpDefault.PortType;}if(tmpDefault.Side){tmpPort.Side=tmpDefault.Side;}break;}}}}this._FlowView._NodeView.renderNode(tmpNode,this._FlowView._NodesLayer,_tmpIsSelected,tmpNodeTypeConfig);}// Render properties panels and tethers
1982
+ if(this._FlowView._PropertiesPanelView&&this._FlowView._PanelsLayer&&this._FlowView._TethersLayer){this._FlowView._PropertiesPanelView.renderPanels(this._FlowView._FlowData.OpenPanels,this._FlowView._PanelsLayer,this._FlowView._TethersLayer,this._FlowView._FlowData.ViewState.SelectedTetherHash);}// Update viewport transform
1983
+ this._FlowView.updateViewportTransform();}/**
1984
+ * Re-render a single connection (remove and re-add) for smooth drag performance.
1985
+ * @param {string} pConnectionHash
1986
+ */},{key:"renderSingleConnection",value:function renderSingleConnection(pConnectionHash){if(!this._FlowView||!this._FlowView._ConnectionsLayer)return;// Remove existing elements for this connection
1987
+ var tmpExisting=this._FlowView._ConnectionsLayer.querySelectorAll("[data-connection-hash=\"".concat(pConnectionHash,"\"]"));for(var i=0;i<tmpExisting.length;i++){tmpExisting[i].remove();}var tmpConnection=this._FlowView.getConnection(pConnectionHash);if(!tmpConnection)return;var tmpIsSelected=this._FlowView._FlowData.ViewState.SelectedConnectionHash===pConnectionHash;this._FlowView._ConnectionRenderer.renderConnection(tmpConnection,this._FlowView._ConnectionsLayer,tmpIsSelected);}/**
1988
+ * Re-render a single tether (remove and re-add) for smooth drag performance.
1989
+ * @param {string} pPanelHash
1990
+ */},{key:"renderSingleTether",value:function renderSingleTether(pPanelHash){if(!this._FlowView||!this._FlowView._TethersLayer||!this._FlowView._TetherService)return;// Remove existing tether elements for this panel
1991
+ var tmpExisting=this._FlowView._TethersLayer.querySelectorAll("[data-panel-hash=\"".concat(pPanelHash,"\"]"));for(var i=0;i<tmpExisting.length;i++){tmpExisting[i].remove();}var tmpPanel=this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===pPanelHash;});if(!tmpPanel)return;var tmpNodeData=this._FlowView.getNode(tmpPanel.NodeHash);if(!tmpNodeData)return;var tmpIsSelected=this._FlowView._FlowData.ViewState.SelectedTetherHash===pPanelHash;this._FlowView._TetherService.renderTether(tmpPanel,tmpNodeData,this._FlowView._TethersLayer,tmpIsSelected,this._FlowView.options.ViewIdentifier);}/**
1992
+ * Update a single node's position in the SVG without full re-render (for drag performance)
1993
+ * @param {string} pNodeHash
1994
+ * @param {number} pX
1995
+ * @param {number} pY
1996
+ */},{key:"updateNodePosition",value:function updateNodePosition(pNodeHash,pX,pY){if(!this._FlowView)return;var tmpNode=this._FlowView.getNode(pNodeHash);if(!tmpNode)return;if(this._FlowView.options.EnableGridSnap){pX=this._FlowView._LayoutService.snapToGrid(pX,this._FlowView.options.GridSnapSize);pY=this._FlowView._LayoutService.snapToGrid(pY,this._FlowView.options.GridSnapSize);}tmpNode.X=pX;tmpNode.Y=pY;// Reset customized handle positions for connections/tethers involving this node
1997
+ this._FlowView._resetHandlesForNode(pNodeHash);// Update the node's SVG group transform for smooth dragging
1998
+ var tmpNodeGroup=this._FlowView._NodesLayer.querySelector("[data-node-hash=\"".concat(pNodeHash,"\"]"));if(tmpNodeGroup){tmpNodeGroup.setAttribute('transform',"translate(".concat(pX,", ").concat(pY,")"));}// Re-render connections that involve this node
1999
+ this.renderConnectionsForNode(pNodeHash);// Update tethers for any panels attached to this node
2000
+ this.renderTethersForNode(pNodeHash);}/**
2001
+ * Re-render only connections that involve a specific node (for drag performance)
2002
+ * @param {string} pNodeHash
2003
+ */},{key:"renderConnectionsForNode",value:function renderConnectionsForNode(pNodeHash){if(!this._FlowView||!this._FlowView._ConnectionsLayer)return;var tmpAffectedConnections=this._FlowView._FlowData.Connections.filter(function(pConn){return pConn.SourceNodeHash===pNodeHash||pConn.TargetNodeHash===pNodeHash;});for(var i=0;i<tmpAffectedConnections.length;i++){var tmpConn=tmpAffectedConnections[i];var tmpIsSelected=this._FlowView._FlowData.ViewState.SelectedConnectionHash===tmpConn.Hash;// Remove existing connection SVG elements
2004
+ var tmpExisting=this._FlowView._ConnectionsLayer.querySelectorAll("[data-connection-hash=\"".concat(tmpConn.Hash,"\"]"));for(var j=0;j<tmpExisting.length;j++){tmpExisting[j].remove();}// Re-render this connection
2005
+ this._FlowView._ConnectionRenderer.renderConnection(tmpConn,this._FlowView._ConnectionsLayer,tmpIsSelected);}}/**
2006
+ * Re-render tethers for panels attached to a specific node (for drag performance).
2007
+ * @param {string} pNodeHash
2008
+ */},{key:"renderTethersForNode",value:function renderTethersForNode(pNodeHash){if(!this._FlowView||!this._FlowView._TethersLayer||!this._FlowView._TetherService)return;var tmpAffectedPanels=this._FlowView._FlowData.OpenPanels.filter(function(pPanel){return pPanel.NodeHash===pNodeHash;});if(tmpAffectedPanels.length===0)return;// Remove existing tethers for these panels and re-render via TetherService
2009
+ for(var i=0;i<tmpAffectedPanels.length;i++){var tmpExisting=this._FlowView._TethersLayer.querySelectorAll("[data-panel-hash=\"".concat(tmpAffectedPanels[i].Hash,"\"]"));for(var j=0;j<tmpExisting.length;j++){tmpExisting[j].remove();}var tmpNodeData=this._FlowView.getNode(tmpAffectedPanels[i].NodeHash);if(!tmpNodeData)continue;var tmpIsSelected=this._FlowView._FlowData.ViewState.SelectedTetherHash===tmpAffectedPanels[i].Hash;this._FlowView._TetherService.renderTether(tmpAffectedPanels[i],tmpNodeData,this._FlowView._TethersLayer,tmpIsSelected,this._FlowView.options.ViewIdentifier);}}/**
2010
+ * Re-inject SVG marker definitions (arrowheads).
2011
+ * Called after a theme switch to update arrowhead colors.
2012
+ */},{key:"reinjectMarkerDefs",value:function reinjectMarkerDefs(){if(!this._FlowView||!this._FlowView._ConnectorShapesProvider||!this._FlowView._SVGElement)return;var tmpViewIdentifier=this._FlowView.options.ViewIdentifier;var tmpDefs=this._FlowView._SVGElement.querySelector('defs');if(!tmpDefs)return;// Remove existing marker elements
2013
+ var tmpExistingMarkers=tmpDefs.querySelectorAll('marker');for(var i=0;i<tmpExistingMarkers.length;i++){tmpExistingMarkers[i].remove();}// Re-generate and inject
2014
+ var tmpMarkerMarkup=this._FlowView._ConnectorShapesProvider.generateMarkerDefs(tmpViewIdentifier);var tmpTempSVG=document.createElementNS('http://www.w3.org/2000/svg','svg');tmpTempSVG.innerHTML=tmpMarkerMarkup;while(tmpTempSVG.firstChild){tmpDefs.appendChild(tmpTempSVG.firstChild);}}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowRenderManager;},{"fable-serviceproviderbase":4}],36:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
2015
+ * PictService-Flow-SelectionManager
2016
+ *
2017
+ * Manages selection state for nodes, connections, and tethers in the flow diagram.
2018
+ * Handles selecting, deselecting, and deleting selected elements.
2019
+ */var PictServiceFlowSelectionManager=/*#__PURE__*/function(_libFableServiceProvi18){function PictServiceFlowSelectionManager(pFable,pOptions,pServiceHash){var _this47;_classCallCheck(this,PictServiceFlowSelectionManager);_this47=_callSuper(this,PictServiceFlowSelectionManager,[pFable,pOptions,pServiceHash]);_this47.serviceType='PictServiceFlowSelectionManager';_this47._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this47;}/**
2020
+ * Select a node
2021
+ * @param {string|null} pNodeHash - Hash of the node to select, or null to deselect
2022
+ */_inherits(PictServiceFlowSelectionManager,_libFableServiceProvi18);return _createClass(PictServiceFlowSelectionManager,[{key:"selectNode",value:function selectNode(pNodeHash){var tmpPreviousSelection=this._FlowView._FlowData.ViewState.SelectedNodeHash;this._FlowView._FlowData.ViewState.SelectedNodeHash=pNodeHash;this._FlowView._FlowData.ViewState.SelectedConnectionHash=null;this._FlowView._FlowData.ViewState.SelectedTetherHash=null;this._FlowView.renderFlow();if(this._FlowView._EventHandlerProvider&&pNodeHash!==tmpPreviousSelection){var tmpNode=pNodeHash?this._FlowView._FlowData.Nodes.find(function(pNode){return pNode.Hash===pNodeHash;}):null;this._FlowView._EventHandlerProvider.fireEvent('onNodeSelected',tmpNode);}}/**
2023
+ * Select a connection
2024
+ * @param {string|null} pConnectionHash - Hash of the connection to select, or null to deselect
2025
+ */},{key:"selectConnection",value:function selectConnection(pConnectionHash){var tmpPreviousSelection=this._FlowView._FlowData.ViewState.SelectedConnectionHash;this._FlowView._FlowData.ViewState.SelectedConnectionHash=pConnectionHash;this._FlowView._FlowData.ViewState.SelectedNodeHash=null;this._FlowView._FlowData.ViewState.SelectedTetherHash=null;this._FlowView.renderFlow();if(this._FlowView._EventHandlerProvider&&pConnectionHash!==tmpPreviousSelection){var tmpConnection=pConnectionHash?this._FlowView._FlowData.Connections.find(function(pConn){return pConn.Hash===pConnectionHash;}):null;this._FlowView._EventHandlerProvider.fireEvent('onConnectionSelected',tmpConnection);}}/**
2026
+ * Select a tether by its panel hash.
2027
+ * @param {string|null} pPanelHash - Hash of the panel whose tether to select, or null to deselect
2028
+ */},{key:"selectTether",value:function selectTether(pPanelHash){var tmpPreviousSelection=this._FlowView._FlowData.ViewState.SelectedTetherHash;this._FlowView._FlowData.ViewState.SelectedTetherHash=pPanelHash;this._FlowView._FlowData.ViewState.SelectedNodeHash=null;this._FlowView._FlowData.ViewState.SelectedConnectionHash=null;this._FlowView.renderFlow();if(this._FlowView._EventHandlerProvider&&pPanelHash!==tmpPreviousSelection){var tmpPanel=pPanelHash?this._FlowView._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===pPanelHash;}):null;this._FlowView._EventHandlerProvider.fireEvent('onTetherSelected',tmpPanel);}}/**
2029
+ * Deselect all nodes and connections
2030
+ */},{key:"deselectAll",value:function deselectAll(){this._FlowView._FlowData.ViewState.SelectedNodeHash=null;this._FlowView._FlowData.ViewState.SelectedConnectionHash=null;this._FlowView._FlowData.ViewState.SelectedTetherHash=null;this._FlowView.renderFlow();}/**
2031
+ * Delete the currently selected node or connection
2032
+ * @returns {boolean}
2033
+ */},{key:"deleteSelected",value:function deleteSelected(){if(this._FlowView._FlowData.ViewState.SelectedNodeHash){return this._FlowView.removeNode(this._FlowView._FlowData.ViewState.SelectedNodeHash);}if(this._FlowView._FlowData.ViewState.SelectedConnectionHash){return this._FlowView.removeConnection(this._FlowView._FlowData.ViewState.SelectedConnectionHash);}return false;}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowSelectionManager;},{"fable-serviceproviderbase":4}],37:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
2034
+ * PictService-Flow-Tether
2035
+ *
2036
+ * Centralizes all tether geometry, path generation, handle state management,
2037
+ * and SVG rendering for the lines that connect properties panels to their nodes.
2038
+ *
2039
+ * Delegates to shared providers for:
2040
+ * - SVG element creation (_FlowView._SVGHelperProvider)
2041
+ * - Geometry calculations (_FlowView._GeometryProvider)
2042
+ * - Path string building (_FlowView._PathGenerator)
2043
+ *
2044
+ * Responsibilities:
2045
+ * - Smart 4-quadrant anchor detection (which edge of the node/panel to connect)
2046
+ * - Bezier and orthogonal path generation
2047
+ * - Auto-midpoint and auto-corner calculations
2048
+ * - Handle position updates during drag
2049
+ * - Handle reset when nodes or panels move
2050
+ * - Line mode toggling (bezier <-> orthogonal)
2051
+ * - SVG element creation for tether lines, hit areas, and drag handles
2052
+ */var PictServiceFlowTether=/*#__PURE__*/function(_libFableServiceProvi19){function PictServiceFlowTether(pFable,pOptions,pServiceHash){var _this48;_classCallCheck(this,PictServiceFlowTether);_this48=_callSuper(this,PictServiceFlowTether,[pFable,pOptions,pServiceHash]);_this48.serviceType='PictServiceFlowTether';_this48._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;return _this48;}// ---- Anchor Calculation ----
2053
+ /**
2054
+ * Determine which node edge and panel edge to connect based on 4-quadrant detection.
2055
+ * Uses the relative position of the panel center to the node center.
2056
+ *
2057
+ * @param {Object} pPanelData - Panel data with X, Y, Width, Height
2058
+ * @param {Object} pNodeData - Node data with X, Y, Width, Height
2059
+ * @returns {{nodeAnchor: {x,y,side}, panelAnchor: {x,y,side}}}
2060
+ */_inherits(PictServiceFlowTether,_libFableServiceProvi19);return _createClass(PictServiceFlowTether,[{key:"getSmartAnchors",value:function getSmartAnchors(pPanelData,pNodeData){var tmpNodeCX=pNodeData.X+pNodeData.Width/2;var tmpNodeCY=pNodeData.Y+pNodeData.Height/2;var tmpPanelCX=pPanelData.X+pPanelData.Width/2;var tmpPanelCY=pPanelData.Y+pPanelData.Height/2;var tmpDX=tmpPanelCX-tmpNodeCX;var tmpDY=tmpPanelCY-tmpNodeCY;var tmpNodeSide,tmpPanelSide;if(Math.abs(tmpDX)>=Math.abs(tmpDY)){// Panel is primarily to the left or right
2061
+ if(tmpDX>=0){tmpNodeSide='right';tmpPanelSide='left';}else{tmpNodeSide='left';tmpPanelSide='right';}}else{// Panel is primarily above or below
2062
+ if(tmpDY>=0){tmpNodeSide='bottom';tmpPanelSide='top';}else{tmpNodeSide='top';tmpPanelSide='bottom';}}var tmpNodeAnchor=this._FlowView._GeometryProvider.getEdgeCenter(pNodeData,tmpNodeSide);var tmpPanelAnchor=this._FlowView._GeometryProvider.getEdgeCenter(pPanelData,tmpPanelSide);return{nodeAnchor:Object.assign(tmpNodeAnchor,{side:tmpNodeSide}),panelAnchor:Object.assign(tmpPanelAnchor,{side:tmpPanelSide})};}// ---- Path Generation ----
2063
+ /**
2064
+ * Generate a bezier path between two anchor points with directional departure/approach.
2065
+ * @param {Object} pFrom - {x, y, side}
2066
+ * @param {Object} pTo - {x, y, side}
2067
+ * @param {number|null} pHandleX - User-set handle X or null for auto
2068
+ * @param {number|null} pHandleY - User-set handle Y or null for auto
2069
+ * @returns {string} SVG path d attribute
2070
+ */},{key:"generateBezierPath",value:function generateBezierPath(pFrom,pTo,pHandleX,pHandleY){var tmpDepartDist=20;var tmpFromDir=this._FlowView._GeometryProvider.sideDirection(pFrom.side);var tmpToDir=this._FlowView._GeometryProvider.sideDirection(pTo.side);var tmpDepartX=pFrom.x+tmpFromDir.dx*tmpDepartDist;var tmpDepartY=pFrom.y+tmpFromDir.dy*tmpDepartDist;var tmpApproachX=pTo.x+tmpToDir.dx*tmpDepartDist;var tmpApproachY=pTo.y+tmpToDir.dy*tmpDepartDist;if(pHandleX==null||pHandleY==null){// Auto bezier: simple cubic from depart to approach
2071
+ var tmpSpanX=Math.abs(tmpApproachX-tmpDepartX);var tmpSpanY=Math.abs(tmpApproachY-tmpDepartY);var tmpSpan=Math.max(tmpSpanX,tmpSpanY,40);var tmpCPDist=tmpSpan*0.4;var tmpCP1X=tmpDepartX+tmpFromDir.dx*tmpCPDist;var tmpCP1Y=tmpDepartY+tmpFromDir.dy*tmpCPDist;var tmpCP2X=tmpApproachX+tmpToDir.dx*tmpCPDist;var tmpCP2Y=tmpApproachY+tmpToDir.dy*tmpCPDist;return this._FlowView._PathGenerator.buildBezierPathString({x:pFrom.x,y:pFrom.y},{x:tmpDepartX,y:tmpDepartY},{x:tmpCP1X,y:tmpCP1Y},{x:tmpCP2X,y:tmpCP2Y},{x:tmpApproachX,y:tmpApproachY},{x:pTo.x,y:pTo.y});}// User-set handle: split bezier into two segments through handle
2072
+ var tmpCP1aDist=30;var tmpCP1aX=tmpDepartX+tmpFromDir.dx*tmpCP1aDist;var tmpCP1aY=tmpDepartY+tmpFromDir.dy*tmpCP1aDist;var tmpCP2aDist=30;var tmpCP2aX=tmpApproachX+tmpToDir.dx*tmpCP2aDist;var tmpCP2aY=tmpApproachY+tmpToDir.dy*tmpCP2aDist;// Tangent at the handle — direction from first segment end to second segment start
2073
+ var tmpTangentX=tmpApproachX-tmpDepartX;var tmpTangentY=tmpApproachY-tmpDepartY;var tmpTangentLen=Math.sqrt(tmpTangentX*tmpTangentX+tmpTangentY*tmpTangentY)||1;tmpTangentX/=tmpTangentLen;tmpTangentY/=tmpTangentLen;var tmpTangentDist=25;var tmpCP1bX=pHandleX-tmpTangentX*tmpTangentDist;var tmpCP1bY=pHandleY-tmpTangentY*tmpTangentDist;var tmpCP2bX=pHandleX+tmpTangentX*tmpTangentDist;var tmpCP2bY=pHandleY+tmpTangentY*tmpTangentDist;return this._FlowView._PathGenerator.buildSplitBezierPathString({x:pFrom.x,y:pFrom.y},{x:tmpDepartX,y:tmpDepartY},{x:tmpCP1aX,y:tmpCP1aY},{x:tmpCP1bX,y:tmpCP1bY},{x:pHandleX,y:pHandleY},{x:tmpCP2bX,y:tmpCP2bY},{x:tmpCP2aX,y:tmpCP2aY},{x:tmpApproachX,y:tmpApproachY},{x:pTo.x,y:pTo.y});}/**
2074
+ * Generate an orthogonal (90-degree) path between two anchor points.
2075
+ * @param {Object} pFrom - {x, y, side}
2076
+ * @param {Object} pTo - {x, y, side}
2077
+ * @param {Object|null} pCorners - {corner1: {x,y}, corner2: {x,y}} or null for auto
2078
+ * @param {number} pMidOffset - Offset for the corridor midpoint
2079
+ * @returns {string} SVG path d attribute
2080
+ */},{key:"generateOrthogonalPath",value:function generateOrthogonalPath(pFrom,pTo,pCorners,pMidOffset){var tmpDepartDist=20;var tmpFromDir=this._FlowView._GeometryProvider.sideDirection(pFrom.side);var tmpToDir=this._FlowView._GeometryProvider.sideDirection(pTo.side);var tmpDepartX=pFrom.x+tmpFromDir.dx*tmpDepartDist;var tmpDepartY=pFrom.y+tmpFromDir.dy*tmpDepartDist;var tmpApproachX=pTo.x+tmpToDir.dx*tmpDepartDist;var tmpApproachY=pTo.y+tmpToDir.dy*tmpDepartDist;var tmpCorner1,tmpCorner2;if(pCorners&&pCorners.corner1&&pCorners.corner2){tmpCorner1=pCorners.corner1;tmpCorner2=pCorners.corner2;}else{// Auto-calculate corners based on direction
2081
+ var tmpAutoCorners=this._FlowView._PathGenerator.computeAutoOrthogonalCorners(tmpDepartX,tmpDepartY,tmpApproachX,tmpApproachY,tmpFromDir,tmpToDir,pMidOffset);tmpCorner1=tmpAutoCorners.corner1;tmpCorner2=tmpAutoCorners.corner2;}return this._FlowView._PathGenerator.buildOrthogonalPathString({x:pFrom.x,y:pFrom.y},{x:tmpDepartX,y:tmpDepartY},{x:tmpCorner1.x,y:tmpCorner1.y},{x:tmpCorner2.x,y:tmpCorner2.y},{x:tmpApproachX,y:tmpApproachY},{x:pTo.x,y:pTo.y});}// ---- Handle Position Computation ----
2082
+ /**
2083
+ * Get auto-calculated bezier midpoint for a tether at t=0.5 on the curve.
2084
+ * @param {Object} pFrom - {x, y, side}
2085
+ * @param {Object} pTo - {x, y, side}
2086
+ * @returns {{x: number, y: number}}
2087
+ */},{key:"getAutoMidpoint",value:function getAutoMidpoint(pFrom,pTo){return this._FlowView._PathGenerator.getAutoMidpointSimple(pFrom,pTo,20);}/**
2088
+ * Get full orthogonal geometry including corners and midpoint for handle rendering.
2089
+ * @param {Object} pFrom - {x, y, side}
2090
+ * @param {Object} pTo - {x, y, side}
2091
+ * @param {Object} pPanelData - Panel data with tether handle properties
2092
+ * @returns {{corner1: {x,y}, corner2: {x,y}, midpoint: {x,y}}}
2093
+ */},{key:"getOrthoGeometry",value:function getOrthoGeometry(pFrom,pTo,pPanelData){var tmpDepartDist=20;var tmpFromDir=this._FlowView._GeometryProvider.sideDirection(pFrom.side);var tmpToDir=this._FlowView._GeometryProvider.sideDirection(pTo.side);var tmpDepartX=pFrom.x+tmpFromDir.dx*tmpDepartDist;var tmpDepartY=pFrom.y+tmpFromDir.dy*tmpDepartDist;var tmpApproachX=pTo.x+tmpToDir.dx*tmpDepartDist;var tmpApproachY=pTo.y+tmpToDir.dy*tmpDepartDist;var tmpCorners;if(pPanelData.TetherHandleCustomized&&pPanelData.TetherOrthoCorner1X!=null){tmpCorners=this._FlowView._PathGenerator.computeAutoOrthogonalCorners(tmpDepartX,tmpDepartY,tmpApproachX,tmpApproachY,tmpFromDir,tmpToDir,pPanelData.TetherOrthoMidOffset||0);tmpCorners.corner1={x:pPanelData.TetherOrthoCorner1X,y:pPanelData.TetherOrthoCorner1Y};tmpCorners.corner2={x:pPanelData.TetherOrthoCorner2X,y:pPanelData.TetherOrthoCorner2Y};}else{tmpCorners=this._FlowView._PathGenerator.computeAutoOrthogonalCorners(tmpDepartX,tmpDepartY,tmpApproachX,tmpApproachY,tmpFromDir,tmpToDir,pPanelData.TetherOrthoMidOffset||0);}var tmpMidpoint={x:(tmpCorners.corner1.x+tmpCorners.corner2.x)/2,y:(tmpCorners.corner1.y+tmpCorners.corner2.y)/2};return{corner1:tmpCorners.corner1,corner2:tmpCorners.corner2,midpoint:tmpMidpoint};}// ---- Path Generation (high-level) ----
2094
+ /**
2095
+ * Generate the SVG path string for a tether based on its panel data and anchors.
2096
+ * @param {Object} pPanelData - Panel data with tether handle properties
2097
+ * @param {Object} pFrom - {x, y, side} panel anchor
2098
+ * @param {Object} pTo - {x, y, side} node anchor
2099
+ * @returns {string} SVG path d attribute
2100
+ */},{key:"generatePath",value:function generatePath(pPanelData,pFrom,pTo){var tmpLineMode=pPanelData.TetherLineMode||'bezier';if(tmpLineMode==='orthogonal'){var tmpCorners=null;if(pPanelData.TetherHandleCustomized&&pPanelData.TetherOrthoCorner1X!=null){tmpCorners={corner1:{x:pPanelData.TetherOrthoCorner1X,y:pPanelData.TetherOrthoCorner1Y},corner2:{x:pPanelData.TetherOrthoCorner2X,y:pPanelData.TetherOrthoCorner2Y}};}return this.generateOrthogonalPath(pFrom,pTo,tmpCorners,pPanelData.TetherOrthoMidOffset||0);}else{// Check for multi-handle array first
2101
+ var tmpHandles=this._getTetherBezierHandles(pPanelData);if(tmpHandles.length>0){return this.generateMultiBezierPath(pFrom,pTo,tmpHandles);}// Single-handle legacy path
2102
+ var tmpHandleX=pPanelData.TetherHandleCustomized&&pPanelData.TetherBezierHandleX!=null?pPanelData.TetherBezierHandleX:null;var tmpHandleY=pPanelData.TetherHandleCustomized&&pPanelData.TetherBezierHandleY!=null?pPanelData.TetherBezierHandleY:null;return this.generateBezierPath(pFrom,pTo,tmpHandleX,tmpHandleY);}}/**
2103
+ * Get the bezier handles array for a tether, respecting the customized flag.
2104
+ * @param {Object} pPanelData
2105
+ * @returns {Array<{x: number, y: number}>}
2106
+ */},{key:"_getTetherBezierHandles",value:function _getTetherBezierHandles(pPanelData){if(!pPanelData||!pPanelData.TetherHandleCustomized){return[];}// Multi-handle format
2107
+ if(Array.isArray(pPanelData.TetherBezierHandles)&&pPanelData.TetherBezierHandles.length>0){return pPanelData.TetherBezierHandles;}// Legacy single-handle format
2108
+ if(pPanelData.TetherBezierHandleX!=null&&pPanelData.TetherBezierHandleY!=null){return[{x:pPanelData.TetherBezierHandleX,y:pPanelData.TetherBezierHandleY}];}return[];}/**
2109
+ * Generate a multi-handle bezier path for a tether.
2110
+ * Delegates to PathGenerator.buildMultiBezierPathString.
2111
+ * @param {Object} pFrom - {x, y, side}
2112
+ * @param {Object} pTo - {x, y, side}
2113
+ * @param {Array<{x: number, y: number}>} pHandles
2114
+ * @returns {string} SVG path d attribute
2115
+ */},{key:"generateMultiBezierPath",value:function generateMultiBezierPath(pFrom,pTo,pHandles){var tmpDepartDist=20;var tmpFromDir=this._FlowView._GeometryProvider.sideDirection(pFrom.side);var tmpToDir=this._FlowView._GeometryProvider.sideDirection(pTo.side);var tmpDepart={x:pFrom.x+tmpFromDir.dx*tmpDepartDist,y:pFrom.y+tmpFromDir.dy*tmpDepartDist};var tmpApproach={x:pTo.x+tmpToDir.dx*tmpDepartDist,y:pTo.y+tmpToDir.dy*tmpDepartDist};return this._FlowView._PathGenerator.buildMultiBezierPathString(pFrom,tmpDepart,pFrom.side,tmpApproach,pTo.side,pTo,pHandles);}// ---- Handle State Management ----
2116
+ /**
2117
+ * Update a tether handle position during drag.
2118
+ * @param {Object} pPanelData - Panel data to update
2119
+ * @param {string} pHandleType - 'bezier-midpoint', 'ortho-corner1', 'ortho-corner2', 'ortho-midpoint'
2120
+ * @param {number} pX
2121
+ * @param {number} pY
2122
+ */},{key:"updateHandlePosition",value:function updateHandlePosition(pPanelData,pHandleType,pX,pY){pPanelData.TetherHandleCustomized=true;// Multi-handle bezier: handle type is 'bezier-handle-N'
2123
+ if(pHandleType&&pHandleType.startsWith('bezier-handle-')){var tmpIndex=parseInt(pHandleType.replace('bezier-handle-',''),10);if(!isNaN(tmpIndex)&&Array.isArray(pPanelData.TetherBezierHandles)&&tmpIndex<pPanelData.TetherBezierHandles.length){pPanelData.TetherBezierHandles[tmpIndex].x=pX;pPanelData.TetherBezierHandles[tmpIndex].y=pY;}return;}switch(pHandleType){case'bezier-midpoint':// Migrate to multi-handle array
2124
+ if(!Array.isArray(pPanelData.TetherBezierHandles)||pPanelData.TetherBezierHandles.length===0){pPanelData.TetherBezierHandles=[{x:pX,y:pY}];}else{pPanelData.TetherBezierHandles[0].x=pX;pPanelData.TetherBezierHandles[0].y=pY;}// Keep legacy fields in sync
2125
+ pPanelData.TetherBezierHandleX=pX;pPanelData.TetherBezierHandleY=pY;break;case'ortho-corner1':pPanelData.TetherOrthoCorner1X=pX;pPanelData.TetherOrthoCorner1Y=pY;break;case'ortho-corner2':pPanelData.TetherOrthoCorner2X=pX;pPanelData.TetherOrthoCorner2Y=pY;break;case'ortho-midpoint':// Store the desired position for offset computation
2126
+ pPanelData.TetherOrthoMidOffset=pPanelData.TetherOrthoMidOffset||0;pPanelData._TetherMidDragX=pX;pPanelData._TetherMidDragY=pY;break;}}/**
2127
+ * Reset tether handle positions to auto for a single panel.
2128
+ * Preserves TetherLineMode but clears all handle coordinates.
2129
+ * @param {Object} pPanelData - Panel data to reset
2130
+ */},{key:"resetHandlePositions",value:function resetHandlePositions(pPanelData){if(pPanelData.TetherHandleCustomized){pPanelData.TetherHandleCustomized=false;pPanelData.TetherBezierHandles=[];pPanelData.TetherBezierHandleX=null;pPanelData.TetherBezierHandleY=null;pPanelData.TetherOrthoCorner1X=null;pPanelData.TetherOrthoCorner1Y=null;pPanelData.TetherOrthoCorner2X=null;pPanelData.TetherOrthoCorner2Y=null;pPanelData.TetherOrthoMidOffset=0;}}/**
2131
+ * Reset tether handle positions for all panels attached to a node.
2132
+ * Called when a node moves.
2133
+ * @param {Array} pOpenPanels - Array of all open panel data objects
2134
+ * @param {string} pNodeHash - The node hash whose panels should be reset
2135
+ */},{key:"resetHandlesForNode",value:function resetHandlesForNode(pOpenPanels,pNodeHash){for(var i=0;i<pOpenPanels.length;i++){var tmpPanel=pOpenPanels[i];if(tmpPanel.NodeHash===pNodeHash){this.resetHandlePositions(tmpPanel);}}}/**
2136
+ * Add a bezier handle to a tether at the specified position.
2137
+ * @param {Object} pPanelData - Panel data
2138
+ * @param {number} pX
2139
+ * @param {number} pY
2140
+ * @param {Object} pFrom - Panel anchor {x, y, side}
2141
+ * @param {Object} pTo - Node anchor {x, y, side}
2142
+ */},{key:"addHandle",value:function addHandle(pPanelData,pX,pY,pFrom,pTo){// Ensure bezier mode and multi-handle array
2143
+ pPanelData.TetherLineMode='bezier';if(!Array.isArray(pPanelData.TetherBezierHandles)){pPanelData.TetherBezierHandles=[];// Migrate legacy single-handle if present
2144
+ if(pPanelData.TetherBezierHandleX!=null&&pPanelData.TetherBezierHandleY!=null){pPanelData.TetherBezierHandles.push({x:pPanelData.TetherBezierHandleX,y:pPanelData.TetherBezierHandleY});}}// Compute insertion index
2145
+ var tmpInsertIndex=0;if(this._FlowView._ConnectionRenderer&&pFrom&&pTo){tmpInsertIndex=this._FlowView._ConnectionRenderer.computeInsertionIndex(pPanelData.TetherBezierHandles,{x:pX,y:pY},pFrom,pTo);}pPanelData.TetherBezierHandles.splice(tmpInsertIndex,0,{x:pX,y:pY});pPanelData.TetherHandleCustomized=true;}/**
2146
+ * Remove a bezier handle from a tether by index.
2147
+ * @param {Object} pPanelData - Panel data
2148
+ * @param {number} pIndex - Index in TetherBezierHandles array
2149
+ */},{key:"removeHandle",value:function removeHandle(pPanelData,pIndex){if(!Array.isArray(pPanelData.TetherBezierHandles))return;if(pIndex<0||pIndex>=pPanelData.TetherBezierHandles.length)return;pPanelData.TetherBezierHandles.splice(pIndex,1);if(pPanelData.TetherBezierHandles.length===0){pPanelData.TetherHandleCustomized=false;pPanelData.TetherBezierHandleX=null;pPanelData.TetherBezierHandleY=null;}}/**
2150
+ * Toggle tether line mode between bezier and orthogonal.
2151
+ * Resets handle positions on toggle.
2152
+ * @param {Object} pPanelData - Panel data to toggle
2153
+ * @returns {string} The new line mode ('bezier' or 'orthogonal')
2154
+ */},{key:"toggleLineMode",value:function toggleLineMode(pPanelData){var tmpCurrentMode=pPanelData.TetherLineMode||'bezier';pPanelData.TetherLineMode=tmpCurrentMode==='bezier'?'orthogonal':'bezier';pPanelData.TetherHandleCustomized=false;pPanelData.TetherBezierHandles=[];pPanelData.TetherBezierHandleX=null;pPanelData.TetherBezierHandleY=null;pPanelData.TetherOrthoCorner1X=null;pPanelData.TetherOrthoCorner1Y=null;pPanelData.TetherOrthoCorner2X=null;pPanelData.TetherOrthoCorner2Y=null;pPanelData.TetherOrthoMidOffset=0;return pPanelData.TetherLineMode;}// ---- SVG Rendering ----
2155
+ /**
2156
+ * Render a tether from a panel to its node.
2157
+ * Creates SVG path elements for the line and hit area, plus drag handles when selected.
2158
+ *
2159
+ * @param {Object} pPanelData - Panel data with position and tether properties
2160
+ * @param {Object} pNodeData - Node data with position
2161
+ * @param {SVGGElement} pTethersLayer - SVG group to append elements to
2162
+ * @param {boolean} pIsSelected - Whether this tether is currently selected
2163
+ * @param {string} pViewIdentifier - The flow view identifier (for marker URL)
2164
+ */},{key:"renderTether",value:function renderTether(pPanelData,pNodeData,pTethersLayer,pIsSelected,pViewIdentifier){if(!pNodeData)return;var tmpAnchors=this.getSmartAnchors(pPanelData,pNodeData);var tmpFrom=tmpAnchors.panelAnchor;var tmpTo=tmpAnchors.nodeAnchor;var tmpPath=this.generatePath(pPanelData,tmpFrom,tmpTo);// Hit area and visible tether path
2165
+ var tmpShapeProvider=this._FlowView._ConnectorShapesProvider;if(tmpShapeProvider){var tmpHitArea=tmpShapeProvider.createTetherHitAreaElement(tmpPath,pPanelData.Hash);pTethersLayer.appendChild(tmpHitArea);var tmpPathElement=tmpShapeProvider.createTetherPathElement(tmpPath,pPanelData.Hash,pIsSelected,pViewIdentifier);pTethersLayer.appendChild(tmpPathElement);}else{var _tmpHitArea2=this._FlowView._SVGHelperProvider.createSVGElement('path');_tmpHitArea2.setAttribute('class','pict-flow-tether-hitarea');_tmpHitArea2.setAttribute('d',tmpPath);_tmpHitArea2.setAttribute('data-element-type','tether-hitarea');_tmpHitArea2.setAttribute('data-panel-hash',pPanelData.Hash);pTethersLayer.appendChild(_tmpHitArea2);var _tmpPathElement2=this._FlowView._SVGHelperProvider.createSVGElement('path');_tmpPathElement2.setAttribute('class',"pict-flow-tether-line".concat(pIsSelected?' selected':''));_tmpPathElement2.setAttribute('d',tmpPath);_tmpPathElement2.setAttribute('marker-end',"url(#flow-tether-arrowhead-".concat(pViewIdentifier,")"));_tmpPathElement2.setAttribute('data-element-type','tether');_tmpPathElement2.setAttribute('data-panel-hash',pPanelData.Hash);pTethersLayer.appendChild(_tmpPathElement2);}// Render drag handles when selected
2166
+ if(pIsSelected){this._renderHandles(pPanelData,pTethersLayer,tmpFrom,tmpTo);}}/**
2167
+ * Render drag handles for a selected tether.
2168
+ * @param {Object} pPanelData
2169
+ * @param {SVGGElement} pTethersLayer
2170
+ * @param {Object} pFrom - Panel anchor {x, y, side}
2171
+ * @param {Object} pTo - Node anchor {x, y, side}
2172
+ */},{key:"_renderHandles",value:function _renderHandles(pPanelData,pTethersLayer,pFrom,pTo){var tmpLineMode=pPanelData.TetherLineMode||'bezier';if(tmpLineMode==='orthogonal'){var tmpGeom=this.getOrthoGeometry(pFrom,pTo,pPanelData);// Corner 1 handle
2173
+ this._createHandle(pTethersLayer,pPanelData.Hash,'ortho-corner1',tmpGeom.corner1.x,tmpGeom.corner1.y,'pict-flow-tether-handle');// Midpoint handle
2174
+ this._createHandle(pTethersLayer,pPanelData.Hash,'ortho-midpoint',tmpGeom.midpoint.x,tmpGeom.midpoint.y,'pict-flow-tether-handle-midpoint');// Corner 2 handle
2175
+ this._createHandle(pTethersLayer,pPanelData.Hash,'ortho-corner2',tmpGeom.corner2.x,tmpGeom.corner2.y,'pict-flow-tether-handle');}else{// Bezier handles
2176
+ var tmpHandles=this._getTetherBezierHandles(pPanelData);if(tmpHandles.length>0){// Multi-handle: render each handle as a draggable circle
2177
+ for(var i=0;i<tmpHandles.length;i++){this._createHandle(pTethersLayer,pPanelData.Hash,'bezier-handle-'+i,tmpHandles[i].x,tmpHandles[i].y,'pict-flow-tether-handle');}}else{// No custom handles: show auto-computed midpoint
2178
+ var tmpMid=this.getAutoMidpoint(pFrom,pTo);this._createHandle(pTethersLayer,pPanelData.Hash,'bezier-midpoint',tmpMid.x,tmpMid.y,'pict-flow-tether-handle-midpoint');}}}/**
2179
+ * Create a single tether drag handle circle.
2180
+ * @param {SVGGElement} pLayer
2181
+ * @param {string} pPanelHash
2182
+ * @param {string} pHandleType
2183
+ * @param {number} pX
2184
+ * @param {number} pY
2185
+ * @param {string} pClassName
2186
+ */},{key:"_createHandle",value:function _createHandle(pLayer,pPanelHash,pHandleType,pX,pY,pClassName){if(!this._FlowView._ConnectorShapesProvider)return;var tmpShapeKey=pClassName==='pict-flow-tether-handle-midpoint'?'tether-handle-midpoint':'tether-handle';this._FlowView._ConnectorShapesProvider.createFullHandle(pLayer,pPanelHash,pHandleType,pX,pY,tmpShapeKey,'tether-handle','data-panel-hash');}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowTether;},{"fable-serviceproviderbase":4}],38:[function(require,module,exports){var libFableServiceProviderBase=require('fable-serviceproviderbase');/**
2187
+ * PictService-Flow-ViewportManager
2188
+ *
2189
+ * Manages viewport transforms (pan/zoom), coordinate conversion between
2190
+ * screen and SVG space, zoom-to-fit calculations, and fullscreen toggling
2191
+ * for the flow diagram.
2192
+ */var PictServiceFlowViewportManager=/*#__PURE__*/function(_libFableServiceProvi20){function PictServiceFlowViewportManager(pFable,pOptions,pServiceHash){var _this49;_classCallCheck(this,PictServiceFlowViewportManager);_this49=_callSuper(this,PictServiceFlowViewportManager,[pFable,pOptions,pServiceHash]);_this49.serviceType='PictServiceFlowViewportManager';_this49._FlowView=pOptions&&pOptions.FlowView?pOptions.FlowView:null;_this49._IsFullscreen=false;return _this49;}/**
2193
+ * Update the viewport transform (pan and zoom)
2194
+ */_inherits(PictServiceFlowViewportManager,_libFableServiceProvi20);return _createClass(PictServiceFlowViewportManager,[{key:"updateViewportTransform",value:function updateViewportTransform(){if(!this._FlowView._ViewportElement)return;var tmpVS=this._FlowView._FlowData.ViewState;this._FlowView._ViewportElement.setAttribute('transform',"translate(".concat(tmpVS.PanX,", ").concat(tmpVS.PanY,") scale(").concat(tmpVS.Zoom,")"));}/**
2195
+ * Set zoom level
2196
+ * @param {number} pZoom - The zoom level
2197
+ * @param {number} [pFocusX] - X coordinate to zoom toward (SVG space)
2198
+ * @param {number} [pFocusY] - Y coordinate to zoom toward (SVG space)
2199
+ */},{key:"setZoom",value:function setZoom(pZoom,pFocusX,pFocusY){var tmpNewZoom=Math.max(this._FlowView.options.MinZoom,Math.min(this._FlowView.options.MaxZoom,pZoom));var tmpOldZoom=this._FlowView._FlowData.ViewState.Zoom;if(typeof pFocusX==='number'&&typeof pFocusY==='number'){// Zoom toward focus point
2200
+ var tmpVS=this._FlowView._FlowData.ViewState;tmpVS.PanX=pFocusX-(pFocusX-tmpVS.PanX)*(tmpNewZoom/tmpOldZoom);tmpVS.PanY=pFocusY-(pFocusY-tmpVS.PanY)*(tmpNewZoom/tmpOldZoom);}this._FlowView._FlowData.ViewState.Zoom=tmpNewZoom;this.updateViewportTransform();}/**
2201
+ * Zoom to fit all nodes in the viewport
2202
+ */},{key:"zoomToFit",value:function zoomToFit(){if(this._FlowView._FlowData.Nodes.length===0)return;if(!this._FlowView._SVGElement)return;var tmpMinX=Infinity,tmpMinY=Infinity;var tmpMaxX=-Infinity,tmpMaxY=-Infinity;for(var i=0;i<this._FlowView._FlowData.Nodes.length;i++){var tmpNode=this._FlowView._FlowData.Nodes[i];tmpMinX=Math.min(tmpMinX,tmpNode.X);tmpMinY=Math.min(tmpMinY,tmpNode.Y);tmpMaxX=Math.max(tmpMaxX,tmpNode.X+tmpNode.Width);tmpMaxY=Math.max(tmpMaxY,tmpNode.Y+tmpNode.Height);}var tmpPadding=50;var tmpFlowWidth=tmpMaxX-tmpMinX+tmpPadding*2;var tmpFlowHeight=tmpMaxY-tmpMinY+tmpPadding*2;var tmpSVGRect=this._FlowView._SVGElement.getBoundingClientRect();var tmpScaleX=tmpSVGRect.width/tmpFlowWidth;var tmpScaleY=tmpSVGRect.height/tmpFlowHeight;var tmpZoom=Math.min(tmpScaleX,tmpScaleY,1.0);// Don't zoom in past 1.0
2203
+ tmpZoom=Math.max(this._FlowView.options.MinZoom,Math.min(this._FlowView.options.MaxZoom,tmpZoom));var tmpCenterX=(tmpMinX+tmpMaxX)/2;var tmpCenterY=(tmpMinY+tmpMaxY)/2;this._FlowView._FlowData.ViewState.Zoom=tmpZoom;this._FlowView._FlowData.ViewState.PanX=tmpSVGRect.width/2-tmpCenterX*tmpZoom;this._FlowView._FlowData.ViewState.PanY=tmpSVGRect.height/2-tmpCenterY*tmpZoom;this.updateViewportTransform();}/**
2204
+ * Convert screen coordinates to SVG viewport coordinates
2205
+ * @param {number} pScreenX
2206
+ * @param {number} pScreenY
2207
+ * @returns {{x: number, y: number}}
2208
+ */},{key:"screenToSVGCoords",value:function screenToSVGCoords(pScreenX,pScreenY){if(!this._FlowView._SVGElement){return{x:pScreenX,y:pScreenY};}var tmpPoint=this._FlowView._SVGElement.createSVGPoint();tmpPoint.x=pScreenX;tmpPoint.y=pScreenY;var tmpCTM=this._FlowView._SVGElement.getScreenCTM();if(tmpCTM){var tmpInverse=tmpCTM.inverse();var tmpTransformed=tmpPoint.matrixTransform(tmpInverse);// Account for viewport pan/zoom
2209
+ var tmpVS=this._FlowView._FlowData.ViewState;return{x:(tmpTransformed.x-tmpVS.PanX)/tmpVS.Zoom,y:(tmpTransformed.y-tmpVS.PanY)/tmpVS.Zoom};}return{x:pScreenX,y:pScreenY};}/**
2210
+ * Toggle fullscreen mode on the flow editor container.
2211
+ * Uses a CSS fixed-position overlay instead of the Fullscreen API.
2212
+ * @returns {boolean} The new fullscreen state
2213
+ */},{key:"toggleFullscreen",value:function toggleFullscreen(){var tmpViewIdentifier=this._FlowView.options.ViewIdentifier;var tmpContainerElements=this._FlowView.pict.ContentAssignment.getElement("#Flow-Wrapper-".concat(tmpViewIdentifier));if(tmpContainerElements.length<1)return this._IsFullscreen;var tmpContainer=tmpContainerElements[0];this._IsFullscreen=!this._IsFullscreen;if(this._IsFullscreen){tmpContainer.classList.add('pict-flow-fullscreen');}else{tmpContainer.classList.remove('pict-flow-fullscreen');}return this._IsFullscreen;}/**
2214
+ * Exit fullscreen mode if currently active.
2215
+ */},{key:"exitFullscreen",value:function exitFullscreen(){if(!this._IsFullscreen)return;var tmpViewIdentifier=this._FlowView.options.ViewIdentifier;var tmpContainerElements=this._FlowView.pict.ContentAssignment.getElement("#Flow-Wrapper-".concat(tmpViewIdentifier));if(tmpContainerElements.length>0){tmpContainerElements[0].classList.remove('pict-flow-fullscreen');}this._IsFullscreen=false;}}]);}(libFableServiceProviderBase);module.exports=PictServiceFlowViewportManager;},{"fable-serviceproviderbase":4}],39:[function(require,module,exports){var libPictView=require('pict-view');var _DefaultConfiguration={ViewIdentifier:'Flow-FloatingToolbar',DefaultRenderable:'Flow-FloatingToolbar-Content',DefaultDestinationAddress:'#Flow-FloatingToolbar-Container',AutoRender:false,FlowViewIdentifier:'Pict-Flow',CSS:false,Templates:[{Hash:'Flow-FloatingToolbar-Template',Template:/*html*/"\n<div class=\"pict-flow-floating-toolbar\" id=\"Flow-FloatingToolbar-{~D:Record.FlowViewIdentifier~}\">\n\t<div class=\"pict-flow-floating-grip\" id=\"Flow-FloatingGrip-{~D:Record.FlowViewIdentifier~}\" title=\"Drag to move \xB7 Double-click to collapse\">\n\t\t<span id=\"Flow-FloatingIcon-grip-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</div>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"add-node\" title=\"Add Node\">\n\t\t<span id=\"Flow-FloatingIcon-plus-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"cards-popup\" title=\"Cards\">\n\t\t<span id=\"Flow-FloatingIcon-cards-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"delete-selected\" title=\"Delete Selected\">\n\t\t<span id=\"Flow-FloatingIcon-trash-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<div class=\"pict-flow-floating-separator\"></div>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"zoom-in\" title=\"Zoom In\">\n\t\t<span id=\"Flow-FloatingIcon-zoom-in-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"zoom-out\" title=\"Zoom Out\">\n\t\t<span id=\"Flow-FloatingIcon-zoom-out-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"zoom-fit\" title=\"Fit to View\">\n\t\t<span id=\"Flow-FloatingIcon-zoom-fit-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<div class=\"pict-flow-floating-separator\"></div>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"auto-layout\" title=\"Auto Layout\">\n\t\t<span id=\"Flow-FloatingIcon-auto-layout-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"layout-popup\" title=\"Layout\">\n\t\t<span id=\"Flow-FloatingIcon-layout-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"fullscreen\" title=\"Toggle Fullscreen\">\n\t\t<span id=\"Flow-FloatingIcon-fullscreen-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n\t<div class=\"pict-flow-floating-separator\"></div>\n\t<button class=\"pict-flow-floating-btn\" data-flow-action=\"dock-toolbar\" title=\"Dock Toolbar\">\n\t\t<span id=\"Flow-FloatingIcon-dock-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n</div>\n"}],Renderables:[{RenderableHash:'Flow-FloatingToolbar-Content',TemplateHash:'Flow-FloatingToolbar-Template',DestinationAddress:'#Flow-FloatingToolbar-Container',RenderMethod:'replace'}]};var PictViewFlowFloatingToolbar=/*#__PURE__*/function(_libPictView){function PictViewFlowFloatingToolbar(pFable,pOptions,pServiceHash){var _this50;_classCallCheck(this,PictViewFlowFloatingToolbar);var tmpOptions=Object.assign({},JSON.parse(JSON.stringify(_DefaultConfiguration)),pOptions);_this50=_callSuper(this,PictViewFlowFloatingToolbar,[pFable,tmpOptions,pServiceHash]);_this50.serviceType='PictViewFlowFloatingToolbar';_this50._ToolbarView=null;_this50._FlowView=null;_this50._IsCollapsed=false;_this50._IsDragging=false;_this50._DragStartX=0;_this50._DragStartY=0;_this50._DragStartLeft=0;_this50._DragStartTop=0;_this50._BoundMouseMove=null;_this50._BoundMouseUp=null;return _this50;}_inherits(PictViewFlowFloatingToolbar,_libPictView);return _createClass(PictViewFlowFloatingToolbar,[{key:"render",value:function render(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress){return _superPropGet(PictViewFlowFloatingToolbar,"render",this,3)([pRenderableHash,pRenderDestinationAddress,this.options]);}},{key:"onAfterRender",value:function onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent){var _this51=this;var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;// Bind click delegation for action buttons
2216
+ var tmpFloatingToolbar=this.pict.ContentAssignment.getElement("#Flow-FloatingToolbar-".concat(tmpFlowViewIdentifier));if(tmpFloatingToolbar.length>0){tmpFloatingToolbar[0].addEventListener('click',function(pEvent){var tmpTarget=pEvent.target;if(!tmpTarget)return;var tmpButton=tmpTarget.closest('[data-flow-action]');if(!tmpButton)return;var tmpAction=tmpButton.getAttribute('data-flow-action');if(tmpAction==='dock-toolbar'){if(_this51._ToolbarView){_this51._ToolbarView._setToolbarMode('docked');}return;}// Delegate all other actions to the docked toolbar
2217
+ if(_this51._ToolbarView){_this51._ToolbarView._handleToolbarAction(tmpAction);}});}// Bind drag behavior on the grip
2218
+ var tmpGrip=this.pict.ContentAssignment.getElement("#Flow-FloatingGrip-".concat(tmpFlowViewIdentifier));if(tmpGrip.length>0){tmpGrip[0].addEventListener('mousedown',function(pEvent){_this51._startDrag(pEvent);});// Double-click grip to toggle collapsed state
2219
+ tmpGrip[0].addEventListener('dblclick',function(pEvent){pEvent.preventDefault();pEvent.stopPropagation();_this51._toggleCollapse();});}// Populate icons
2220
+ this._populateIcons();// Remove buttons from DOM based on options
2221
+ if(tmpFloatingToolbar.length>0){if(this.options.EnableAddNode===false){var tmpAddNodeBtn=tmpFloatingToolbar[0].querySelector('[data-flow-action="add-node"]');if(tmpAddNodeBtn){tmpAddNodeBtn.remove();}}if(this.options.EnableCardPalette===false){var tmpCardsBtn=tmpFloatingToolbar[0].querySelector('[data-flow-action="cards-popup"]');if(tmpCardsBtn){tmpCardsBtn.remove();}}}return _superPropGet(PictViewFlowFloatingToolbar,"onAfterRender",this,3)([pRenderable,pRenderDestinationAddress,pRecord,pContent]);}/**
2222
+ * Populate SVG icons into all floating toolbar button spans.
2223
+ */},{key:"_populateIcons",value:function _populateIcons(){var tmpIconProvider=this._FlowView?this._FlowView._IconProvider:null;if(!tmpIconProvider)return;var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpIconMap={'grip':'grip','plus':'plus','trash':'trash','zoom-in':'zoom-in','zoom-out':'zoom-out','zoom-fit':'zoom-fit','auto-layout':'auto-layout','cards':'cards','layout':'layout','fullscreen':'fullscreen','dock':'dock'};var tmpKeys=Object.keys(tmpIconMap);for(var i=0;i<tmpKeys.length;i++){var tmpElementId="Flow-FloatingIcon-".concat(tmpKeys[i],"-").concat(tmpFlowViewIdentifier);var tmpElements=this.pict.ContentAssignment.getElement("#".concat(tmpElementId));if(tmpElements.length>0){tmpElements[0].innerHTML=tmpIconProvider.getIconSVGMarkup(tmpIconMap[tmpKeys[i]],16);}}}/**
2224
+ * Toggle the floating toolbar between expanded and collapsed (grip-only square) states.
2225
+ */},{key:"_toggleCollapse",value:function _toggleCollapse(){var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpToolbar=this.pict.ContentAssignment.getElement("#Flow-FloatingToolbar-".concat(tmpFlowViewIdentifier));if(tmpToolbar.length<1)return;this._IsCollapsed=!this._IsCollapsed;if(this._IsCollapsed){tmpToolbar[0].classList.add('collapsed');}else{tmpToolbar[0].classList.remove('collapsed');}}/**
2226
+ * Start dragging the floating toolbar.
2227
+ * @param {MouseEvent} pEvent
2228
+ */},{key:"_startDrag",value:function _startDrag(pEvent){var _this52=this;pEvent.preventDefault();var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpToolbar=this.pict.ContentAssignment.getElement("#Flow-FloatingToolbar-".concat(tmpFlowViewIdentifier));if(tmpToolbar.length<1)return;var tmpEl=tmpToolbar[0];this._IsDragging=true;this._DragStartX=pEvent.clientX;this._DragStartY=pEvent.clientY;this._DragStartLeft=tmpEl.offsetLeft;this._DragStartTop=tmpEl.offsetTop;this._BoundMouseMove=function(pMoveEvent){_this52._onDragMove(pMoveEvent);};this._BoundMouseUp=function(){_this52._onDragEnd();};document.addEventListener('mousemove',this._BoundMouseMove);document.addEventListener('mouseup',this._BoundMouseUp);}/**
2229
+ * Handle drag movement.
2230
+ * @param {MouseEvent} pEvent
2231
+ */},{key:"_onDragMove",value:function _onDragMove(pEvent){if(!this._IsDragging)return;var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpToolbar=this.pict.ContentAssignment.getElement("#Flow-FloatingToolbar-".concat(tmpFlowViewIdentifier));if(tmpToolbar.length<1)return;var tmpEl=tmpToolbar[0];var tmpDeltaX=pEvent.clientX-this._DragStartX;var tmpDeltaY=pEvent.clientY-this._DragStartY;var tmpNewLeft=this._DragStartLeft+tmpDeltaX;var tmpNewTop=this._DragStartTop+tmpDeltaY;// Clamp to parent bounds
2232
+ var tmpParent=tmpEl.parentElement;if(tmpParent){var tmpMaxLeft=tmpParent.clientWidth-tmpEl.offsetWidth;var tmpMaxTop=tmpParent.clientHeight-tmpEl.offsetHeight;tmpNewLeft=Math.max(0,Math.min(tmpNewLeft,tmpMaxLeft));tmpNewTop=Math.max(0,Math.min(tmpNewTop,tmpMaxTop));}tmpEl.style.left=tmpNewLeft+'px';tmpEl.style.top=tmpNewTop+'px';}/**
2233
+ * End dragging.
2234
+ */},{key:"_onDragEnd",value:function _onDragEnd(){this._IsDragging=false;if(this._BoundMouseMove){document.removeEventListener('mousemove',this._BoundMouseMove);this._BoundMouseMove=null;}if(this._BoundMouseUp){document.removeEventListener('mouseup',this._BoundMouseUp);this._BoundMouseUp=null;}// Save position
2235
+ if(this._ToolbarView){var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpToolbar=this.pict.ContentAssignment.getElement("#Flow-FloatingToolbar-".concat(tmpFlowViewIdentifier));if(tmpToolbar.length>0){this._ToolbarView._FloatingPosition.X=tmpToolbar[0].offsetLeft;this._ToolbarView._FloatingPosition.Y=tmpToolbar[0].offsetTop;}}}/**
2236
+ * Show the floating toolbar at the saved position.
2237
+ */},{key:"show",value:function show(){var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpContainer=this.pict.ContentAssignment.getElement("#Flow-FloatingToolbar-Container-".concat(tmpFlowViewIdentifier));if(tmpContainer.length>0){tmpContainer[0].style.display='block';}var tmpToolbar=this.pict.ContentAssignment.getElement("#Flow-FloatingToolbar-".concat(tmpFlowViewIdentifier));if(tmpToolbar.length>0&&this._ToolbarView){tmpToolbar[0].style.left=this._ToolbarView._FloatingPosition.X+'px';tmpToolbar[0].style.top=this._ToolbarView._FloatingPosition.Y+'px';}// Restore expanded state when showing
2238
+ if(this._IsCollapsed&&tmpToolbar.length>0){this._IsCollapsed=false;tmpToolbar[0].classList.remove('collapsed');}}/**
2239
+ * Hide the floating toolbar.
2240
+ */},{key:"hide",value:function hide(){var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpContainer=this.pict.ContentAssignment.getElement("#Flow-FloatingToolbar-Container-".concat(tmpFlowViewIdentifier));if(tmpContainer.length>0){tmpContainer[0].style.display='none';}}}]);}(libPictView);module.exports=PictViewFlowFloatingToolbar;module.exports.default_configuration=_DefaultConfiguration;},{"pict-view":45}],40:[function(require,module,exports){var libPictView=require('pict-view');var _DefaultConfiguration={ViewIdentifier:'Flow-NodeRenderer',AutoRender:false,// Title bar height for nodes
2241
+ NodeTitleBarHeight:22};var PictViewFlowNode=/*#__PURE__*/function(_libPictView2){function PictViewFlowNode(pFable,pOptions,pServiceHash){var _this53;_classCallCheck(this,PictViewFlowNode);var tmpOptions=Object.assign({},JSON.parse(JSON.stringify(_DefaultConfiguration)),pOptions);_this53=_callSuper(this,PictViewFlowNode,[pFable,tmpOptions,pServiceHash]);_this53.serviceType='PictViewFlowNode';_this53._FlowView=null;return _this53;}/**
2242
+ * Render a node into the nodes SVG layer
2243
+ * @param {Object} pNodeData - The node data object
2244
+ * @param {SVGGElement} pNodesLayer - The SVG <g> element to append to
2245
+ * @param {boolean} pIsSelected - Whether this node is selected
2246
+ * @param {Object} pNodeTypeConfig - The node type configuration
2247
+ */_inherits(PictViewFlowNode,_libPictView2);return _createClass(PictViewFlowNode,[{key:"renderNode",value:function renderNode(pNodeData,pNodesLayer,pIsSelected,pNodeTypeConfig){var _this54=this;var tmpGroup=this._FlowView._SVGHelperProvider.createSVGElement('g');// Build CSS class list with optional per-type modifier classes
2248
+ var tmpClassList="pict-flow-node ".concat(pIsSelected?'selected':''," pict-flow-node-").concat(pNodeData.Type||'default');if(pNodeTypeConfig){if(pNodeTypeConfig.PortLabelsOnHover)tmpClassList+=' pict-flow-node-port-labels-hover';if(pNodeTypeConfig.PortLabelsVertical)tmpClassList+=' pict-flow-node-port-labels-vertical';}tmpGroup.setAttribute('class',tmpClassList);tmpGroup.setAttribute('transform',"translate(".concat(pNodeData.X,", ").concat(pNodeData.Y,")"));tmpGroup.setAttribute('data-node-hash',pNodeData.Hash);tmpGroup.setAttribute('data-element-type','node');var tmpWidth=pNodeData.Width||180;var tmpHeight=pNodeData.Height||80;var tmpTitleBarHeight=this.options.NodeTitleBarHeight;// Ensure node is tall enough for all ports in their zones
2249
+ var tmpGeomProvider=this._FlowView._GeometryProvider;if(tmpGeomProvider&&pNodeData.Ports&&pNodeData.Ports.length>0){var tmpMinHeight=tmpGeomProvider.computeMinimumNodeHeight(pNodeData.Ports,tmpTitleBarHeight);if(tmpMinHeight>tmpHeight){tmpHeight=tmpMinHeight;}}// Write the adjusted dimensions back to the node data so that
2250
+ // connection rendering (which reads pNodeData.Width/Height to
2251
+ // compute port positions) uses the same values we render with.
2252
+ pNodeData.Width=tmpWidth;pNodeData.Height=tmpHeight;// Determine node body mode from theme (bracket vs rect)
2253
+ var tmpNodeBodyMode='rect';if(this._FlowView._ThemeProvider){var tmpActiveTheme=this._FlowView._ThemeProvider.getActiveTheme();if(tmpActiveTheme&&tmpActiveTheme.NodeBodyMode){tmpNodeBodyMode=tmpActiveTheme.NodeBodyMode;}}if(tmpNodeBodyMode==='bracket'){this._renderBracketNodeBody(tmpGroup,pNodeData,tmpWidth,tmpHeight,tmpTitleBarHeight,pNodeTypeConfig);}else{this._renderRectNodeBody(tmpGroup,pNodeData,tmpWidth,tmpHeight,tmpTitleBarHeight,pNodeTypeConfig);}// Determine if this node has a title-bar icon (FlowCard with CardMetadata)
2254
+ var tmpHasTitleIcon=false;var tmpTitleIconSize=12;var tmpTitleIconMarginLeft=8;var tmpTitleIconGap=4;if(pNodeTypeConfig&&pNodeTypeConfig.CardMetadata){var tmpMeta=pNodeTypeConfig.CardMetadata;var tmpIconProvider=this._FlowView._IconProvider;if(tmpMeta.Icon||tmpIconProvider){tmpHasTitleIcon=true;}}// Title text (position adjusts when a title-bar icon is present)
2255
+ var tmpTitle=this._FlowView._SVGHelperProvider.createSVGElement('text');tmpTitle.setAttribute('class','pict-flow-node-title');if(tmpHasTitleIcon){tmpTitle.setAttribute('x',String(tmpTitleIconMarginLeft+tmpTitleIconSize+tmpTitleIconGap));tmpTitle.setAttribute('text-anchor','start');}else{tmpTitle.setAttribute('x',String(tmpWidth/2));tmpTitle.setAttribute('text-anchor','middle');}tmpTitle.setAttribute('y',String(tmpTitleBarHeight/2+1));tmpTitle.setAttribute('dominant-baseline','central');tmpTitle.textContent=pNodeData.Title||'Untitled';tmpGroup.appendChild(tmpTitle);// Determine whether labels should be rendered
2256
+ var tmpShowTypeLabel=!pNodeTypeConfig||pNodeTypeConfig.ShowTypeLabel!==false;var tmpLabelsInFront=!pNodeTypeConfig||pNodeTypeConfig.LabelsInFront!==false;// Helper: render type label + code badge + tooltip (the "middle labels")
2257
+ var tmpRenderTypeLabels=function tmpRenderTypeLabels(){// Type label (below title bar — hover-only for FlowCard nodes via CSS)
2258
+ if(tmpShowTypeLabel&&pNodeTypeConfig&&pNodeTypeConfig.Label&&pNodeTypeConfig.Label!==pNodeData.Title){var tmpTypeLabel=_this54._FlowView._SVGHelperProvider.createSVGElement('text');tmpTypeLabel.setAttribute('class','pict-flow-node-type-label');tmpTypeLabel.setAttribute('x',String(tmpWidth/2));tmpTypeLabel.setAttribute('y',String(tmpTitleBarHeight+16));tmpTypeLabel.setAttribute('text-anchor','middle');tmpTypeLabel.setAttribute('dominant-baseline','central');tmpTypeLabel.textContent=pNodeTypeConfig.Label;tmpGroup.appendChild(tmpTypeLabel);}// FlowCard metadata: icon in title bar, code badge in body (hover-only via CSS)
2259
+ if(pNodeTypeConfig&&pNodeTypeConfig.CardMetadata){var _tmpMeta=pNodeTypeConfig.CardMetadata;var _tmpIconProvider=_this54._FlowView._IconProvider;var tmpTitleIconRendered=false;// Icon position in title bar (vertically centered)
2260
+ var tmpIconX=tmpTitleIconMarginLeft;var tmpIconY=(tmpTitleBarHeight-tmpTitleIconSize)/2;if(_tmpMeta.Icon&&_tmpIconProvider&&!_tmpIconProvider.isEmojiIcon(_tmpMeta.Icon)){// SVG icon via the icon provider — rendered into title bar
2261
+ var tmpResolvedKey=_tmpIconProvider.resolveIconKey(_tmpMeta);var tmpIconGroup=_tmpIconProvider.renderIconIntoSVGGroup(tmpResolvedKey,tmpGroup,tmpIconX,tmpIconY,tmpTitleIconSize);if(tmpIconGroup){tmpIconGroup.setAttribute('class',(tmpIconGroup.getAttribute('class')||'')+' pict-flow-node-title-icon');}tmpTitleIconRendered=true;}else if(_tmpMeta.Icon&&_tmpIconProvider&&_tmpIconProvider.isEmojiIcon(_tmpMeta.Icon)){// Emoji icon in title bar
2262
+ var tmpIconText=_this54._FlowView._SVGHelperProvider.createSVGElement('text');tmpIconText.setAttribute('class','pict-flow-node-card-icon pict-flow-node-title-icon-emoji');tmpIconText.setAttribute('font-size',String(tmpTitleIconSize));tmpIconText.setAttribute('text-anchor','middle');tmpIconText.setAttribute('dominant-baseline','central');tmpIconText.setAttribute('pointer-events','none');tmpIconText.setAttribute('x',String(tmpIconX+tmpTitleIconSize/2));tmpIconText.setAttribute('y',String(tmpTitleBarHeight/2));tmpIconText.textContent=_tmpMeta.Icon;tmpGroup.appendChild(tmpIconText);tmpTitleIconRendered=true;}else if(_tmpMeta.Icon){// No icon provider — text fallback in title bar
2263
+ var _tmpIconText=_this54._FlowView._SVGHelperProvider.createSVGElement('text');_tmpIconText.setAttribute('class','pict-flow-node-card-icon pict-flow-node-title-icon-emoji');_tmpIconText.setAttribute('font-size',String(tmpTitleIconSize));_tmpIconText.setAttribute('text-anchor','middle');_tmpIconText.setAttribute('dominant-baseline','central');_tmpIconText.setAttribute('pointer-events','none');_tmpIconText.setAttribute('x',String(tmpIconX+tmpTitleIconSize/2));_tmpIconText.setAttribute('y',String(tmpTitleBarHeight/2));_tmpIconText.textContent=_tmpMeta.Icon;tmpGroup.appendChild(_tmpIconText);tmpTitleIconRendered=true;}// Default fallback icon in title bar
2264
+ if(!tmpTitleIconRendered&&_tmpIconProvider){var _tmpIconGroup=_tmpIconProvider.renderIconIntoSVGGroup('default',tmpGroup,tmpIconX,tmpIconY,tmpTitleIconSize);if(_tmpIconGroup){_tmpIconGroup.setAttribute('class',(_tmpIconGroup.getAttribute('class')||'')+' pict-flow-node-title-icon');}}// Code badge in body (hover-only via CSS, skipped when ShowTypeLabel is false)
2265
+ var tmpBodyCenterY=tmpTitleBarHeight+(tmpHeight-tmpTitleBarHeight)/2;if(tmpShowTypeLabel&&_tmpMeta.Code){var tmpCodeText=_this54._FlowView._SVGHelperProvider.createSVGElement('text');tmpCodeText.setAttribute('class','pict-flow-node-card-code');tmpCodeText.setAttribute('font-size','10');tmpCodeText.setAttribute('font-family','monospace');tmpCodeText.setAttribute('fill','#7f8c8d');tmpCodeText.setAttribute('text-anchor','middle');tmpCodeText.setAttribute('dominant-baseline','central');tmpCodeText.setAttribute('pointer-events','none');tmpCodeText.setAttribute('x',String(tmpWidth/2));tmpCodeText.setAttribute('y',String(tmpBodyCenterY));tmpCodeText.textContent=_tmpMeta.Code;tmpGroup.appendChild(tmpCodeText);}// Tooltip via SVG <title> element
2266
+ if(_tmpMeta.Tooltip||_tmpMeta.Description){var tmpSVGTitle=_this54._FlowView._SVGHelperProvider.createSVGElement('title');tmpSVGTitle.textContent=_tmpMeta.Tooltip||_tmpMeta.Description;tmpGroup.appendChild(tmpSVGTitle);}}};// Render order depends on LabelsInFront:
2267
+ // true (default): body content first, then labels + ports (labels on top)
2268
+ // false: labels + ports first, then body content (content on top)
2269
+ if(tmpLabelsInFront){this._renderBodyContent(pNodeData,tmpGroup,tmpWidth,tmpHeight,pNodeTypeConfig);tmpRenderTypeLabels();this._renderPorts(pNodeData,tmpGroup,tmpWidth,tmpHeight,pNodeTypeConfig);}else{tmpRenderTypeLabels();this._renderPorts(pNodeData,tmpGroup,tmpWidth,tmpHeight,pNodeTypeConfig);this._renderBodyContent(pNodeData,tmpGroup,tmpWidth,tmpHeight,pNodeTypeConfig);}// Panel indicator icon (small rect in bottom-right corner)
2270
+ if(pNodeTypeConfig&&pNodeTypeConfig.PropertiesPanel){var tmpIndicatorSize=10;var tmpIndicatorMargin=4;var tmpIndicatorX=tmpWidth-tmpIndicatorSize-tmpIndicatorMargin;var tmpIndicatorY=tmpHeight-tmpIndicatorSize-tmpIndicatorMargin;var tmpShapeProvider=this._FlowView._ConnectorShapesProvider;var tmpIndicator;if(tmpShapeProvider){tmpIndicator=tmpShapeProvider.createPanelIndicatorElement(pNodeData.Hash,tmpIndicatorX,tmpIndicatorY,tmpIndicatorSize,tmpIndicatorSize);}else{tmpIndicator=this._FlowView._SVGHelperProvider.createSVGElement('rect');tmpIndicator.setAttribute('class','pict-flow-node-panel-indicator');tmpIndicator.setAttribute('x',String(tmpIndicatorX));tmpIndicator.setAttribute('y',String(tmpIndicatorY));tmpIndicator.setAttribute('width',String(tmpIndicatorSize));tmpIndicator.setAttribute('height',String(tmpIndicatorSize));tmpIndicator.setAttribute('rx','2');tmpIndicator.setAttribute('ry','2');tmpIndicator.setAttribute('data-node-hash',pNodeData.Hash);tmpIndicator.setAttribute('data-element-type','panel-indicator');}var tmpIndicatorTitle=this._FlowView._SVGHelperProvider.createSVGElement('title');tmpIndicatorTitle.textContent='Double-click to open properties';tmpIndicator.appendChild(tmpIndicatorTitle);tmpGroup.appendChild(tmpIndicator);}pNodesLayer.appendChild(tmpGroup);}/**
2271
+ * Render ports for a node — delegates to the PortRenderer service.
2272
+ * @param {Object} pNodeData
2273
+ * @param {SVGGElement} pGroup - The node's SVG group
2274
+ * @param {number} pWidth
2275
+ * @param {number} pHeight
2276
+ * @param {Object} [pNodeTypeConfig] - Node type configuration (for label display options)
2277
+ */},{key:"_renderPorts",value:function _renderPorts(pNodeData,pGroup,pWidth,pHeight,pNodeTypeConfig){this._FlowView._PortRenderer.renderPorts(pNodeData,pGroup,pWidth,pHeight,pNodeTypeConfig,this.options.NodeTitleBarHeight);}/**
2278
+ * Render custom body content for a node (svg, html, or canvas).
2279
+ *
2280
+ * Checks for a BodyContent configuration on the node type and renders
2281
+ * the appropriate content type into the node's SVG group.
2282
+ *
2283
+ * @param {Object} pNodeData - The node data object
2284
+ * @param {SVGGElement} pGroup - The node's SVG group
2285
+ * @param {number} pWidth - Node width
2286
+ * @param {number} pHeight - Node height
2287
+ * @param {Object} pNodeTypeConfig - The node type configuration
2288
+ */},{key:"_renderBodyContent",value:function _renderBodyContent(pNodeData,pGroup,pWidth,pHeight,pNodeTypeConfig){if(!pNodeTypeConfig||!pNodeTypeConfig.BodyContent)return;var tmpBodyContent=pNodeTypeConfig.BodyContent;var tmpContentType=tmpBodyContent.ContentType;if(!tmpContentType)return;var tmpTitleBarHeight=this.options.NodeTitleBarHeight;var tmpPadding=typeof tmpBodyContent.Padding==='number'?tmpBodyContent.Padding:2;var tmpBodyBounds={x:tmpPadding,y:tmpTitleBarHeight+tmpPadding,width:pWidth-tmpPadding*2,height:pHeight-tmpTitleBarHeight-tmpPadding*2};var tmpPict=this._FlowView.pict||this.pict;// Register any templates defined in the BodyContent config (once)
2289
+ if(tmpBodyContent.Templates&&Array.isArray(tmpBodyContent.Templates)){if(!this._registeredBodyTemplates){this._registeredBodyTemplates=new Set();}for(var i=0;i<tmpBodyContent.Templates.length;i++){var tmpTpl=tmpBodyContent.Templates[i];if(tmpTpl.Hash&&tmpTpl.Template&&!this._registeredBodyTemplates.has(tmpTpl.Hash)){tmpPict.TemplateProvider.addTemplate(tmpTpl.Hash,tmpTpl.Template,'PictViewFlowNode-BodyContent');this._registeredBodyTemplates.add(tmpTpl.Hash);}}}switch(tmpContentType){case'svg':this._renderBodyContentSVG(pNodeData,pGroup,tmpBodyContent,tmpBodyBounds,pNodeTypeConfig,tmpPict);break;case'html':this._renderBodyContentHTML(pNodeData,pGroup,tmpBodyContent,tmpBodyBounds,pNodeTypeConfig,tmpPict);break;case'canvas':this._renderBodyContentCanvas(pNodeData,pGroup,tmpBodyContent,tmpBodyBounds,pNodeTypeConfig);break;default:this.log.warn('PictViewFlowNode _renderBodyContent: unknown ContentType ['+tmpContentType+']');break;}}/**
2290
+ * Render SVG body content into a <g> group.
2291
+ */},{key:"_renderBodyContentSVG",value:function _renderBodyContentSVG(pNodeData,pGroup,pBodyContent,pBounds,pNodeTypeConfig,pPict){var tmpContentGroup=this._FlowView._SVGHelperProvider.createSVGElement('g');tmpContentGroup.setAttribute('class','pict-flow-node-body-content');tmpContentGroup.setAttribute('transform',"translate(".concat(pBounds.x,", ").concat(pBounds.y,")"));// Render template content
2292
+ var tmpRenderedContent=this._resolveBodyTemplate(pBodyContent,pNodeData,pPict);if(tmpRenderedContent){// Parse SVG markup into the group via a temporary SVG element
2293
+ var tmpTempSVG=document.createElementNS('http://www.w3.org/2000/svg','svg');tmpTempSVG.innerHTML=tmpRenderedContent;while(tmpTempSVG.firstChild){tmpContentGroup.appendChild(tmpTempSVG.firstChild);}}// Invoke render callback if provided
2294
+ if(typeof pBodyContent.RenderCallback==='function'){pBodyContent.RenderCallback(tmpContentGroup,pNodeData,pNodeTypeConfig,pBounds);}pGroup.appendChild(tmpContentGroup);}/**
2295
+ * Render HTML body content into a foreignObject.
2296
+ */},{key:"_renderBodyContentHTML",value:function _renderBodyContentHTML(pNodeData,pGroup,pBodyContent,pBounds,pNodeTypeConfig,pPict){var tmpFO=this._FlowView._SVGHelperProvider.createSVGElement('foreignObject');tmpFO.setAttribute('class','pict-flow-node-body-content-fo');tmpFO.setAttribute('x',String(pBounds.x));tmpFO.setAttribute('y',String(pBounds.y));tmpFO.setAttribute('width',String(pBounds.width));tmpFO.setAttribute('height',String(pBounds.height));var tmpDiv=document.createElement('div');tmpDiv.setAttribute('xmlns','http://www.w3.org/1999/xhtml');tmpDiv.setAttribute('class','pict-flow-node-body-content-html');// Pointer event isolation — prevent node drag/canvas pan
2297
+ tmpDiv.addEventListener('pointerdown',function(pEvent){pEvent.stopPropagation();});tmpDiv.addEventListener('wheel',function(pEvent){pEvent.stopPropagation();});// Render template content
2298
+ var tmpRenderedContent=this._resolveBodyTemplate(pBodyContent,pNodeData,pPict);if(tmpRenderedContent){tmpDiv.innerHTML=tmpRenderedContent;}// Invoke render callback if provided
2299
+ if(typeof pBodyContent.RenderCallback==='function'){pBodyContent.RenderCallback(tmpDiv,pNodeData,pNodeTypeConfig,pBounds);}tmpFO.appendChild(tmpDiv);pGroup.appendChild(tmpFO);}/**
2300
+ * Render canvas body content into a foreignObject.
2301
+ */},{key:"_renderBodyContentCanvas",value:function _renderBodyContentCanvas(pNodeData,pGroup,pBodyContent,pBounds,pNodeTypeConfig){var tmpFO=this._FlowView._SVGHelperProvider.createSVGElement('foreignObject');tmpFO.setAttribute('class','pict-flow-node-body-content-fo');tmpFO.setAttribute('x',String(pBounds.x));tmpFO.setAttribute('y',String(pBounds.y));tmpFO.setAttribute('width',String(pBounds.width));tmpFO.setAttribute('height',String(pBounds.height));var tmpCanvas=document.createElement('canvas');tmpCanvas.setAttribute('xmlns','http://www.w3.org/1999/xhtml');tmpCanvas.setAttribute('class','pict-flow-node-body-content-canvas');tmpCanvas.width=Math.floor(pBounds.width);tmpCanvas.height=Math.floor(pBounds.height);tmpCanvas.style.width='100%';tmpCanvas.style.height='100%';// Pointer event isolation
2302
+ tmpCanvas.addEventListener('pointerdown',function(pEvent){pEvent.stopPropagation();});tmpCanvas.addEventListener('wheel',function(pEvent){pEvent.stopPropagation();});// Invoke render callback (the primary rendering path for canvas)
2303
+ if(typeof pBodyContent.RenderCallback==='function'){pBodyContent.RenderCallback(tmpCanvas,pNodeData,pNodeTypeConfig,pBounds);}tmpFO.appendChild(tmpCanvas);pGroup.appendChild(tmpFO);}/**
2304
+ * Resolve and render a body content template string.
2305
+ * @param {Object} pBodyContent - The BodyContent config
2306
+ * @param {Object} pNodeData - The node data (template record)
2307
+ * @param {Object} pPict - The Pict instance
2308
+ * @returns {string|null} Rendered template content, or null
2309
+ */},{key:"_resolveBodyTemplate",value:function _resolveBodyTemplate(pBodyContent,pNodeData,pPict){if(pBodyContent.TemplateHash){return pPict.parseTemplateByHash(pBodyContent.TemplateHash,pNodeData);}if(pBodyContent.Template){return pPict.parseTemplate(pBodyContent.Template,pNodeData,null,[pNodeData]);}return null;}// ── Node Body Renderers ──────────────────────────────────────────────
2310
+ /**
2311
+ * Render the standard rect-based node body (default mode).
2312
+ * @param {SVGGElement} pGroup
2313
+ * @param {Object} pNodeData
2314
+ * @param {number} pWidth
2315
+ * @param {number} pHeight
2316
+ * @param {number} pTitleBarHeight
2317
+ * @param {Object} pNodeTypeConfig
2318
+ */},{key:"_renderRectNodeBody",value:function _renderRectNodeBody(pGroup,pNodeData,pWidth,pHeight,pTitleBarHeight,pNodeTypeConfig){// Node body (main rectangle)
2319
+ var tmpBody=this._FlowView._SVGHelperProvider.createSVGElement('rect');tmpBody.setAttribute('class','pict-flow-node-body');tmpBody.setAttribute('x','0');tmpBody.setAttribute('y','0');tmpBody.setAttribute('width',String(pWidth));tmpBody.setAttribute('height',String(pHeight));tmpBody.setAttribute('data-node-hash',pNodeData.Hash);tmpBody.setAttribute('data-element-type','node-body');// Apply custom styles from node type
2320
+ if(pNodeTypeConfig&&pNodeTypeConfig.BodyStyle){for(var tmpStyleKey in pNodeTypeConfig.BodyStyle){tmpBody.setAttribute(tmpStyleKey,pNodeTypeConfig.BodyStyle[tmpStyleKey]);}}// Apply per-instance style overrides (for node-specific editing)
2321
+ // These must be applied as inline styles so they override CSS rules
2322
+ // (CSS declarations take precedence over SVG presentation attributes).
2323
+ if(pNodeData.Style){var tmpInlineStyles=[];if(pNodeData.Style.BodyFill)tmpInlineStyles.push('fill:'+pNodeData.Style.BodyFill);if(pNodeData.Style.BodyStroke)tmpInlineStyles.push('stroke:'+pNodeData.Style.BodyStroke);if(pNodeData.Style.BodyStrokeWidth)tmpInlineStyles.push('stroke-width:'+pNodeData.Style.BodyStrokeWidth);if(tmpInlineStyles.length>0){tmpBody.setAttribute('style',tmpInlineStyles.join(';'));}}pGroup.appendChild(tmpBody);// Title bar background (top portion)
2324
+ var tmpTitleBar=this._FlowView._SVGHelperProvider.createSVGElement('rect');tmpTitleBar.setAttribute('class','pict-flow-node-title-bar');tmpTitleBar.setAttribute('x','0');tmpTitleBar.setAttribute('y','0');tmpTitleBar.setAttribute('width',String(pWidth));tmpTitleBar.setAttribute('height',String(pTitleBarHeight));tmpTitleBar.setAttribute('data-node-hash',pNodeData.Hash);tmpTitleBar.setAttribute('data-element-type','node-body');// Apply custom title bar color
2325
+ if(pNodeTypeConfig&&pNodeTypeConfig.TitleBarColor){tmpTitleBar.setAttribute('fill',pNodeTypeConfig.TitleBarColor);}pGroup.appendChild(tmpTitleBar);// Title bar bottom fill (to square off the rounded corners at the bottom of the title bar)
2326
+ var tmpTitleBarBottom=this._FlowView._SVGHelperProvider.createSVGElement('rect');tmpTitleBarBottom.setAttribute('class','pict-flow-node-title-bar-bottom');tmpTitleBarBottom.setAttribute('x','0');tmpTitleBarBottom.setAttribute('y',String(pTitleBarHeight-8));tmpTitleBarBottom.setAttribute('width',String(pWidth));tmpTitleBarBottom.setAttribute('height','8');tmpTitleBarBottom.setAttribute('data-node-hash',pNodeData.Hash);tmpTitleBarBottom.setAttribute('data-element-type','node-body');if(pNodeTypeConfig&&pNodeTypeConfig.TitleBarColor){tmpTitleBarBottom.setAttribute('fill',pNodeTypeConfig.TitleBarColor);}// Per-instance title bar color override
2327
+ // Applied as inline style to override CSS rules.
2328
+ if(pNodeData.Style&&pNodeData.Style.TitleBarColor){tmpTitleBar.setAttribute('style','fill:'+pNodeData.Style.TitleBarColor);tmpTitleBarBottom.setAttribute('style','fill:'+pNodeData.Style.TitleBarColor);}pGroup.appendChild(tmpTitleBarBottom);}/**
2329
+ * Render a bracket-style node body (used by sketch/blueprint themes).
2330
+ *
2331
+ * The bracket body consists of:
2332
+ * 1. A fill rect for the body background (no stroke)
2333
+ * 2. A fill rect for the title bar background (no stroke)
2334
+ * 3. A bracket path drawn via the noise provider (outline + title divider)
2335
+ *
2336
+ * @param {SVGGElement} pGroup
2337
+ * @param {Object} pNodeData
2338
+ * @param {number} pWidth
2339
+ * @param {number} pHeight
2340
+ * @param {number} pTitleBarHeight
2341
+ * @param {Object} pNodeTypeConfig
2342
+ */},{key:"_renderBracketNodeBody",value:function _renderBracketNodeBody(pGroup,pNodeData,pWidth,pHeight,pTitleBarHeight,pNodeTypeConfig){// 1. Body fill rect (background only, no stroke)
2343
+ var tmpBodyFill=this._FlowView._SVGHelperProvider.createSVGElement('rect');tmpBodyFill.setAttribute('class','pict-flow-node-body pict-flow-node-bracket-fill');tmpBodyFill.setAttribute('x','0');tmpBodyFill.setAttribute('y','0');tmpBodyFill.setAttribute('width',String(pWidth));tmpBodyFill.setAttribute('height',String(pHeight));tmpBodyFill.setAttribute('data-node-hash',pNodeData.Hash);tmpBodyFill.setAttribute('data-element-type','node-body');// Per-instance style overrides
2344
+ if(pNodeData.Style){var tmpInlineStyles=[];if(pNodeData.Style.BodyFill)tmpInlineStyles.push('fill:'+pNodeData.Style.BodyFill);if(tmpInlineStyles.length>0){tmpBodyFill.setAttribute('style',tmpInlineStyles.join(';'));}}pGroup.appendChild(tmpBodyFill);// 2. Title bar fill rect (background only, no stroke)
2345
+ var tmpTitleFill=this._FlowView._SVGHelperProvider.createSVGElement('rect');tmpTitleFill.setAttribute('class','pict-flow-node-title-bar pict-flow-node-bracket-title-fill');tmpTitleFill.setAttribute('x','0');tmpTitleFill.setAttribute('y','0');tmpTitleFill.setAttribute('width',String(pWidth));tmpTitleFill.setAttribute('height',String(pTitleBarHeight));tmpTitleFill.setAttribute('data-node-hash',pNodeData.Hash);tmpTitleFill.setAttribute('data-element-type','node-body');if(pNodeTypeConfig&&pNodeTypeConfig.TitleBarColor){tmpTitleFill.setAttribute('style','fill:'+pNodeTypeConfig.TitleBarColor);}if(pNodeData.Style&&pNodeData.Style.TitleBarColor){tmpTitleFill.setAttribute('style','fill:'+pNodeData.Style.TitleBarColor);}pGroup.appendChild(tmpTitleFill);// 3. Bracket path (outline + title divider with optional noise)
2346
+ var tmpBracketConfig={SerifLength:6,TitleSeparator:true};if(this._FlowView._ThemeProvider){var tmpActiveTheme=this._FlowView._ThemeProvider.getActiveTheme();if(tmpActiveTheme&&tmpActiveTheme.BracketConfig){tmpBracketConfig=Object.assign(tmpBracketConfig,tmpActiveTheme.BracketConfig);}}var tmpAmplitude=0;if(this._FlowView._ThemeProvider){tmpAmplitude=this._FlowView._ThemeProvider.getNodeNoiseAmplitude();}var tmpBracketD='';if(this._FlowView._NoiseProvider){tmpBracketD=this._FlowView._NoiseProvider.generateBracketPath(pWidth,pHeight,tmpBracketConfig.SerifLength,tmpBracketConfig.TitleSeparator?pTitleBarHeight:0,tmpAmplitude,pNodeData.Hash);}var tmpBracketPath=this._FlowView._SVGHelperProvider.createSVGElement('path');tmpBracketPath.setAttribute('class','pict-flow-node-bracket');tmpBracketPath.setAttribute('d',tmpBracketD);tmpBracketPath.setAttribute('data-node-hash',pNodeData.Hash);tmpBracketPath.setAttribute('data-element-type','node-body');// Per-instance stroke overrides
2347
+ if(pNodeData.Style){var _tmpInlineStyles=[];if(pNodeData.Style.BodyStroke)_tmpInlineStyles.push('stroke:'+pNodeData.Style.BodyStroke);if(pNodeData.Style.BodyStrokeWidth)_tmpInlineStyles.push('stroke-width:'+pNodeData.Style.BodyStrokeWidth);if(_tmpInlineStyles.length>0){tmpBracketPath.setAttribute('style',_tmpInlineStyles.join(';'));}}pGroup.appendChild(tmpBracketPath);}}]);}(libPictView);module.exports=PictViewFlowNode;module.exports.default_configuration=_DefaultConfiguration;},{"pict-view":45}],41:[function(require,module,exports){var libPictView=require('pict-view');var _DefaultConfiguration={ViewIdentifier:'Flow-PropertiesPanel',AutoRender:false,Templates:[{Hash:'Flow-InfoPanel-Wrapper',Template:'<div class="pict-flow-info-panel">{~D:Record.PanelContent~}</div>'},{Hash:'Flow-InfoPanel-Header-Icon',Template:'<div class="pict-flow-info-panel-header with-icon">{~D:Record.Icon~} {~D:Record.Label~}</div>'},{Hash:'Flow-InfoPanel-Header',Template:'<div class="pict-flow-info-panel-header">{~D:Record.Label~}</div>'},{Hash:'Flow-InfoPanel-Description',Template:'<div class="pict-flow-info-panel-description">{~D:Record.Description~}</div>'},{Hash:'Flow-InfoPanel-Badges',Template:'<div class="pict-flow-info-panel-badges">{~D:Record.BadgesContent~}</div>'},{Hash:'Flow-InfoPanel-Badge-Category',Template:'<span class="pict-flow-info-panel-badge category">{~D:Record.Category~}</span>'},{Hash:'Flow-InfoPanel-Badge-Code',Template:'<span class="pict-flow-info-panel-badge code">{~D:Record.Code~}</span>'},{Hash:'Flow-InfoPanel-Section-Inputs',Template:'<div class="pict-flow-info-panel-section"><div class="pict-flow-info-panel-section-title">Inputs</div>{~D:Record.PortsContent~}</div>'},{Hash:'Flow-InfoPanel-Section-Outputs',Template:'<div class="pict-flow-info-panel-section"><div class="pict-flow-info-panel-section-title">Outputs</div>{~D:Record.PortsContent~}</div>'},{Hash:'Flow-InfoPanel-Port-Input',Template:'<div class="pict-flow-info-panel-port input">{~D:Record.Label~}{~D:Record.Constraint~}</div>'},{Hash:'Flow-InfoPanel-Port-Output',Template:'<div class="pict-flow-info-panel-port output">{~D:Record.Label~}</div>'},{Hash:'Flow-InfoPanel-Port-Constraint',Template:' <span class="pict-flow-info-panel-port-constraint">{~D:Record.ConstraintText~}</span>'},{Hash:'Flow-InfoPanel-Section-Generic',Template:'<div class="pict-flow-info-panel-section"><div class="pict-flow-info-panel-section-title">{~D:Record.SectionTitle~}</div>{~D:Record.PortsContent~}</div>'},{Hash:'Flow-InfoPanel-Port-Event',Template:'<div class="pict-flow-info-panel-port event">{~D:Record.Label~}</div>'},{Hash:'Flow-InfoPanel-Port-Value',Template:'<div class="pict-flow-info-panel-port value">{~D:Record.Label~}{~D:Record.DataType~}</div>'},{Hash:'Flow-InfoPanel-Port-DataType',Template:' <span class="pict-flow-info-panel-port-constraint">{~D:Record.DataTypeText~}</span>'},{Hash:'Flow-NodeProps-Editor',Template:'<div class="pict-flow-node-props-fields"><div class="pict-flow-node-props-field"><label class="pict-flow-node-props-label">Title</label><input type="text" class="pict-flow-node-props-input" data-prop="Title" value="{~D:Record.Title~}" /></div><div class="pict-flow-node-props-field"><label class="pict-flow-node-props-label">Width</label><input type="number" class="pict-flow-node-props-input" data-prop="Width" value="{~D:Record.Width~}" min="60" step="10" /></div><div class="pict-flow-node-props-field"><label class="pict-flow-node-props-label">Height</label><input type="number" class="pict-flow-node-props-input" data-prop="Height" value="{~D:Record.Height~}" min="40" step="10" /></div><div class="pict-flow-node-props-field"><label class="pict-flow-node-props-label">Body Fill</label><input type="color" class="pict-flow-node-props-input pict-flow-node-props-color" data-prop="Style.BodyFill" value="{~D:Record.BodyFillValue~}" /></div><div class="pict-flow-node-props-field"><label class="pict-flow-node-props-label">Body Stroke</label><input type="color" class="pict-flow-node-props-input pict-flow-node-props-color" data-prop="Style.BodyStroke" value="{~D:Record.BodyStrokeValue~}" /></div><div class="pict-flow-node-props-field"><label class="pict-flow-node-props-label">Stroke Width</label><input type="number" class="pict-flow-node-props-input" data-prop="Style.BodyStrokeWidth" value="{~D:Record.BodyStrokeWidthValue~}" min="0" max="10" step="0.5" /></div><div class="pict-flow-node-props-field"><label class="pict-flow-node-props-label">Title Bar</label><input type="color" class="pict-flow-node-props-input pict-flow-node-props-color" data-prop="Style.TitleBarColor" value="{~D:Record.TitleBarColorValue~}" /></div></div>'}]};/**
2348
+ * PictView-Flow-PropertiesPanel
2349
+ *
2350
+ * Renders and manages all open properties panels on the flow graph.
2351
+ * Panels are SVG foreignObject elements containing HTML, placed inside
2352
+ * the viewport group so they zoom/pan with the graph.
2353
+ *
2354
+ * Responsibilities:
2355
+ * - Reconcile DOM (add new panels, remove closed ones, update positions)
2356
+ * - Render tether lines from each panel to its node
2357
+ * - Manage panel instance cache (PictFlowCardPropertiesPanel subclasses)
2358
+ * - Isolate HTML events from SVG interactions
2359
+ */var PictViewFlowPropertiesPanel=/*#__PURE__*/function(_libPictView3){function PictViewFlowPropertiesPanel(pFable,pOptions,pServiceHash){var _this55;_classCallCheck(this,PictViewFlowPropertiesPanel);var tmpOptions=Object.assign({},JSON.parse(JSON.stringify(_DefaultConfiguration)),pOptions);_this55=_callSuper(this,PictViewFlowPropertiesPanel,[pFable,tmpOptions,pServiceHash]);_this55.serviceType='PictViewFlowPropertiesPanel';_this55._FlowView=null;// Cache of active panel instances: Map<panelHash, PictFlowCardPropertiesPanel>
2360
+ _this55._PanelInstances={};return _this55;}/**
2361
+ * Render all open panels and their tethers.
2362
+ *
2363
+ * Uses DOM reconciliation for panels (to preserve live HTML state)
2364
+ * and clear-and-rebuild for tethers (trivial SVG lines).
2365
+ *
2366
+ * @param {Array} pOpenPanels - Array of panel data objects from _FlowData.OpenPanels
2367
+ * @param {SVGGElement} pPanelsLayer - The SVG <g> for panel foreignObjects
2368
+ * @param {SVGGElement} pTethersLayer - The SVG <g> for tether lines
2369
+ * @param {string|null} pSelectedTetherHash - Hash of the selected tether's panel, or null
2370
+ */_inherits(PictViewFlowPropertiesPanel,_libPictView3);return _createClass(PictViewFlowPropertiesPanel,[{key:"renderPanels",value:function renderPanels(pOpenPanels,pPanelsLayer,pTethersLayer,pSelectedTetherHash){if(!pPanelsLayer||!pTethersLayer)return;if(!this._FlowView)return;var tmpOpenPanels=Array.isArray(pOpenPanels)?pOpenPanels:[];// --- Reconcile panels layer (add new, remove closed, update positions) ---
2371
+ var tmpExistingPanelHashes=new Set();var tmpExistingForeignObjects=pPanelsLayer.querySelectorAll('.pict-flow-panel-foreign-object');for(var i=0;i<tmpExistingForeignObjects.length;i++){tmpExistingPanelHashes.add(tmpExistingForeignObjects[i].getAttribute('data-panel-hash'));}var tmpDesiredPanelHashes=new Set();for(var _i47=0;_i47<tmpOpenPanels.length;_i47++){tmpDesiredPanelHashes.add(tmpOpenPanels[_i47].Hash);}// Remove panels that are no longer open
2372
+ for(var _i48=0;_i48<tmpExistingForeignObjects.length;_i48++){var tmpHash=tmpExistingForeignObjects[_i48].getAttribute('data-panel-hash');if(!tmpDesiredPanelHashes.has(tmpHash)){tmpExistingForeignObjects[_i48].remove();// Destroy cached instance
2373
+ if(this._PanelInstances[tmpHash]){this._PanelInstances[tmpHash].destroy();delete this._PanelInstances[tmpHash];}}}// Add or update panels
2374
+ for(var _i49=0;_i49<tmpOpenPanels.length;_i49++){var tmpPanelData=tmpOpenPanels[_i49];if(tmpExistingPanelHashes.has(tmpPanelData.Hash)){// Update position of existing panel
2375
+ var tmpFO=pPanelsLayer.querySelector("[data-panel-hash=\"".concat(tmpPanelData.Hash,"\"]"));if(tmpFO){tmpFO.setAttribute('x',String(tmpPanelData.X));tmpFO.setAttribute('y',String(tmpPanelData.Y));tmpFO.setAttribute('width',String(tmpPanelData.Width));tmpFO.setAttribute('height',String(tmpPanelData.Height));}}else{// Create new panel
2376
+ this._createPanelForeignObject(tmpPanelData,pPanelsLayer);}}// --- Clear and rebuild tethers ---
2377
+ while(pTethersLayer.firstChild){pTethersLayer.removeChild(pTethersLayer.firstChild);}for(var _i50=0;_i50<tmpOpenPanels.length;_i50++){var tmpIsSelected=pSelectedTetherHash===tmpOpenPanels[_i50].Hash;this._renderTether(tmpOpenPanels[_i50],pTethersLayer,tmpIsSelected);}}/**
2378
+ * Create a foreignObject containing the panel chrome and content.
2379
+ * Delegates to the PanelChrome provider for template-based chrome creation,
2380
+ * then renders panel content into the body container.
2381
+ *
2382
+ * @param {Object} pPanelData - Panel data from OpenPanels
2383
+ * @param {SVGGElement} pPanelsLayer
2384
+ */},{key:"_createPanelForeignObject",value:function _createPanelForeignObject(pPanelData,pPanelsLayer){var tmpPanelChromeProvider=this._FlowView._PanelChromeProvider;if(!tmpPanelChromeProvider)return;var tmpBody=tmpPanelChromeProvider.createPanelForeignObject(pPanelData,pPanelsLayer);// Render the panel content into the Properties tab pane
2385
+ if(tmpBody){this._renderPanelContent(pPanelData,tmpBody);}var tmpFO=pPanelsLayer.querySelector("[data-panel-hash=\"".concat(pPanelData.Hash,"\"]"));if(tmpFO){// Render appearance and help tabs
2386
+ this._renderAppearanceTab(pPanelData,tmpFO);this._renderHelpTab(pPanelData,tmpFO);// Wire up tab switching
2387
+ this._wireTabSwitching(tmpFO);}}/**
2388
+ * Instantiate (or reuse) the panel type implementation and render into the body container.
2389
+ *
2390
+ * @param {Object} pPanelData
2391
+ * @param {HTMLDivElement} pBodyContainer
2392
+ */},{key:"_renderPanelContent",value:function _renderPanelContent(pPanelData,pBodyContainer){var tmpNodeData=this._FlowView.getNode(pPanelData.NodeHash);if(!tmpNodeData)return;var tmpNodeTypeConfig=this._FlowView._NodeTypeProvider.getNodeType(tmpNodeData.Type);if(!tmpNodeTypeConfig)return;// If no PropertiesPanel is configured, render the auto-generated info panel
2393
+ if(!tmpNodeTypeConfig.PropertiesPanel){this._renderInfoPanelContent(pBodyContainer,tmpNodeData,tmpNodeTypeConfig);return;}var tmpPanelConfig=tmpNodeTypeConfig.PropertiesPanel;var tmpPanelType=tmpPanelConfig.PanelType||'Base';// Try to get a registered panel type service
2394
+ var tmpServiceName="PictFlowCardPropertiesPanel-".concat(tmpPanelType);var tmpInstance=null;if(this._PanelInstances[pPanelData.Hash]){// Reuse existing instance
2395
+ tmpInstance=this._PanelInstances[pPanelData.Hash];}else{// Create a new instance
2396
+ if(this.fable.servicesMap.hasOwnProperty(tmpServiceName)){tmpInstance=this.fable.instantiateServiceProviderWithoutRegistration(tmpServiceName,tmpPanelConfig);}else if(this.fable.servicesMap.hasOwnProperty('PictFlowCardPropertiesPanel')){// Fall back to base class
2397
+ tmpInstance=this.fable.instantiateServiceProviderWithoutRegistration('PictFlowCardPropertiesPanel',tmpPanelConfig);}if(tmpInstance){tmpInstance._FlowView=this._FlowView;this._PanelInstances[pPanelData.Hash]=tmpInstance;}}if(tmpInstance){tmpInstance.render(pBodyContainer,tmpNodeData);}// After the form renders, append port summary sections showing
2398
+ // event inputs, event outputs, and state outputs.
2399
+ // SettingsInputs are already visible as form fields above.
2400
+ this._renderPortSummary(pBodyContainer,tmpNodeTypeConfig);}/**
2401
+ * Render an auto-generated info panel for nodes without a configured PropertiesPanel.
2402
+ * Shows the node type, description, and a summary of input/output ports with
2403
+ * their connection constraints.
2404
+ *
2405
+ * Uses configuration-based templates from _DefaultConfiguration.Templates
2406
+ * rendered via pict.parseTemplateByHash().
2407
+ *
2408
+ * @param {HTMLDivElement} pContainer
2409
+ * @param {Object} pNodeData
2410
+ * @param {Object} pNodeTypeConfig
2411
+ */},{key:"_renderInfoPanelContent",value:function _renderInfoPanelContent(pContainer,pNodeData,pNodeTypeConfig){var tmpMeta=pNodeTypeConfig.CardMetadata||{};var tmpPorts=pNodeTypeConfig.DefaultPorts||[];var tmpInputs=tmpPorts.filter(function(pPort){return pPort.Direction==='input';});var tmpOutputs=tmpPorts.filter(function(pPort){return pPort.Direction==='output';});var tmpLabel=pNodeTypeConfig.Label||pNodeData.Type;// Build content by rendering configuration-based templates
2412
+ var tmpContentParts=[];// Header
2413
+ var tmpIconProvider=this._FlowView._IconProvider;if(tmpMeta.Icon&&tmpIconProvider&&!tmpIconProvider.isEmojiIcon(tmpMeta.Icon)){// SVG icon markup for the header
2414
+ var tmpResolvedKey=tmpIconProvider.resolveIconKey(tmpMeta);var tmpIconMarkup=tmpIconProvider.getIconSVGMarkup(tmpResolvedKey,18);tmpContentParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Header-Icon',{Icon:tmpIconMarkup,Label:tmpLabel}));}else if(tmpMeta.Icon){tmpContentParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Header-Icon',{Icon:tmpMeta.Icon,Label:tmpLabel}));}else if(tmpIconProvider){// No icon specified — render default fallback
2415
+ var tmpDefaultMarkup=tmpIconProvider.getIconSVGMarkup('default',18);tmpContentParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Header-Icon',{Icon:tmpDefaultMarkup,Label:tmpLabel}));}else{tmpContentParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Header',{Label:tmpLabel}));}// Description
2416
+ if(tmpMeta.Description){tmpContentParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Description',{Description:tmpMeta.Description}));}// Category + Code badges
2417
+ if(tmpMeta.Category||tmpMeta.Code){var tmpBadgesContent='';if(tmpMeta.Category){tmpBadgesContent+=this.pict.parseTemplateByHash('Flow-InfoPanel-Badge-Category',{Category:tmpMeta.Category});}if(tmpMeta.Code){tmpBadgesContent+=this.pict.parseTemplateByHash('Flow-InfoPanel-Badge-Code',{Code:tmpMeta.Code});}tmpContentParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Badges',{BadgesContent:tmpBadgesContent}));}// Inputs
2418
+ if(tmpInputs.length>0){var tmpPortsContent='';for(var i=0;i<tmpInputs.length;i++){var tmpPort=tmpInputs[i];var tmpConstraint=this._getPortConstraintHTML(tmpPort);tmpPortsContent+=this.pict.parseTemplateByHash('Flow-InfoPanel-Port-Input',{Label:tmpPort.Label||'In',Constraint:tmpConstraint});}tmpContentParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Section-Inputs',{PortsContent:tmpPortsContent}));}// Outputs
2419
+ if(tmpOutputs.length>0){var _tmpPortsContent='';for(var _i51=0;_i51<tmpOutputs.length;_i51++){var _tmpPort2=tmpOutputs[_i51];_tmpPortsContent+=this.pict.parseTemplateByHash('Flow-InfoPanel-Port-Output',{Label:_tmpPort2.Label||'Out'});}tmpContentParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Section-Outputs',{PortsContent:_tmpPortsContent}));}pContainer.innerHTML=this.pict.parseTemplateByHash('Flow-InfoPanel-Wrapper',{PanelContent:tmpContentParts.join('')});}/**
2420
+ * Render port summary sections below the form panel content.
2421
+ * Shows event inputs, event outputs, and state outputs — the ports
2422
+ * that the form does not cover (since the form only shows SettingsInputs).
2423
+ *
2424
+ * @param {HTMLDivElement} pContainer
2425
+ * @param {Object} pNodeTypeConfig
2426
+ */},{key:"_renderPortSummary",value:function _renderPortSummary(pContainer,pNodeTypeConfig){var tmpPorts=pNodeTypeConfig.DefaultPorts||[];if(tmpPorts.length===0)return;// Categorize ports by type (settings are already shown as form fields)
2427
+ var tmpEventInputs=[];var tmpEventOutputs=[];var tmpStateOutputs=[];for(var i=0;i<tmpPorts.length;i++){var tmpPort=tmpPorts[i];var tmpPortType=tmpPort.PortType||'';if(tmpPortType==='event-in'){tmpEventInputs.push(tmpPort);}else if(tmpPortType==='event-out'||tmpPortType==='error'){tmpEventOutputs.push(tmpPort);}else if(tmpPortType==='value'){tmpStateOutputs.push(tmpPort);}}// Only render if there are non-settings ports to show
2428
+ if(tmpEventInputs.length===0&&tmpEventOutputs.length===0&&tmpStateOutputs.length===0){return;}var tmpSummaryParts=[];// Event Inputs
2429
+ if(tmpEventInputs.length>0){var tmpPortsContent='';for(var _i52=0;_i52<tmpEventInputs.length;_i52++){tmpPortsContent+=this.pict.parseTemplateByHash('Flow-InfoPanel-Port-Event',{Label:tmpEventInputs[_i52].Label||tmpEventInputs[_i52].Name||'Event In'});}tmpSummaryParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Section-Generic',{SectionTitle:'Event Inputs',PortsContent:tmpPortsContent}));}// Event Outputs
2430
+ if(tmpEventOutputs.length>0){var _tmpPortsContent2='';for(var _i53=0;_i53<tmpEventOutputs.length;_i53++){var _tmpPort3=tmpEventOutputs[_i53];var tmpLabel=_tmpPort3.Label||_tmpPort3.Name||'Event Out';if(_tmpPort3.PortType==='error'){tmpLabel+=' ⚠';}_tmpPortsContent2+=this.pict.parseTemplateByHash('Flow-InfoPanel-Port-Event',{Label:tmpLabel});}tmpSummaryParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Section-Generic',{SectionTitle:'Event Outputs',PortsContent:_tmpPortsContent2}));}// State Outputs
2431
+ if(tmpStateOutputs.length>0){var _tmpPortsContent3='';for(var _i54=0;_i54<tmpStateOutputs.length;_i54++){var _tmpPort4=tmpStateOutputs[_i54];var _tmpLabel=_tmpPort4.Label||_tmpPort4.Name||'Output';var tmpDataType='';if(_tmpPort4.DataType){tmpDataType=this.pict.parseTemplateByHash('Flow-InfoPanel-Port-DataType',{DataTypeText:_tmpPort4.DataType});}_tmpPortsContent3+=this.pict.parseTemplateByHash('Flow-InfoPanel-Port-Value',{Label:_tmpLabel,DataType:tmpDataType});}tmpSummaryParts.push(this.pict.parseTemplateByHash('Flow-InfoPanel-Section-Generic',{SectionTitle:'State Outputs',PortsContent:_tmpPortsContent3}));}if(tmpSummaryParts.length>0){// Create a wrapper div for the port summary and append it to the container
2432
+ var tmpSummaryDiv=document.createElement('div');tmpSummaryDiv.className='pict-flow-info-panel pict-flow-port-summary';tmpSummaryDiv.innerHTML=tmpSummaryParts.join('');pContainer.appendChild(tmpSummaryDiv);}}/**
2433
+ * Build the constraint markup for a port using configuration templates.
2434
+ *
2435
+ * @param {Object} pPort
2436
+ * @returns {string} Rendered constraint HTML or empty string
2437
+ */},{key:"_getPortConstraintHTML",value:function _getPortConstraintHTML(pPort){var tmpMin=typeof pPort.MinimumInputCount==='number'?pPort.MinimumInputCount:0;var tmpMax=typeof pPort.MaximumInputCount==='number'?pPort.MaximumInputCount:-1;if(tmpMin>0||tmpMax>0){var tmpConstraintText='';if(tmpMax<0){tmpConstraintText="(min ".concat(tmpMin,")");}else if(tmpMin===tmpMax){tmpConstraintText="(exactly ".concat(tmpMin,")");}else{tmpConstraintText="(".concat(tmpMin,"\u2013").concat(tmpMax,")");}return this.pict.parseTemplateByHash('Flow-InfoPanel-Port-Constraint',{ConstraintText:tmpConstraintText});}return'';}/**
2438
+ * Render the Appearance tab content with node property editor fields.
2439
+ *
2440
+ * @param {Object} pPanelData - Panel data from OpenPanels
2441
+ * @param {Element} pForeignObject - The panel's SVG foreignObject element
2442
+ */},{key:"_renderAppearanceTab",value:function _renderAppearanceTab(pPanelData,pForeignObject){var _this56=this;var tmpNodeData=this._FlowView.getNode(pPanelData.NodeHash);if(!tmpNodeData)return;var tmpAppearancePane=pForeignObject.querySelector('.pict-flow-panel-tab-pane[data-tab="appearance"]');if(!tmpAppearancePane)return;// Build the template record with safe defaults for Style values
2443
+ var tmpStyle=tmpNodeData.Style||{};// Resolve default colors from the node type config or CSS token defaults
2444
+ var tmpNodeTypeConfig=this._FlowView._NodeTypeProvider.getNodeType(tmpNodeData.Type);var tmpDefaultTitleBarColor='#2c3e50';var tmpDefaultBodyFill='#ffffff';var tmpDefaultBodyStroke='#d0d4d8';if(tmpNodeTypeConfig){if(tmpNodeTypeConfig.TitleBarColor)tmpDefaultTitleBarColor=tmpNodeTypeConfig.TitleBarColor;if(tmpNodeTypeConfig.BodyStyle){if(tmpNodeTypeConfig.BodyStyle.fill)tmpDefaultBodyFill=tmpNodeTypeConfig.BodyStyle.fill;if(tmpNodeTypeConfig.BodyStyle.stroke)tmpDefaultBodyStroke=tmpNodeTypeConfig.BodyStyle.stroke;}}var tmpRecord={Title:tmpNodeData.Title||'',Width:tmpNodeData.Width||180,Height:tmpNodeData.Height||80,BodyFillValue:tmpStyle.BodyFill||tmpDefaultBodyFill,BodyStrokeValue:tmpStyle.BodyStroke||tmpDefaultBodyStroke,BodyStrokeWidthValue:tmpStyle.BodyStrokeWidth||1,TitleBarColorValue:tmpStyle.TitleBarColor||tmpDefaultTitleBarColor};tmpAppearancePane.innerHTML=this.pict.parseTemplateByHash('Flow-NodeProps-Editor',tmpRecord);// Wire up live change handlers on all input fields
2445
+ var tmpInputs=tmpAppearancePane.querySelectorAll('.pict-flow-node-props-input');var _loop=function _loop(){var tmpInput=tmpInputs[i];var tmpProp=tmpInput.getAttribute('data-prop');tmpInput.addEventListener('input',function(pEvent){pEvent.stopPropagation();_this56._applyNodePropChange(pPanelData.NodeHash,tmpProp,tmpInput.value,tmpInput.type);});// Prevent pointer events from propagating to SVG drag handler
2446
+ tmpInput.addEventListener('pointerdown',function(pEvent){pEvent.stopPropagation();});};for(var i=0;i<tmpInputs.length;i++){_loop();}}/**
2447
+ * Render the Help tab content if help text is defined on the node type.
2448
+ * Shows the Help tab button only when help content is available.
2449
+ *
2450
+ * @param {Object} pPanelData - Panel data from OpenPanels
2451
+ * @param {Element} pForeignObject - The panel's SVG foreignObject element
2452
+ */},{key:"_renderHelpTab",value:function _renderHelpTab(pPanelData,pForeignObject){var tmpNodeData=this._FlowView.getNode(pPanelData.NodeHash);if(!tmpNodeData)return;var tmpNodeTypeConfig=this._FlowView._NodeTypeProvider.getNodeType(tmpNodeData.Type);if(!tmpNodeTypeConfig)return;var tmpHelpText=tmpNodeTypeConfig.CardMetadata&&tmpNodeTypeConfig.CardMetadata.Help?tmpNodeTypeConfig.CardMetadata.Help:null;if(!tmpHelpText)return;// Show the Help tab button
2453
+ var tmpHelpTabButton=pForeignObject.querySelector('.pict-flow-panel-tab[data-tab-target="help"]');if(tmpHelpTabButton){tmpHelpTabButton.style.display='';}// Render help content into the help pane
2454
+ var tmpHelpPane=pForeignObject.querySelector('.pict-flow-panel-tab-pane[data-tab="help"]');if(tmpHelpPane){tmpHelpPane.innerHTML='<div class="pict-flow-panel-help-content">'+tmpHelpText+'</div>';}}/**
2455
+ * Wire up tab switching on all tab buttons within a panel foreignObject.
2456
+ *
2457
+ * @param {Element} pForeignObject - The panel's SVG foreignObject element
2458
+ */},{key:"_wireTabSwitching",value:function _wireTabSwitching(pForeignObject){var tmpTabs=pForeignObject.querySelectorAll('.pict-flow-panel-tab');var tmpPanes=pForeignObject.querySelectorAll('.pict-flow-panel-tab-pane');for(var i=0;i<tmpTabs.length;i++){tmpTabs[i].addEventListener('click',function(pEvent){pEvent.stopPropagation();var tmpTarget=pEvent.currentTarget.getAttribute('data-tab-target');// Deactivate all tabs and panes
2459
+ for(var j=0;j<tmpTabs.length;j++){tmpTabs[j].classList.remove('active');}for(var _j=0;_j<tmpPanes.length;_j++){tmpPanes[_j].classList.remove('active');tmpPanes[_j].style.display='none';}// Activate the selected tab and pane
2460
+ pEvent.currentTarget.classList.add('active');var tmpTargetPane=pForeignObject.querySelector('.pict-flow-panel-tab-pane[data-tab="'+tmpTarget+'"]');if(tmpTargetPane){tmpTargetPane.classList.add('active');tmpTargetPane.style.display='block';}});}}/**
2461
+ * Apply a node property change from the properties editor and re-render.
2462
+ *
2463
+ * @param {string} pNodeHash - Hash of the node to update
2464
+ * @param {string} pPropPath - Property path (e.g. 'Title', 'Width', 'Style.BodyFill')
2465
+ * @param {string} pValue - The new value from the input
2466
+ * @param {string} pInputType - The input element type ('text', 'number', 'color')
2467
+ */},{key:"_applyNodePropChange",value:function _applyNodePropChange(pNodeHash,pPropPath,pValue,pInputType){var tmpNodeData=this._FlowView.getNode(pNodeHash);if(!tmpNodeData)return;// Parse numeric values
2468
+ var tmpValue=pValue;if(pInputType==='number'){tmpValue=parseFloat(pValue);if(isNaN(tmpValue))return;}// Apply the value based on the property path
2469
+ if(pPropPath==='Title'){tmpNodeData.Title=tmpValue;}else if(pPropPath==='Width'){tmpNodeData.Width=tmpValue;}else if(pPropPath==='Height'){tmpNodeData.Height=tmpValue;}else if(pPropPath.startsWith('Style.')){if(!tmpNodeData.Style)tmpNodeData.Style={};var tmpStyleKey=pPropPath.substring(6);// Remove 'Style.' prefix
2470
+ tmpNodeData.Style[tmpStyleKey]=tmpValue;}// Re-render the flow to reflect changes
2471
+ this._FlowView.renderFlow();this._FlowView.marshalFromView();// Fire change event
2472
+ if(this._FlowView._EventHandlerProvider){this._FlowView._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowView._FlowData);}}/**
2473
+ * Render a tether from a panel to its node.
2474
+ * Delegates to the TetherService for geometry, path generation, and SVG element creation.
2475
+ *
2476
+ * @param {Object} pPanelData
2477
+ * @param {SVGGElement} pTethersLayer
2478
+ * @param {boolean} pIsSelected
2479
+ */},{key:"_renderTether",value:function _renderTether(pPanelData,pTethersLayer,pIsSelected){var tmpTetherService=this._FlowView._TetherService;if(!tmpTetherService)return;var tmpNodeData=this._FlowView.getNode(pPanelData.NodeHash);if(!tmpNodeData)return;var tmpViewIdentifier=this._FlowView.options.ViewIdentifier;tmpTetherService.renderTether(pPanelData,tmpNodeData,pTethersLayer,pIsSelected,tmpViewIdentifier);}/**
2480
+ * Marshal data from all open panels back into their node Data objects.
2481
+ */},{key:"marshalAllFromPanels",value:function marshalAllFromPanels(){for(var tmpPanelHash in this._PanelInstances){var tmpInstance=this._PanelInstances[tmpPanelHash];if(tmpInstance&&tmpInstance._NodeData){tmpInstance.marshalFromPanel(tmpInstance._NodeData);}}}/**
2482
+ * Destroy a specific panel instance and clean up.
2483
+ *
2484
+ * @param {string} pPanelHash
2485
+ */},{key:"destroyPanel",value:function destroyPanel(pPanelHash){if(this._PanelInstances[pPanelHash]){this._PanelInstances[pPanelHash].destroy();delete this._PanelInstances[pPanelHash];}}/**
2486
+ * Destroy all panel instances.
2487
+ */},{key:"destroyAllPanels",value:function destroyAllPanels(){for(var tmpPanelHash in this._PanelInstances){this._PanelInstances[tmpPanelHash].destroy();}this._PanelInstances={};}}]);}(libPictView);module.exports=PictViewFlowPropertiesPanel;module.exports.default_configuration=_DefaultConfiguration;},{"pict-view":45}],42:[function(require,module,exports){var libPictView=require('pict-view');var _DefaultConfiguration={ViewIdentifier:'Flow-Toolbar',DefaultRenderable:'Flow-Toolbar-Content',DefaultDestinationAddress:'#Flow-Toolbar-Container',AutoRender:false,FlowViewIdentifier:'Pict-Flow',EnablePalette:true,EnableAddNode:true,EnableCardPalette:true,CSS:false,Templates:[{Hash:'Flow-Toolbar-Template',Template:/*html*/"\n<div class=\"pict-flow-toolbar\" id=\"Flow-Toolbar-Bar-{~D:Record.FlowViewIdentifier~}\">\n\t<div class=\"pict-flow-toolbar-group\">\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"add-node\" id=\"Flow-Toolbar-AddNode-{~D:Record.FlowViewIdentifier~}\" title=\"Add Node\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-plus-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t\t<span class=\"pict-flow-toolbar-btn-text\">Node</span>\n\t\t</button>\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"cards-popup\" id=\"Flow-Toolbar-Cards-{~D:Record.FlowViewIdentifier~}\" title=\"Card Palette\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-cards-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t\t<span class=\"pict-flow-toolbar-btn-text\">Cards</span>\n\t\t\t<span class=\"pict-flow-toolbar-btn-chevron\" id=\"Flow-Toolbar-CardsChevron-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"delete-selected\" title=\"Delete Node\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-trash-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t</div>\n\t<div class=\"pict-flow-toolbar-group\">\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"layout-popup\" id=\"Flow-Toolbar-Layout-{~D:Record.FlowViewIdentifier~}\" title=\"Manage Layouts\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-layout-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t\t<span class=\"pict-flow-toolbar-btn-text\">Layout</span>\n\t\t\t<span class=\"pict-flow-toolbar-btn-chevron\" id=\"Flow-Toolbar-LayoutChevron-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"auto-layout\" title=\"Auto Layout\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-auto-layout-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t\t<span class=\"pict-flow-toolbar-btn-text\">Auto Layout</span>\n\t\t</button>\n\t</div>\n\t<div class=\"pict-flow-toolbar-group\">\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"zoom-in\" title=\"Zoom In\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-zoom-in-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"zoom-out\" title=\"Zoom Out\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-zoom-out-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"zoom-fit\" title=\"Fit to View\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-zoom-fit-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t</div>\n\t<div class=\"pict-flow-toolbar-group pict-flow-toolbar-right\">\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"settings-popup\" id=\"Flow-Toolbar-Settings-{~D:Record.FlowViewIdentifier~}\" title=\"Theme Settings\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-settings-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"fullscreen\" id=\"Flow-Toolbar-Fullscreen-{~D:Record.FlowViewIdentifier~}\" title=\"Toggle Fullscreen\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Fullscreen-Icon-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"toggle-floating\" title=\"Float\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-grip-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t\t<button class=\"pict-flow-toolbar-btn\" data-flow-action=\"collapse-toolbar\" title=\"Collapse Toolbar\">\n\t\t\t<span class=\"pict-flow-toolbar-btn-icon\" id=\"Flow-Toolbar-Icon-collapse-{~D:Record.FlowViewIdentifier~}\"></span>\n\t\t</button>\n\t</div>\n</div>\n<div class=\"pict-flow-toolbar-collapsed\" id=\"Flow-Toolbar-Collapsed-{~D:Record.FlowViewIdentifier~}\">\n\t<button class=\"pict-flow-toolbar-expand-btn\" data-flow-action=\"expand-toolbar\" title=\"Expand Toolbar\" id=\"Flow-Toolbar-ExpandBtn-{~D:Record.FlowViewIdentifier~}\">\n\t\t<span id=\"Flow-Toolbar-Icon-expand-{~D:Record.FlowViewIdentifier~}\"></span>\n\t</button>\n</div>\n<div class=\"pict-flow-toolbar-popup-anchor\" id=\"Flow-Toolbar-PopupAnchor-{~D:Record.FlowViewIdentifier~}\">\n</div>\n"}],Renderables:[{RenderableHash:'Flow-Toolbar-Content',TemplateHash:'Flow-Toolbar-Template',DestinationAddress:'#Flow-Toolbar-Container',RenderMethod:'replace'}]};var PictViewFlowToolbar=/*#__PURE__*/function(_libPictView4){function PictViewFlowToolbar(pFable,pOptions,pServiceHash){var _this57;_classCallCheck(this,PictViewFlowToolbar);var tmpOptions=Object.assign({},JSON.parse(JSON.stringify(_DefaultConfiguration)),pOptions);_this57=_callSuper(this,PictViewFlowToolbar,[pFable,tmpOptions,pServiceHash]);_this57.serviceType='PictViewFlowToolbar';_this57._FlowView=null;// Toolbar mode state
2488
+ _this57._ToolbarMode='docked';// 'docked' | 'floating' | 'collapsed'
2489
+ _this57._ActivePopup=null;// 'add-node' | 'cards' | 'layout' | null
2490
+ _this57._FloatingPosition={X:80,Y:80};_this57._DocumentClickHandler=null;_this57._FloatingToolbarView=null;return _this57;}_inherits(PictViewFlowToolbar,_libPictView4);return _createClass(PictViewFlowToolbar,[{key:"render",value:function render(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress){// Pass this.options as the template record so {~D:Record.FlowViewIdentifier~}
2491
+ // resolves correctly in the toolbar template.
2492
+ return _superPropGet(PictViewFlowToolbar,"render",this,3)([pRenderableHash,pRenderDestinationAddress,this.options]);}},{key:"onAfterRender",value:function onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent){var _this58=this;var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;// Bind toolbar button events via event delegation
2493
+ var tmpToolbarBar=this.pict.ContentAssignment.getElement("#Flow-Toolbar-Bar-".concat(tmpFlowViewIdentifier));if(tmpToolbarBar.length>0){tmpToolbarBar[0].addEventListener('click',function(pEvent){var tmpTarget=pEvent.target;if(!tmpTarget)return;// Walk up to find the button with the action
2494
+ var tmpButton=tmpTarget.closest('[data-flow-action]');if(!tmpButton)return;var tmpAction=tmpButton.getAttribute('data-flow-action');_this58._handleToolbarAction(tmpAction);});}// Bind expand button click (it's outside the main toolbar bar)
2495
+ var tmpExpandBtn=this.pict.ContentAssignment.getElement("#Flow-Toolbar-ExpandBtn-".concat(tmpFlowViewIdentifier));if(tmpExpandBtn.length>0){tmpExpandBtn[0].addEventListener('click',function(){_this58._setToolbarMode('docked');});}// Populate SVG icons for toolbar buttons
2496
+ this._populateToolbarIcons();// Remove buttons from DOM based on options
2497
+ if(this.options.EnableAddNode===false){var tmpAddNodeBtn=this.pict.ContentAssignment.getElement("#Flow-Toolbar-AddNode-".concat(tmpFlowViewIdentifier));if(tmpAddNodeBtn.length>0){tmpAddNodeBtn[0].remove();}}if(this.options.EnableCardPalette===false){var tmpCardsBtn=this.pict.ContentAssignment.getElement("#Flow-Toolbar-Cards-".concat(tmpFlowViewIdentifier));if(tmpCardsBtn.length>0){tmpCardsBtn[0].remove();}}return _superPropGet(PictViewFlowToolbar,"onAfterRender",this,3)([pRenderable,pRenderDestinationAddress,pRecord,pContent]);}// ── Icon Population ───────────────────────────────────────────────────
2498
+ /**
2499
+ * Populate SVG icons for all toolbar buttons.
2500
+ */},{key:"_populateToolbarIcons",value:function _populateToolbarIcons(){var tmpIconProvider=this._FlowView?this._FlowView._IconProvider:null;if(!tmpIconProvider)return;var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;// Map of element ID suffix → icon key
2501
+ var tmpIconMap={'plus':'plus','trash':'trash','zoom-in':'zoom-in','zoom-out':'zoom-out','zoom-fit':'zoom-fit','auto-layout':'auto-layout','cards':'cards','layout':'layout','settings':'settings','grip':'grip','collapse':'collapse','expand':'expand'};var tmpKeys=Object.keys(tmpIconMap);for(var i=0;i<tmpKeys.length;i++){var tmpElementId="Flow-Toolbar-Icon-".concat(tmpKeys[i],"-").concat(tmpFlowViewIdentifier);var tmpElements=this.pict.ContentAssignment.getElement("#".concat(tmpElementId));if(tmpElements.length>0){tmpElements[0].innerHTML=tmpIconProvider.getIconSVGMarkup(tmpIconMap[tmpKeys[i]],14);}}// Fullscreen icon
2502
+ var tmpFullscreenIcon=this.pict.ContentAssignment.getElement("#Flow-Toolbar-Fullscreen-Icon-".concat(tmpFlowViewIdentifier));if(tmpFullscreenIcon.length>0){tmpFullscreenIcon[0].innerHTML=tmpIconProvider.getIconSVGMarkup('fullscreen',14);}// Chevrons (smaller)
2503
+ var tmpCardsChevron=this.pict.ContentAssignment.getElement("#Flow-Toolbar-CardsChevron-".concat(tmpFlowViewIdentifier));if(tmpCardsChevron.length>0){tmpCardsChevron[0].innerHTML=tmpIconProvider.getIconSVGMarkup('chevron-down',8);}var tmpLayoutChevron=this.pict.ContentAssignment.getElement("#Flow-Toolbar-LayoutChevron-".concat(tmpFlowViewIdentifier));if(tmpLayoutChevron.length>0){tmpLayoutChevron[0].innerHTML=tmpIconProvider.getIconSVGMarkup('chevron-down',8);}}// ── Popup Management ──────────────────────────────────────────────────
2504
+ /**
2505
+ * Open a popup below a trigger button.
2506
+ * @param {string} pType - 'add-node' | 'cards' | 'layout'
2507
+ */},{key:"_openPopup",value:function _openPopup(pType){var _this59=this;// Toggle off if already open
2508
+ if(this._ActivePopup===pType){this._closePopup();return;}// Close any existing popup first
2509
+ this._closePopup();var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpAnchor=this.pict.ContentAssignment.getElement("#Flow-Toolbar-PopupAnchor-".concat(tmpFlowViewIdentifier));if(tmpAnchor.length<1)return;// Create popup div
2510
+ var tmpPopup=document.createElement('div');tmpPopup.className='pict-flow-toolbar-popup';tmpPopup.setAttribute('id',"Flow-Toolbar-Popup-".concat(tmpFlowViewIdentifier));// Build popup content
2511
+ switch(pType){case'add-node':this._buildAddNodePopup(tmpPopup);break;case'cards':this._buildCardsPopup(tmpPopup);break;case'layout':this._buildLayoutPopup(tmpPopup);break;case'settings':this._buildSettingsPopup(tmpPopup);break;}tmpAnchor[0].appendChild(tmpPopup);this._ActivePopup=pType;// Position the popup below the trigger button
2512
+ this._positionPopup(tmpPopup,pType);// Click-outside-to-close handler (delayed to avoid catching the opening click)
2513
+ setTimeout(function(){_this59._DocumentClickHandler=function(pEvent){if(!tmpPopup.contains(pEvent.target)){// Check if click was on the trigger button itself (toggle behavior)
2514
+ var tmpButton=pEvent.target.closest('[data-flow-action]');if(tmpButton){var tmpAction=tmpButton.getAttribute('data-flow-action');if(tmpAction===pType||tmpAction===pType.replace('-popup','')+'-popup'){return;// Let the toggle handle it
2515
+ }}_this59._closePopup();}};document.addEventListener('click',_this59._DocumentClickHandler,true);},0);// Focus search input if Add Node popup
2516
+ if(pType==='add-node'){var tmpSearch=tmpPopup.querySelector('.pict-flow-popup-search');if(tmpSearch){setTimeout(function(){tmpSearch.focus();},50);}}}/**
2517
+ * Close the active popup and clean up.
2518
+ */},{key:"_closePopup",value:function _closePopup(){if(this._DocumentClickHandler){document.removeEventListener('click',this._DocumentClickHandler,true);this._DocumentClickHandler=null;}var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpPopup=this.pict.ContentAssignment.getElement("#Flow-Toolbar-Popup-".concat(tmpFlowViewIdentifier));if(tmpPopup.length>0){tmpPopup[0].parentNode.removeChild(tmpPopup[0]);}this._ActivePopup=null;}/**
2519
+ * Position a popup below its trigger button.
2520
+ * @param {HTMLElement} pPopupDiv
2521
+ * @param {string} pType
2522
+ */},{key:"_positionPopup",value:function _positionPopup(pPopupDiv,pType){var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;// Determine which button triggered the popup
2523
+ var tmpTriggerSelector;switch(pType){case'add-node':tmpTriggerSelector="#Flow-Toolbar-AddNode-".concat(tmpFlowViewIdentifier);break;case'cards':tmpTriggerSelector="#Flow-Toolbar-Cards-".concat(tmpFlowViewIdentifier);break;case'layout':tmpTriggerSelector="#Flow-Toolbar-Layout-".concat(tmpFlowViewIdentifier);break;case'settings':tmpTriggerSelector="#Flow-Toolbar-Settings-".concat(tmpFlowViewIdentifier);break;default:return;}var tmpTriggerElements=this.pict.ContentAssignment.getElement(tmpTriggerSelector);if(tmpTriggerElements.length<1)return;var tmpAnchor=this.pict.ContentAssignment.getElement("#Flow-Toolbar-PopupAnchor-".concat(tmpFlowViewIdentifier));if(tmpAnchor.length<1)return;var tmpTriggerRect=tmpTriggerElements[0].getBoundingClientRect();var tmpAnchorRect=tmpAnchor[0].getBoundingClientRect();var tmpLeft=tmpTriggerRect.left-tmpAnchorRect.left;pPopupDiv.style.left=tmpLeft+'px';pPopupDiv.style.top='0px';}// ── Add Node Popup ────────────────────────────────────────────────────
2524
+ /**
2525
+ * Build the searchable Add Node popup content.
2526
+ * @param {HTMLElement} pContainer
2527
+ */},{key:"_buildAddNodePopup",value:function _buildAddNodePopup(pContainer){var _this60=this;// Search wrapper
2528
+ var tmpSearchWrapper=document.createElement('div');tmpSearchWrapper.className='pict-flow-popup-search-wrapper';var tmpSearchIcon=document.createElement('span');tmpSearchIcon.className='pict-flow-popup-search-icon';var tmpIconProvider=this._FlowView?this._FlowView._IconProvider:null;if(tmpIconProvider){tmpSearchIcon.innerHTML=tmpIconProvider.getIconSVGMarkup('search',12);}tmpSearchWrapper.appendChild(tmpSearchIcon);var tmpSearchInput=document.createElement('input');tmpSearchInput.className='pict-flow-popup-search';tmpSearchInput.setAttribute('type','text');tmpSearchInput.setAttribute('placeholder','Search node types...');tmpSearchWrapper.appendChild(tmpSearchInput);pContainer.appendChild(tmpSearchWrapper);// Node list
2529
+ var tmpListDiv=document.createElement('div');tmpListDiv.className='pict-flow-popup-node-list';pContainer.appendChild(tmpListDiv);// Initial population
2530
+ this._populateNodeList(tmpListDiv,'');// Filter on input
2531
+ tmpSearchInput.addEventListener('input',function(){_this60._populateNodeList(tmpListDiv,tmpSearchInput.value);});}/**
2532
+ * Populate the node list in the Add Node popup, filtered by search text.
2533
+ * @param {HTMLElement} pListDiv
2534
+ * @param {string} pFilter
2535
+ */},{key:"_populateNodeList",value:function _populateNodeList(pListDiv,pFilter){var _this61=this;if(!this._FlowView||!this._FlowView._NodeTypeProvider)return;// Clear
2536
+ while(pListDiv.firstChild){pListDiv.removeChild(pListDiv.firstChild);}var tmpTypes=this._FlowView._NodeTypeProvider.getNodeTypes();var tmpTypeKeys=Object.keys(tmpTypes);var tmpFilter=(pFilter||'').toLowerCase().trim();var tmpIconProvider=this._FlowView._IconProvider;var tmpMatchCount=0;var _loop2=function _loop2(i){var tmpTypeConfig=tmpTypes[tmpTypeKeys[i]];var tmpMeta=tmpTypeConfig.CardMetadata||{};// Skip disabled cards
2537
+ if(tmpMeta.Enabled===false)return 0;// continue
2538
+ // Filter match: label, code, or category
2539
+ if(tmpFilter){var tmpLabel=(tmpTypeConfig.Label||'').toLowerCase();var tmpCode=(tmpMeta.Code||'').toLowerCase();var tmpCategory=(tmpMeta.Category||'').toLowerCase();if(tmpLabel.indexOf(tmpFilter)<0&&tmpCode.indexOf(tmpFilter)<0&&tmpCategory.indexOf(tmpFilter)<0){return 0;// continue
2540
+ }}tmpMatchCount++;var tmpRow=document.createElement('div');tmpRow.className='pict-flow-popup-list-item';tmpRow.setAttribute('data-node-type',tmpTypeKeys[i]);// Icon
2541
+ var tmpIconSpan=document.createElement('span');tmpIconSpan.className='pict-flow-popup-list-item-icon';if(tmpIconProvider){var tmpResolvedKey=tmpIconProvider.resolveIconKey(tmpMeta);tmpIconSpan.innerHTML=tmpIconProvider.getIconSVGMarkup(tmpResolvedKey,16);}tmpRow.appendChild(tmpIconSpan);// Label
2542
+ var tmpLabelSpan=document.createElement('span');tmpLabelSpan.className='pict-flow-popup-list-item-label';tmpLabelSpan.textContent=tmpTypeConfig.Label;tmpRow.appendChild(tmpLabelSpan);// Code badge
2543
+ if(tmpMeta.Code){var tmpCodeSpan=document.createElement('span');tmpCodeSpan.className='pict-flow-popup-list-item-code';tmpCodeSpan.textContent=tmpMeta.Code;tmpRow.appendChild(tmpCodeSpan);}// Click handler
2544
+ tmpRow.addEventListener('click',function(){_this61._addNodeAtCenter(tmpTypeKeys[i]);_this61._closePopup();});pListDiv.appendChild(tmpRow);},_ret;for(var i=0;i<tmpTypeKeys.length;i++){_ret=_loop2(i);if(_ret===0)continue;}if(tmpMatchCount===0){var tmpEmpty=document.createElement('div');tmpEmpty.className='pict-flow-popup-list-empty';tmpEmpty.textContent='No matching node types';pListDiv.appendChild(tmpEmpty);}}// ── Cards Popup ───────────────────────────────────────────────────────
2545
+ /**
2546
+ * Build the Cards popup content with search and categorized palette.
2547
+ * @param {HTMLElement} pContainer
2548
+ */},{key:"_buildCardsPopup",value:function _buildCardsPopup(pContainer){var _this62=this;// Search wrapper
2549
+ var tmpSearchWrapper=document.createElement('div');tmpSearchWrapper.className='pict-flow-popup-search-wrapper';var tmpSearchIcon=document.createElement('span');tmpSearchIcon.className='pict-flow-popup-search-icon';var tmpIconProvider=this._FlowView?this._FlowView._IconProvider:null;if(tmpIconProvider){tmpSearchIcon.innerHTML=tmpIconProvider.getIconSVGMarkup('search',12);}tmpSearchWrapper.appendChild(tmpSearchIcon);var tmpSearchInput=document.createElement('input');tmpSearchInput.className='pict-flow-popup-search';tmpSearchInput.setAttribute('type','text');tmpSearchInput.setAttribute('placeholder','Search cards...');tmpSearchWrapper.appendChild(tmpSearchInput);pContainer.appendChild(tmpSearchWrapper);// Palette list container
2550
+ var tmpListDiv=document.createElement('div');tmpListDiv.className='pict-flow-popup-node-list';pContainer.appendChild(tmpListDiv);// Initial population
2551
+ this._renderPalette(tmpListDiv,'');// Filter on input
2552
+ tmpSearchInput.addEventListener('input',function(){_this62._renderPalette(tmpListDiv,tmpSearchInput.value);});// Focus search input
2553
+ setTimeout(function(){tmpSearchInput.focus();},50);}/**
2554
+ * Render the card palette with categories and card chips into a container.
2555
+ * @param {HTMLElement} pContainer - The target container element
2556
+ * @param {string} [pFilter] - Optional search filter text
2557
+ */},{key:"_renderPalette",value:function _renderPalette(pContainer,pFilter){var _this63=this;if(!this._FlowView||!this._FlowView._NodeTypeProvider)return;// Clear existing content
2558
+ while(pContainer.firstChild){pContainer.removeChild(pContainer.firstChild);}var tmpCategories=this._FlowView._NodeTypeProvider.getCardsByCategory();var tmpCategoryKeys=Object.keys(tmpCategories);var tmpFilter=(pFilter||'').toLowerCase().trim();var tmpTotalMatchCount=0;for(var i=0;i<tmpCategoryKeys.length;i++){var tmpCategoryName=tmpCategoryKeys[i];var tmpCards=tmpCategories[tmpCategoryName];var tmpMatchingCards=[];// Filter cards within this category
2559
+ for(var j=0;j<tmpCards.length;j++){var tmpCardConfig=tmpCards[j];var tmpMeta=tmpCardConfig.CardMetadata||{};if(tmpFilter){var tmpLabel=(tmpCardConfig.Label||'').toLowerCase();var tmpCode=(tmpMeta.Code||'').toLowerCase();var tmpCategory=tmpCategoryName.toLowerCase();if(tmpLabel.indexOf(tmpFilter)<0&&tmpCode.indexOf(tmpFilter)<0&&tmpCategory.indexOf(tmpFilter)<0){continue;}}tmpMatchingCards.push(tmpCardConfig);}if(tmpMatchingCards.length===0)continue;tmpTotalMatchCount+=tmpMatchingCards.length;var tmpCategoryDiv=document.createElement('div');tmpCategoryDiv.className='pict-flow-palette-category';tmpCategoryDiv.style.padding='0.35em 0.5em';var tmpCategoryLabel=document.createElement('div');tmpCategoryLabel.className='pict-flow-palette-category-label';tmpCategoryLabel.textContent=tmpCategoryName;tmpCategoryDiv.appendChild(tmpCategoryLabel);var tmpCardsDiv=document.createElement('div');tmpCardsDiv.className='pict-flow-palette-cards';var _loop3=function _loop3(){var tmpCardConfig=tmpMatchingCards[_j2];var tmpMeta=tmpCardConfig.CardMetadata||{};var tmpCardEl=document.createElement('div');tmpCardEl.className='pict-flow-palette-card';if(tmpMeta.Enabled===false){tmpCardEl.classList.add('disabled');}tmpCardEl.setAttribute('data-card-type',tmpCardConfig.Hash);if(tmpMeta.Tooltip){tmpCardEl.setAttribute('title',tmpMeta.Tooltip);}else if(tmpMeta.Description){tmpCardEl.setAttribute('title',tmpMeta.Description);}// Icon or color swatch
2560
+ if(tmpMeta.Icon){var tmpIconSpan=document.createElement('span');tmpIconSpan.className='pict-flow-palette-card-icon';var tmpIconProvider=_this63._FlowView._IconProvider;if(tmpIconProvider&&!tmpIconProvider.isEmojiIcon(tmpMeta.Icon)){var tmpResolvedKey=tmpIconProvider.resolveIconKey(tmpMeta);tmpIconSpan.innerHTML=tmpIconProvider.getIconSVGMarkup(tmpResolvedKey,14);}else{tmpIconSpan.textContent=tmpMeta.Icon;}tmpCardEl.appendChild(tmpIconSpan);}else if(_this63._FlowView._IconProvider){var _tmpIconSpan=document.createElement('span');_tmpIconSpan.className='pict-flow-palette-card-icon';_tmpIconSpan.innerHTML=_this63._FlowView._IconProvider.getIconSVGMarkup('default',14);tmpCardEl.appendChild(_tmpIconSpan);}else if(tmpCardConfig.TitleBarColor){var tmpSwatch=document.createElement('span');tmpSwatch.className='pict-flow-palette-card-swatch';tmpSwatch.style.backgroundColor=tmpCardConfig.TitleBarColor;tmpCardEl.appendChild(tmpSwatch);}// Title
2561
+ var tmpTitleSpan=document.createElement('span');tmpTitleSpan.className='pict-flow-palette-card-title';tmpTitleSpan.textContent=tmpCardConfig.Label;tmpCardEl.appendChild(tmpTitleSpan);// Code badge
2562
+ if(tmpMeta.Code){var tmpCodeSpan=document.createElement('span');tmpCodeSpan.className='pict-flow-palette-card-code';tmpCodeSpan.textContent=tmpMeta.Code;tmpCardEl.appendChild(tmpCodeSpan);}// Click handler
2563
+ tmpCardEl.addEventListener('click',function(){_this63._addCardFromPalette(tmpCardConfig.Hash);_this63._closePopup();});tmpCardsDiv.appendChild(tmpCardEl);};for(var _j2=0;_j2<tmpMatchingCards.length;_j2++){_loop3();}tmpCategoryDiv.appendChild(tmpCardsDiv);pContainer.appendChild(tmpCategoryDiv);}if(tmpTotalMatchCount===0){var tmpEmpty=document.createElement('div');tmpEmpty.className='pict-flow-popup-list-empty';tmpEmpty.textContent=tmpFilter?'No matching cards':'No card types available';pContainer.appendChild(tmpEmpty);}}// ── Layout Popup ──────────────────────────────────────────────────────
2564
+ /**
2565
+ * Build the Layout popup content.
2566
+ * @param {HTMLElement} pContainer
2567
+ */},{key:"_buildLayoutPopup",value:function _buildLayoutPopup(pContainer){var _this64=this;var tmpIconProvider=this._FlowView?this._FlowView._IconProvider:null;// Save Layout section at top
2568
+ var tmpSaveSection=document.createElement('div');tmpSaveSection.className='pict-flow-popup-layout-save-section';// Save input row (hidden initially)
2569
+ var tmpSaveInputRow=document.createElement('div');tmpSaveInputRow.className='pict-flow-popup-layout-save-input-row';tmpSaveInputRow.style.display='none';var tmpSaveInput=document.createElement('input');tmpSaveInput.className='pict-flow-popup-layout-save-input';tmpSaveInput.setAttribute('type','text');tmpSaveInput.setAttribute('placeholder','Layout name...');tmpSaveInputRow.appendChild(tmpSaveInput);var tmpSaveConfirmBtn=document.createElement('button');tmpSaveConfirmBtn.className='pict-flow-popup-layout-save-confirm';tmpSaveConfirmBtn.title='Save';if(tmpIconProvider){tmpSaveConfirmBtn.innerHTML=tmpIconProvider.getIconSVGMarkup('save',14);}else{tmpSaveConfirmBtn.textContent='✓';}tmpSaveInputRow.appendChild(tmpSaveConfirmBtn);// "Save Current Layout" clickable row
2570
+ var tmpSaveRow=document.createElement('div');tmpSaveRow.className='pict-flow-popup-layout-save';var tmpSaveIcon=document.createElement('span');tmpSaveIcon.className='pict-flow-popup-layout-save-icon';if(tmpIconProvider){tmpSaveIcon.innerHTML=tmpIconProvider.getIconSVGMarkup('save',14);}tmpSaveRow.appendChild(tmpSaveIcon);var tmpSaveText=document.createElement('span');tmpSaveText.textContent='Save Current Layout';tmpSaveRow.appendChild(tmpSaveText);// Click "Save Current Layout" to reveal the input row
2571
+ tmpSaveRow.addEventListener('click',function(){tmpSaveRow.style.display='none';tmpSaveInputRow.style.display='';tmpSaveInput.value='';setTimeout(function(){tmpSaveInput.focus();},50);});// Confirm save via button click
2572
+ var tmpDoSave=function tmpDoSave(){var tmpName=tmpSaveInput.value.trim();if(tmpName==='')return;_this64._FlowView._LayoutProvider.saveLayout(tmpName);// Refresh the popup content
2573
+ while(pContainer.firstChild){pContainer.removeChild(pContainer.firstChild);}_this64._buildLayoutPopup(pContainer);};tmpSaveConfirmBtn.addEventListener('click',tmpDoSave);// Confirm save via Enter key
2574
+ tmpSaveInput.addEventListener('keydown',function(pEvent){if(pEvent.key==='Enter'){pEvent.preventDefault();tmpDoSave();}else if(pEvent.key==='Escape'){// Cancel — hide input, show the save row again
2575
+ tmpSaveInputRow.style.display='none';tmpSaveRow.style.display='';}});// Prevent clicks inside the input from closing the popup
2576
+ tmpSaveInput.addEventListener('click',function(pEvent){pEvent.stopPropagation();});tmpSaveSection.appendChild(tmpSaveRow);tmpSaveSection.appendChild(tmpSaveInputRow);pContainer.appendChild(tmpSaveSection);// Divider
2577
+ var tmpDivider=document.createElement('div');tmpDivider.className='pict-flow-popup-divider';pContainer.appendChild(tmpDivider);// Layout rows
2578
+ if(!this._FlowView||!this._FlowView._LayoutProvider){var tmpEmpty=document.createElement('div');tmpEmpty.className='pict-flow-popup-list-empty';tmpEmpty.textContent='No saved layouts';pContainer.appendChild(tmpEmpty);return;}var tmpLayouts=this._FlowView._LayoutProvider.getLayouts();if(tmpLayouts.length===0){var _tmpEmpty=document.createElement('div');_tmpEmpty.className='pict-flow-popup-list-empty';_tmpEmpty.textContent='No saved layouts';pContainer.appendChild(_tmpEmpty);return;}var _loop4=function _loop4(){var tmpLayout=tmpLayouts[i];var tmpRow=document.createElement('div');tmpRow.className='pict-flow-popup-layout-row';var tmpNameSpan=document.createElement('span');tmpNameSpan.className='pict-flow-popup-layout-name';tmpNameSpan.textContent=tmpLayout.Name;tmpRow.appendChild(tmpNameSpan);// Delete button (visible on hover via CSS)
2579
+ var tmpDeleteBtn=document.createElement('button');tmpDeleteBtn.className='pict-flow-popup-layout-delete';tmpDeleteBtn.title='Delete layout';if(tmpIconProvider){tmpDeleteBtn.innerHTML=tmpIconProvider.getIconSVGMarkup('trash',12);}else{tmpDeleteBtn.textContent='×';}tmpRow.appendChild(tmpDeleteBtn);// Click row → restore layout
2580
+ tmpRow.addEventListener('click',function(pEvent){// Don't restore if they clicked the delete button
2581
+ if(pEvent.target.closest('.pict-flow-popup-layout-delete')){return;}_this64._FlowView._LayoutProvider.restoreLayout(tmpLayout.Hash);_this64._closePopup();});// Click delete → delete layout and refresh popup
2582
+ tmpDeleteBtn.addEventListener('click',function(pEvent){pEvent.stopPropagation();_this64._FlowView._LayoutProvider.deleteLayout(tmpLayout.Hash);// Refresh the popup content
2583
+ while(pContainer.firstChild){pContainer.removeChild(pContainer.firstChild);}_this64._buildLayoutPopup(pContainer);});pContainer.appendChild(tmpRow);};for(var i=0;i<tmpLayouts.length;i++){_loop4();}}// ── Settings Popup ───────────────────────────────────────────────────
2584
+ /**
2585
+ * Build the Settings popup content (theme dropdown + noise slider).
2586
+ * @param {HTMLElement} pContainer
2587
+ */},{key:"_buildSettingsPopup",value:function _buildSettingsPopup(pContainer){var _this65=this;if(!this._FlowView||!this._FlowView._ThemeProvider)return;var tmpThemeProvider=this._FlowView._ThemeProvider;// Theme selector section
2588
+ var tmpThemeSection=document.createElement('div');tmpThemeSection.className='pict-flow-popup-settings-section';var tmpThemeLabel=document.createElement('label');tmpThemeLabel.className='pict-flow-popup-settings-label';tmpThemeLabel.textContent='Theme';tmpThemeSection.appendChild(tmpThemeLabel);var tmpThemeSelect=document.createElement('select');tmpThemeSelect.className='pict-flow-popup-settings-select';var tmpThemeKeys=tmpThemeProvider.getThemeKeys();var tmpActiveKey=tmpThemeProvider.getActiveThemeKey();for(var i=0;i<tmpThemeKeys.length;i++){var tmpOption=document.createElement('option');tmpOption.value=tmpThemeKeys[i];var tmpTheme=tmpThemeProvider._Themes[tmpThemeKeys[i]];tmpOption.textContent=tmpTheme.Label||tmpThemeKeys[i];if(tmpThemeKeys[i]===tmpActiveKey){tmpOption.selected=true;}tmpThemeSelect.appendChild(tmpOption);}tmpThemeSelect.addEventListener('change',function(){_this65._FlowView.setTheme(tmpThemeSelect.value);// Refresh the noise slider visibility
2589
+ _this65._refreshNoiseSlider(pContainer);});// Prevent popup close on select interaction
2590
+ tmpThemeSelect.addEventListener('click',function(pEvent){pEvent.stopPropagation();});tmpThemeSection.appendChild(tmpThemeSelect);pContainer.appendChild(tmpThemeSection);// Divider
2591
+ var tmpDivider=document.createElement('div');tmpDivider.className='pict-flow-popup-divider';pContainer.appendChild(tmpDivider);// Noise level section
2592
+ var tmpNoiseSection=document.createElement('div');tmpNoiseSection.className='pict-flow-popup-settings-section pict-flow-popup-settings-noise';tmpNoiseSection.setAttribute('data-settings-type','noise');var tmpNoiseLabel=document.createElement('label');tmpNoiseLabel.className='pict-flow-popup-settings-label';tmpNoiseLabel.textContent='Noise';tmpNoiseSection.appendChild(tmpNoiseLabel);var tmpNoiseRow=document.createElement('div');tmpNoiseRow.className='pict-flow-popup-settings-slider-row';var tmpNoiseSlider=document.createElement('input');tmpNoiseSlider.type='range';tmpNoiseSlider.className='pict-flow-popup-settings-slider';tmpNoiseSlider.min='0';tmpNoiseSlider.max='100';tmpNoiseSlider.value=String(Math.round(tmpThemeProvider.getNoiseLevel()*100));var tmpNoiseValue=document.createElement('span');tmpNoiseValue.className='pict-flow-popup-settings-slider-value';tmpNoiseValue.textContent=tmpNoiseSlider.value+'%';tmpNoiseSlider.addEventListener('input',function(){var tmpLevel=parseInt(tmpNoiseSlider.value,10)/100;tmpNoiseValue.textContent=tmpNoiseSlider.value+'%';_this65._FlowView.setNoiseLevel(tmpLevel);});// Prevent popup close on slider interaction
2593
+ tmpNoiseSlider.addEventListener('click',function(pEvent){pEvent.stopPropagation();});tmpNoiseSlider.addEventListener('pointerdown',function(pEvent){pEvent.stopPropagation();});tmpNoiseRow.appendChild(tmpNoiseSlider);tmpNoiseRow.appendChild(tmpNoiseValue);tmpNoiseSection.appendChild(tmpNoiseRow);pContainer.appendChild(tmpNoiseSection);// Show/hide noise slider based on active theme
2594
+ this._refreshNoiseSlider(pContainer);}/**
2595
+ * Show or hide the noise slider based on whether the active theme supports noise.
2596
+ * @param {HTMLElement} pContainer - The settings popup container
2597
+ */},{key:"_refreshNoiseSlider",value:function _refreshNoiseSlider(pContainer){var tmpNoiseSection=pContainer.querySelector('[data-settings-type="noise"]');if(!tmpNoiseSection)return;var tmpTheme=this._FlowView._ThemeProvider.getActiveTheme();if(tmpTheme&&tmpTheme.NoiseConfig&&tmpTheme.NoiseConfig.Enabled){tmpNoiseSection.style.display='';// Update slider value to reflect theme default
2598
+ var tmpSlider=tmpNoiseSection.querySelector('.pict-flow-popup-settings-slider');var tmpValueLabel=tmpNoiseSection.querySelector('.pict-flow-popup-settings-slider-value');if(tmpSlider){var tmpLevel=Math.round(this._FlowView._ThemeProvider.getNoiseLevel()*100);tmpSlider.value=String(tmpLevel);if(tmpValueLabel)tmpValueLabel.textContent=tmpLevel+'%';}}else{tmpNoiseSection.style.display='none';}}// ── Toolbar Mode Switching ────────────────────────────────────────────
2599
+ /**
2600
+ * Switch between docked, floating, and collapsed modes.
2601
+ * @param {string} pMode - 'docked' | 'floating' | 'collapsed'
2602
+ */},{key:"_setToolbarMode",value:function _setToolbarMode(pMode){// Close any active popup first
2603
+ this._closePopup();var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;var tmpBar=this.pict.ContentAssignment.getElement("#Flow-Toolbar-Bar-".concat(tmpFlowViewIdentifier));var tmpCollapsed=this.pict.ContentAssignment.getElement("#Flow-Toolbar-Collapsed-".concat(tmpFlowViewIdentifier));switch(pMode){case'docked':// Show toolbar bar
2604
+ if(tmpBar.length>0)tmpBar[0].style.display='';// Hide collapsed button
2605
+ if(tmpCollapsed.length>0)tmpCollapsed[0].classList.remove('visible');// Hide floating toolbar
2606
+ if(this._FloatingToolbarView)this._FloatingToolbarView.hide();break;case'floating':// Hide toolbar bar
2607
+ if(tmpBar.length>0)tmpBar[0].style.display='none';// Hide collapsed button
2608
+ if(tmpCollapsed.length>0)tmpCollapsed[0].classList.remove('visible');// Show floating toolbar
2609
+ this._showFloatingToolbar();break;case'collapsed':// Hide toolbar bar
2610
+ if(tmpBar.length>0)tmpBar[0].style.display='none';// Show collapsed button
2611
+ if(tmpCollapsed.length>0)tmpCollapsed[0].classList.add('visible');// Hide floating toolbar
2612
+ if(this._FloatingToolbarView)this._FloatingToolbarView.hide();break;}this._ToolbarMode=pMode;}/**
2613
+ * Lazily create and show the floating toolbar.
2614
+ */},{key:"_showFloatingToolbar",value:function _showFloatingToolbar(){if(!this._FlowView)return;if(!this._FloatingToolbarView){var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;this._FloatingToolbarView=this.fable.instantiateServiceProviderWithoutRegistration('PictViewFlowFloatingToolbar',{FlowViewIdentifier:tmpFlowViewIdentifier,DefaultDestinationAddress:"#Flow-FloatingToolbar-Container-".concat(tmpFlowViewIdentifier),EnableAddNode:this.options.EnableAddNode,EnableCardPalette:this.options.EnableCardPalette});this._FloatingToolbarView._ToolbarView=this;this._FloatingToolbarView._FlowView=this._FlowView;this._FloatingToolbarView.render();}this._FloatingToolbarView.show();}// ── Node Placement Helpers ────────────────────────────────────────────
2615
+ /**
2616
+ * Add a node at the center of the visible viewport.
2617
+ * @param {string} pNodeType - The node type hash
2618
+ */},{key:"_addNodeAtCenter",value:function _addNodeAtCenter(pNodeType){if(!this._FlowView)return;var tmpVS=this._FlowView.viewState;// Calculate the center of the visible SVG area
2619
+ var tmpSVGContainer=this._FlowView._SVGElement;var tmpWidth=tmpSVGContainer?tmpSVGContainer.clientWidth:600;var tmpHeight=tmpSVGContainer?tmpSVGContainer.clientHeight:400;var tmpCenterX=(-tmpVS.PanX+tmpWidth/2)/tmpVS.Zoom;var tmpCenterY=(-tmpVS.PanY+tmpHeight/2)/tmpVS.Zoom;// Slight offset to avoid stacking
2620
+ var tmpNodeCount=this._FlowView.flowData.Nodes.length;tmpCenterX+=tmpNodeCount%5*30;tmpCenterY+=tmpNodeCount%5*30;this._FlowView.addNode(pNodeType,tmpCenterX,tmpCenterY);}/**
2621
+ * Add a node from a palette card click.
2622
+ * @param {string} pCardType - The card type hash
2623
+ */},{key:"_addCardFromPalette",value:function _addCardFromPalette(pCardType){if(!this._FlowView)return;var tmpVS=this._FlowView.viewState;var tmpX=(-tmpVS.PanX+200)/tmpVS.Zoom;var tmpY=(-tmpVS.PanY+200)/tmpVS.Zoom;// Offset to avoid overlap
2624
+ var tmpNodeCount=this._FlowView.flowData.Nodes.length;tmpX+=tmpNodeCount%5*40;tmpY+=tmpNodeCount%5*40;this._FlowView.addNode(pCardType,tmpX,tmpY);}// ── Action Handler ────────────────────────────────────────────────────
2625
+ /**
2626
+ * Handle a toolbar action
2627
+ * @param {string} pAction
2628
+ */},{key:"_handleToolbarAction",value:function _handleToolbarAction(pAction){if(!this._FlowView)return;var tmpFlowViewIdentifier=this.options.FlowViewIdentifier;switch(pAction){case'add-node':this._openPopup('add-node');break;case'delete-selected':this._FlowView.deleteSelected();break;case'zoom-in':this._FlowView.setZoom(this._FlowView.viewState.Zoom+this._FlowView.options.ZoomStep);break;case'zoom-out':this._FlowView.setZoom(this._FlowView.viewState.Zoom-this._FlowView.options.ZoomStep);break;case'zoom-fit':this._FlowView.zoomToFit();break;case'auto-layout':this._FlowView.autoLayout();break;case'cards-popup':this._openPopup('cards');break;case'layout-popup':this._openPopup('layout');break;case'settings-popup':this._openPopup('settings');break;case'toggle-floating':if(this._ToolbarMode==='floating'){this._setToolbarMode('docked');}else{this._setToolbarMode('floating');}break;case'collapse-toolbar':this._setToolbarMode('collapsed');break;case'expand-toolbar':this._setToolbarMode('docked');break;case'fullscreen':{var tmpIsFullscreen=this._FlowView.toggleFullscreen();var tmpIconProvider=this._FlowView._IconProvider;var tmpIconElements=this.pict.ContentAssignment.getElement("#Flow-Toolbar-Fullscreen-Icon-".concat(tmpFlowViewIdentifier));if(tmpIconElements.length>0&&tmpIconProvider){tmpIconElements[0].innerHTML=tmpIconProvider.getIconSVGMarkup(tmpIsFullscreen?'exit-fullscreen':'fullscreen',14);}var tmpFullscreenBtn=this.pict.ContentAssignment.getElement("#Flow-Toolbar-Fullscreen-".concat(tmpFlowViewIdentifier));if(tmpFullscreenBtn.length>0){tmpFullscreenBtn[0].setAttribute('title',tmpIsFullscreen?'Exit Fullscreen':'Toggle Fullscreen');}}break;default:this.log.warn("PictViewFlowToolbar: unknown action '".concat(pAction,"'"));break;}}}]);}(libPictView);module.exports=PictViewFlowToolbar;module.exports.default_configuration=_DefaultConfiguration;},{"pict-view":45}],43:[function(require,module,exports){var libPictView=require('pict-view');var libPictServiceFlowInteractionManager=require('../services/PictService-Flow-InteractionManager.js');var libPictServiceFlowConnectionRenderer=require('../services/PictService-Flow-ConnectionRenderer.js');var libPictServiceFlowTether=require('../services/PictService-Flow-Tether.js');var libPictServiceFlowLayout=require('../services/PictService-Flow-Layout.js');var libPictServiceFlowPathGenerator=require('../services/PictService-Flow-PathGenerator.js');var libPictServiceFlowViewportManager=require('../services/PictService-Flow-ViewportManager.js');var libPictServiceFlowSelectionManager=require('../services/PictService-Flow-SelectionManager.js');var libPictServiceFlowPanelManager=require('../services/PictService-Flow-PanelManager.js');var libPictServiceFlowDataManager=require('../services/PictService-Flow-DataManager.js');var libPictServiceFlowConnectionHandleManager=require('../services/PictService-Flow-ConnectionHandleManager.js');var libPictServiceFlowRenderManager=require('../services/PictService-Flow-RenderManager.js');var libPictServiceFlowPortRenderer=require('../services/PictService-Flow-PortRenderer.js');var libPictProviderFlowNodeTypes=require('../providers/PictProvider-Flow-NodeTypes.js');var libPictProviderFlowEventHandler=require('../providers/PictProvider-Flow-EventHandler.js');var libPictProviderFlowLayouts=require('../providers/PictProvider-Flow-Layouts.js');var libPictProviderFlowSVGHelpers=require('../providers/PictProvider-Flow-SVGHelpers.js');var libPictProviderFlowGeometry=require('../providers/PictProvider-Flow-Geometry.js');var libPictProviderFlowPanelChrome=require('../providers/PictProvider-Flow-PanelChrome.js');var libPictProviderFlowCSS=require('../providers/PictProvider-Flow-CSS.js');var libPictProviderFlowIcons=require('../providers/PictProvider-Flow-Icons.js');var libPictProviderFlowConnectorShapes=require('../providers/PictProvider-Flow-ConnectorShapes.js');var libPictProviderFlowTheme=require('../providers/PictProvider-Flow-Theme.js');var libPictProviderFlowNoise=require('../providers/PictProvider-Flow-Noise.js');var libPictViewFlowNode=require('./PictView-Flow-Node.js');var libPictViewFlowToolbar=require('./PictView-Flow-Toolbar.js');var libPictViewFlowFloatingToolbar=require('./PictView-Flow-FloatingToolbar.js');var libPictViewFlowPropertiesPanel=require('./PictView-Flow-PropertiesPanel.js');var libPictFlowCardPropertiesPanel=require('../PictFlowCardPropertiesPanel.js');var libPanelTemplate=require('../panels/FlowCardPropertiesPanel-Template.js');var libPanelMarkdown=require('../panels/FlowCardPropertiesPanel-Markdown.js');var libPanelForm=require('../panels/FlowCardPropertiesPanel-Form.js');var libPanelView=require('../panels/FlowCardPropertiesPanel-View.js');var _DefaultConfiguration={ViewIdentifier:'Pict-Flow',DefaultRenderable:'Flow-Container',DefaultDestinationAddress:'#Flow-Container',AutoRender:false,FlowDataAddress:false,TargetElementAddress:'#Flow-SVG-Container',EnableToolbar:true,EnableAddNode:true,EnableCardPalette:true,IncludeDefaultNodeTypes:true,EnablePanning:true,EnableZooming:true,EnableNodeDragging:true,EnableConnectionCreation:true,EnableGridSnap:false,GridSnapSize:20,MinZoom:0.1,MaxZoom:5.0,ZoomStep:0.1,DefaultNodeType:'default',DefaultNodeWidth:180,DefaultNodeHeight:80,CSS:false,Templates:[{Hash:'Flow-PanelChrome-Template',Template:/*html*/"<div class=\"pict-flow-panel\" xmlns=\"http://www.w3.org/1999/xhtml\"><div class=\"pict-flow-panel-titlebar\" data-element-type=\"panel-titlebar\" data-panel-hash=\"{~D:Record.Hash~}\"><span class=\"pict-flow-panel-title-text\">{~D:Record.Title~}</span><span class=\"pict-flow-panel-close-btn\" data-element-type=\"panel-close\" data-panel-hash=\"{~D:Record.Hash~}\"><span class=\"pict-flow-panel-close-icon\"></span></span></div><div class=\"pict-flow-panel-content\" data-panel-hash=\"{~D:Record.Hash~}\"><div class=\"pict-flow-panel-tab-pane active\" data-tab=\"properties\" data-panel-hash=\"{~D:Record.Hash~}\"></div><div class=\"pict-flow-panel-tab-pane\" data-tab=\"help\" data-panel-hash=\"{~D:Record.Hash~}\" style=\"display:none;\"></div><div class=\"pict-flow-panel-tab-pane\" data-tab=\"appearance\" data-panel-hash=\"{~D:Record.Hash~}\" style=\"display:none;\"></div></div><div class=\"pict-flow-panel-resize-handle\" data-element-type=\"panel-resize\" data-panel-hash=\"{~D:Record.Hash~}\"></div><div class=\"pict-flow-panel-tabbar\" data-panel-hash=\"{~D:Record.Hash~}\"><div class=\"pict-flow-panel-tab active\" data-tab-target=\"properties\" data-panel-hash=\"{~D:Record.Hash~}\">Properties</div><div class=\"pict-flow-panel-tab\" data-tab-target=\"help\" data-panel-hash=\"{~D:Record.Hash~}\" style=\"display:none;\">Help</div><div class=\"pict-flow-panel-tab\" data-tab-target=\"appearance\" data-panel-hash=\"{~D:Record.Hash~}\">Appearance</div></div></div>"},{Hash:'Flow-Container-Template',Template:/*html*/"\n<div class=\"pict-flow-container\" id=\"Flow-Wrapper-{~D:Record.ViewIdentifier~}\">\n\t<div id=\"Flow-Toolbar-{~D:Record.ViewIdentifier~}\"></div>\n\t<div id=\"Flow-FloatingToolbar-Container-{~D:Record.ViewIdentifier~}\" style=\"display:none;position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:100;\"></div>\n\t<div class=\"pict-flow-svg-container\" id=\"Flow-SVG-Container-{~D:Record.ViewIdentifier~}\">\n\t\t<svg class=\"pict-flow-svg\"\n\t\t\tid=\"Flow-SVG-{~D:Record.ViewIdentifier~}\"\n\t\t\txmlns=\"http://www.w3.org/2000/svg\">\n\t\t\t<defs>\n\t\t\t\t<pattern id=\"flow-grid-{~D:Record.ViewIdentifier~}\"\n\t\t\t\t\twidth=\"20\" height=\"20\" patternUnits=\"userSpaceOnUse\">\n\t\t\t\t\t<line x1=\"20\" y1=\"0\" x2=\"20\" y2=\"20\" class=\"pict-flow-grid-pattern\" />\n\t\t\t\t\t<line x1=\"0\" y1=\"20\" x2=\"20\" y2=\"20\" class=\"pict-flow-grid-pattern\" />\n\t\t\t\t</pattern>\n\t\t\t</defs>\n\t\t\t<rect width=\"10000\" height=\"10000\" x=\"-5000\" y=\"-5000\"\n\t\t\t\tfill=\"url(#flow-grid-{~D:Record.ViewIdentifier~})\"\n\t\t\t\tclass=\"pict-flow-grid-background\" />\n\t\t\t<g class=\"pict-flow-viewport\" id=\"Flow-Viewport-{~D:Record.ViewIdentifier~}\">\n\t\t\t\t<g class=\"pict-flow-connections-layer\" id=\"Flow-Connections-{~D:Record.ViewIdentifier~}\"></g>\n\t\t\t\t<g class=\"pict-flow-nodes-layer\" id=\"Flow-Nodes-{~D:Record.ViewIdentifier~}\"></g>\n\t\t\t\t<g class=\"pict-flow-tethers-layer\" id=\"Flow-Tethers-{~D:Record.ViewIdentifier~}\"></g>\n\t\t\t\t<g class=\"pict-flow-panels-layer\" id=\"Flow-Panels-{~D:Record.ViewIdentifier~}\"></g>\n\t\t\t</g>\n\t\t</svg>\n\t</div>\n</div>\n"}],Renderables:[{RenderableHash:'Flow-Container',TemplateHash:'Flow-Container-Template',DestinationAddress:'#Flow-Container',RenderMethod:'replace'}]};var PictViewFlow=/*#__PURE__*/function(_libPictView5){function PictViewFlow(pFable,pOptions,pServiceHash){var _this66;_classCallCheck(this,PictViewFlow);var tmpOptions=Object.assign({},JSON.parse(JSON.stringify(_DefaultConfiguration)),pOptions);_this66=_callSuper(this,PictViewFlow,[pFable,tmpOptions,pServiceHash]);_this66.serviceType='PictSectionFlow';// ---- Declarative service registry ----
2629
+ // Each entry defines a service to register, instantiate, and guard.
2630
+ // Optional flags:
2631
+ // NoFlowView — instantiate without { FlowView: this }
2632
+ // PostInit — method name to call on the instance after creation
2633
+ // RegisterOnly — only register the type; do not bulk-instantiate
2634
+ _this66._ServiceRegistry=[// Providers (stateless or config-only — no FlowView needed)
2635
+ {ServiceType:'PictProviderFlowSVGHelpers',Library:libPictProviderFlowSVGHelpers,Property:'_SVGHelperProvider',NoFlowView:true},{ServiceType:'PictProviderFlowGeometry',Library:libPictProviderFlowGeometry,Property:'_GeometryProvider',NoFlowView:true},{ServiceType:'PictProviderFlowNoise',Library:libPictProviderFlowNoise,Property:'_NoiseProvider',NoFlowView:true},// Providers (need FlowView)
2636
+ {ServiceType:'PictProviderFlowTheme',Library:libPictProviderFlowTheme,Property:'_ThemeProvider'},{ServiceType:'PictProviderFlowCSS',Library:libPictProviderFlowCSS,Property:'_CSSProvider',PostInit:'registerCSS'},{ServiceType:'PictProviderFlowIcons',Library:libPictProviderFlowIcons,Property:'_IconProvider',PostInit:'registerIconTemplates'},{ServiceType:'PictProviderFlowConnectorShapes',Library:libPictProviderFlowConnectorShapes,Property:'_ConnectorShapesProvider'},{ServiceType:'PictProviderFlowPanelChrome',Library:libPictProviderFlowPanelChrome,Property:'_PanelChromeProvider'},{ServiceType:'PictProviderFlowNodeTypes',Library:libPictProviderFlowNodeTypes,Property:'_NodeTypeProvider',ExtraOptions:function ExtraOptions(){return{AdditionalNodeTypes:_this66.options.NodeTypes,IncludeDefaultNodeTypes:_this66.options.IncludeDefaultNodeTypes};}},{ServiceType:'PictProviderFlowEventHandler',Library:libPictProviderFlowEventHandler,Property:'_EventHandlerProvider'},{ServiceType:'PictProviderFlowLayouts',Library:libPictProviderFlowLayouts,Property:'_LayoutProvider',PostInit:'loadPersistedLayouts'},// Services
2637
+ {ServiceType:'PictServiceFlowPathGenerator',Library:libPictServiceFlowPathGenerator,Property:'_PathGenerator'},{ServiceType:'PictServiceFlowDataManager',Library:libPictServiceFlowDataManager,Property:'_DataManager'},{ServiceType:'PictServiceFlowConnectionHandleManager',Library:libPictServiceFlowConnectionHandleManager,Property:'_ConnectionHandleManager'},{ServiceType:'PictServiceFlowRenderManager',Library:libPictServiceFlowRenderManager,Property:'_RenderManager'},{ServiceType:'PictServiceFlowPortRenderer',Library:libPictServiceFlowPortRenderer,Property:'_PortRenderer'},{ServiceType:'PictServiceFlowInteractionManager',Library:libPictServiceFlowInteractionManager,Property:'_InteractionManager'},{ServiceType:'PictServiceFlowConnectionRenderer',Library:libPictServiceFlowConnectionRenderer,Property:'_ConnectionRenderer'},{ServiceType:'PictServiceFlowTether',Library:libPictServiceFlowTether,Property:'_TetherService'},{ServiceType:'PictServiceFlowLayout',Library:libPictServiceFlowLayout,Property:'_LayoutService'},{ServiceType:'PictServiceFlowViewportManager',Library:libPictServiceFlowViewportManager,Property:'_ViewportManager'},{ServiceType:'PictServiceFlowSelectionManager',Library:libPictServiceFlowSelectionManager,Property:'_SelectionManager'},{ServiceType:'PictServiceFlowPanelManager',Library:libPictServiceFlowPanelManager,Property:'_PanelManager'},// View types (register only — instantiated with custom config in onAfterInitialRender)
2638
+ {ServiceType:'PictViewFlowNode',Library:libPictViewFlowNode,RegisterOnly:true},{ServiceType:'PictViewFlowToolbar',Library:libPictViewFlowToolbar,RegisterOnly:true},{ServiceType:'PictViewFlowFloatingToolbar',Library:libPictViewFlowFloatingToolbar,RegisterOnly:true},{ServiceType:'PictViewFlowPropertiesPanel',Library:libPictViewFlowPropertiesPanel,RegisterOnly:true},// Panel types (register only)
2639
+ {ServiceType:'PictFlowCardPropertiesPanel',Library:libPictFlowCardPropertiesPanel,RegisterOnly:true},{ServiceType:'PictFlowCardPropertiesPanel-Template',Library:libPanelTemplate,RegisterOnly:true},{ServiceType:'PictFlowCardPropertiesPanel-Markdown',Library:libPanelMarkdown,RegisterOnly:true},{ServiceType:'PictFlowCardPropertiesPanel-Form',Library:libPanelForm,RegisterOnly:true},{ServiceType:'PictFlowCardPropertiesPanel-View',Library:libPanelView,RegisterOnly:true}];_this66._registerServiceTypes();// Internal state
2640
+ _this66._FlowData={Nodes:[],Connections:[],OpenPanels:[],SavedLayouts:[],ViewState:{PanX:0,PanY:0,Zoom:1,SelectedNodeHash:null,SelectedConnectionHash:null,SelectedTetherHash:null}};_this66._SVGElement=null;_this66._ViewportElement=null;_this66._NodesLayer=null;_this66._ConnectionsLayer=null;_this66._TethersLayer=null;_this66._PanelsLayer=null;_this66._DataManager=null;_this66._ConnectionHandleManager=null;_this66._RenderManager=null;_this66._PortRenderer=null;_this66._InteractionManager=null;_this66._ConnectionRenderer=null;_this66._TetherService=null;_this66._LayoutService=null;_this66._PathGenerator=null;_this66._ViewportManager=null;_this66._SelectionManager=null;_this66._PanelManager=null;_this66._CSSProvider=null;_this66._IconProvider=null;_this66._ConnectorShapesProvider=null;_this66._ThemeProvider=null;_this66._NoiseProvider=null;_this66._SVGHelperProvider=null;_this66._GeometryProvider=null;_this66._PanelChromeProvider=null;_this66._NodeTypeProvider=null;_this66._LayoutProvider=null;_this66._EventHandlerProvider=null;_this66._NodeView=null;_this66._ToolbarView=null;_this66._PropertiesPanelView=null;_this66.initialRenderComplete=false;return _this66;}_inherits(PictViewFlow,_libPictView5);return _createClass(PictViewFlow,[{key:"_registerServiceTypes",value:function _registerServiceTypes(){for(var i=0;i<this._ServiceRegistry.length;i++){var tmpEntry=this._ServiceRegistry[i];if(!this.fable.servicesMap.hasOwnProperty(tmpEntry.ServiceType)){this.fable.addServiceType(tmpEntry.ServiceType,tmpEntry.Library);}}}},{key:"_instantiateServices",value:function _instantiateServices(){for(var i=0;i<this._ServiceRegistry.length;i++){var tmpEntry=this._ServiceRegistry[i];if(tmpEntry.RegisterOnly)continue;if(this[tmpEntry.Property])continue;var tmpOptions=tmpEntry.NoFlowView?{}:{FlowView:this};if(typeof tmpEntry.ExtraOptions==='function'){Object.assign(tmpOptions,tmpEntry.ExtraOptions());}this[tmpEntry.Property]=this.fable.instantiateServiceProviderWithoutRegistration(tmpEntry.ServiceType,tmpOptions);if(tmpEntry.PostInit&&typeof this[tmpEntry.Property][tmpEntry.PostInit]==='function'){this[tmpEntry.Property][tmpEntry.PostInit]();}}}},{key:"flowData",get:function get(){return this._FlowData;}},{key:"viewState",get:function get(){return this._FlowData.ViewState;}// Backward-compatible getter for InteractionManager direct access
2641
+ },{key:"_IsFullscreen",get:function get(){return this._ViewportManager?this._ViewportManager._IsFullscreen:false;}/**
2642
+ * Override render to pass view options as the template record,
2643
+ * so template expressions like {~D:Record.ViewIdentifier~} resolve correctly.
2644
+ */},{key:"render",value:function render(pRenderableHash,pRenderDestinationAddress){return _superPropGet(PictViewFlow,"render",this,3)([pRenderableHash,pRenderDestinationAddress,this.options]);}},{key:"renderAsync",value:function renderAsync(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,pRootRenderable,fCallback){// If no record address is explicitly provided, use this.options as the record
2645
+ if(typeof pTemplateRecordAddress==='function'||typeof pTemplateRecordAddress==='undefined'){return _superPropGet(PictViewFlow,"renderAsync",this,3)([pRenderableHash,pRenderDestinationAddress,this.options,pRootRenderable,pTemplateRecordAddress||fCallback]);}return _superPropGet(PictViewFlow,"renderAsync",this,3)([pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,pRootRenderable,fCallback]);}},{key:"onBeforeInitialize",value:function onBeforeInitialize(){_superPropGet(PictViewFlow,"onBeforeInitialize",this,3)([]);// Theme + Noise must be created first (CSS PostInit depends on theme state)
2646
+ this._ThemeProvider=this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowTheme',{FlowView:this});this._NoiseProvider=this.fable.instantiateServiceProviderWithoutRegistration('PictProviderFlowNoise');// Apply initial theme from options
2647
+ if(this.options.Theme){this._ThemeProvider.setTheme(this.options.Theme);}if(typeof this.options.NoiseLevel==='number'){this._ThemeProvider.setNoiseLevel(this.options.NoiseLevel);}// Instantiate all remaining services (skips Theme + Noise since already set)
2648
+ this._instantiateServices();return _superPropGet(PictViewFlow,"onBeforeInitialize",this,3)([]);}},{key:"onAfterRender",value:function onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent){if(!this.initialRenderComplete){this.onAfterInitialRender();this.initialRenderComplete=true;}return _superPropGet(PictViewFlow,"onAfterRender",this,3)([pRenderable,pRenderDestinationAddress,pRecord,pContent]);}},{key:"onAfterInitialRender",value:function onAfterInitialRender(){var tmpViewIdentifier=this.options.ViewIdentifier;// Grab SVG DOM elements
2649
+ var tmpSVGElements=this.pict.ContentAssignment.getElement("#Flow-SVG-".concat(tmpViewIdentifier));if(tmpSVGElements.length<1){this.log.error("PictSectionFlow could not find SVG element #Flow-SVG-".concat(tmpViewIdentifier));return false;}this._SVGElement=tmpSVGElements[0];var tmpViewportElements=this.pict.ContentAssignment.getElement("#Flow-Viewport-".concat(tmpViewIdentifier));if(tmpViewportElements.length>0){this._ViewportElement=tmpViewportElements[0];}var tmpNodesElements=this.pict.ContentAssignment.getElement("#Flow-Nodes-".concat(tmpViewIdentifier));if(tmpNodesElements.length>0){this._NodesLayer=tmpNodesElements[0];}var tmpConnectionsElements=this.pict.ContentAssignment.getElement("#Flow-Connections-".concat(tmpViewIdentifier));if(tmpConnectionsElements.length>0){this._ConnectionsLayer=tmpConnectionsElements[0];}var tmpTethersElements=this.pict.ContentAssignment.getElement("#Flow-Tethers-".concat(tmpViewIdentifier));if(tmpTethersElements.length>0){this._TethersLayer=tmpTethersElements[0];}var tmpPanelsElements=this.pict.ContentAssignment.getElement("#Flow-Panels-".concat(tmpViewIdentifier));if(tmpPanelsElements.length>0){this._PanelsLayer=tmpPanelsElements[0];}// Ensure all services are initialized (fallback if onBeforeInitialize was skipped)
2650
+ this._instantiateServices();// Inject marker defs via the connector shapes provider
2651
+ // Note: insertAdjacentHTML does not work on SVG elements (wrong namespace),
2652
+ // so we parse via a temporary <svg> element to ensure SVG namespace.
2653
+ if(this._ConnectorShapesProvider&&this._SVGElement){var tmpDefs=this._SVGElement.querySelector('defs');if(tmpDefs){var tmpMarkerMarkup=this._ConnectorShapesProvider.generateMarkerDefs(tmpViewIdentifier);var tmpTempSVG=document.createElementNS('http://www.w3.org/2000/svg','svg');tmpTempSVG.innerHTML=tmpMarkerMarkup;while(tmpTempSVG.firstChild){tmpDefs.appendChild(tmpTempSVG.firstChild);}}}// Setup the toolbar if enabled
2654
+ if(this.options.EnableToolbar){this._ToolbarView=this.fable.instantiateServiceProviderWithoutRegistration('PictViewFlowToolbar',Object.assign({},libPictViewFlowToolbar.default_configuration,{ViewIdentifier:"Flow-Toolbar-".concat(tmpViewIdentifier),DefaultDestinationAddress:"#Flow-Toolbar-".concat(tmpViewIdentifier),FlowViewIdentifier:tmpViewIdentifier,EnableAddNode:this.options.EnableAddNode,EnableCardPalette:this.options.EnableCardPalette}));// Use the toolbar's render method after it's set up
2655
+ if(this._ToolbarView&&typeof this._ToolbarView.render==='function'){this._ToolbarView._FlowView=this;this._ToolbarView.render();}}// Setup the node renderer
2656
+ this._NodeView=this.fable.instantiateServiceProviderWithoutRegistration('PictViewFlowNode',Object.assign({},libPictViewFlowNode.default_configuration,{ViewIdentifier:"Flow-NodeRenderer-".concat(tmpViewIdentifier),AutoRender:false}));this._NodeView._FlowView=this;// Setup the properties panel renderer
2657
+ this._PropertiesPanelView=this.fable.instantiateServiceProviderWithoutRegistration('PictViewFlowPropertiesPanel',Object.assign({},libPictViewFlowPropertiesPanel.default_configuration,{ViewIdentifier:"Flow-PropertiesPanel-".concat(tmpViewIdentifier),AutoRender:false}));this._PropertiesPanelView._FlowView=this;// Bind interaction events
2658
+ this._InteractionManager.initialize(this._SVGElement,this._ViewportElement);// Load initial flow data if an address is configured
2659
+ if(this.options.FlowDataAddress){this.marshalToView();}// Render the initial flow
2660
+ this.renderFlow();}// ---- Data Manager Delegations ----
2661
+ },{key:"marshalToView",value:function marshalToView(){return this._DataManager.marshalToView();}},{key:"marshalFromView",value:function marshalFromView(){return this._DataManager.marshalFromView();}},{key:"getFlowData",value:function getFlowData(){return this._DataManager.getFlowData();}},{key:"setFlowData",value:function setFlowData(pFlowData){return this._DataManager.setFlowData(pFlowData);}},{key:"addNode",value:function addNode(pType,pX,pY,pTitle,pData){return this._DataManager.addNode(pType,pX,pY,pTitle,pData);}},{key:"removeNode",value:function removeNode(pNodeHash){return this._DataManager.removeNode(pNodeHash);}},{key:"addConnection",value:function addConnection(pSourceNodeHash,pSourcePortHash,pTargetNodeHash,pTargetPortHash,pData){return this._DataManager.addConnection(pSourceNodeHash,pSourcePortHash,pTargetNodeHash,pTargetPortHash,pData);}},{key:"removeConnection",value:function removeConnection(pConnectionHash){return this._DataManager.removeConnection(pConnectionHash);}/**
2662
+ * Select a node
2663
+ * @param {string|null} pNodeHash - Hash of the node to select, or null to deselect
2664
+ */},{key:"selectNode",value:function selectNode(pNodeHash){return this._SelectionManager.selectNode(pNodeHash);}/**
2665
+ * Select a connection
2666
+ * @param {string|null} pConnectionHash - Hash of the connection to select, or null to deselect
2667
+ */},{key:"selectConnection",value:function selectConnection(pConnectionHash){return this._SelectionManager.selectConnection(pConnectionHash);}/**
2668
+ * Deselect all nodes and connections
2669
+ */},{key:"deselectAll",value:function deselectAll(){return this._SelectionManager.deselectAll();}/**
2670
+ * Delete the currently selected node or connection
2671
+ * @returns {boolean}
2672
+ */},{key:"deleteSelected",value:function deleteSelected(){return this._SelectionManager.deleteSelected();}/**
2673
+ * Update the viewport transform (pan and zoom)
2674
+ */},{key:"updateViewportTransform",value:function updateViewportTransform(){return this._ViewportManager.updateViewportTransform();}/**
2675
+ * Set zoom level
2676
+ * @param {number} pZoom - The zoom level
2677
+ * @param {number} [pFocusX] - X coordinate to zoom toward (SVG space)
2678
+ * @param {number} [pFocusY] - Y coordinate to zoom toward (SVG space)
2679
+ */},{key:"setZoom",value:function setZoom(pZoom,pFocusX,pFocusY){return this._ViewportManager.setZoom(pZoom,pFocusX,pFocusY);}/**
2680
+ * Zoom to fit all nodes in the viewport
2681
+ */},{key:"zoomToFit",value:function zoomToFit(){return this._ViewportManager.zoomToFit();}/**
2682
+ * Apply auto-layout to all nodes
2683
+ */},{key:"autoLayout",value:function autoLayout(){if(this._LayoutService){this._LayoutService.autoLayout(this._FlowData.Nodes,this._FlowData.Connections);this.renderFlow();this.marshalFromView();if(this._EventHandlerProvider){this._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowData);}}}/**
2684
+ * Toggle fullscreen mode on the flow editor container.
2685
+ * Uses a CSS fixed-position overlay instead of the Fullscreen API.
2686
+ * @returns {boolean} The new fullscreen state
2687
+ */},{key:"toggleFullscreen",value:function toggleFullscreen(){return this._ViewportManager.toggleFullscreen();}/**
2688
+ * Exit fullscreen mode if currently active.
2689
+ */},{key:"exitFullscreen",value:function exitFullscreen(){return this._ViewportManager.exitFullscreen();}// ── Theme API ────────────────────────────────────────────────────────
2690
+ /**
2691
+ * Switch the active theme and re-render.
2692
+ * @param {string} pThemeKey - Theme key (e.g. 'default', 'sketch', 'blueprint', 'mono', 'retro-80s', 'retro-90s')
2693
+ */},{key:"setTheme",value:function setTheme(pThemeKey){if(!this._ThemeProvider){this.log.warn('PictSectionFlow setTheme: ThemeProvider not available');return;}var tmpApplied=this._ThemeProvider.setTheme(pThemeKey);if(!tmpApplied)return;// Re-register CSS with the new theme overrides
2694
+ if(this._CSSProvider){this._CSSProvider.registerCSS();}// Re-inject marker defs (arrowhead colors may have changed)
2695
+ this._reinjectMarkerDefs();// Full re-render
2696
+ if(this.initialRenderComplete){this.renderFlow();}if(this._EventHandlerProvider){this._EventHandlerProvider.fireEvent('onThemeChanged',pThemeKey);}}/**
2697
+ * Set the noise level (0 to 1) and re-render.
2698
+ * @param {number} pLevel - 0 = precise, 1 = maximum wobble
2699
+ */},{key:"setNoiseLevel",value:function setNoiseLevel(pLevel){if(!this._ThemeProvider){this.log.warn('PictSectionFlow setNoiseLevel: ThemeProvider not available');return;}this._ThemeProvider.setNoiseLevel(pLevel);// Full re-render to apply new noise
2700
+ if(this.initialRenderComplete){this.renderFlow();}}/**
2701
+ * Get the current noise level (0 to 1).
2702
+ * @returns {number}
2703
+ */},{key:"getNoiseLevel",value:function getNoiseLevel(){if(this._ThemeProvider){return this._ThemeProvider.getNoiseLevel();}return 0;}/**
2704
+ * Get the active theme key.
2705
+ * @returns {string}
2706
+ */},{key:"getThemeKey",value:function getThemeKey(){if(this._ThemeProvider){return this._ThemeProvider.getActiveThemeKey();}return'default';}},{key:"_reinjectMarkerDefs",value:function _reinjectMarkerDefs(){return this._RenderManager.reinjectMarkerDefs();}/**
2707
+ * Get a node by hash
2708
+ * @param {string} pNodeHash
2709
+ * @returns {Object|null}
2710
+ */},{key:"getNode",value:function getNode(pNodeHash){return this._FlowData.Nodes.find(function(pNode){return pNode.Hash===pNodeHash;})||null;}/**
2711
+ * Get a connection by hash
2712
+ * @param {string} pConnectionHash
2713
+ * @returns {Object|null}
2714
+ */},{key:"getConnection",value:function getConnection(pConnectionHash){return this._FlowData.Connections.find(function(pConn){return pConn.Hash===pConnectionHash;})||null;}/**
2715
+ * Select a tether by its panel hash.
2716
+ * @param {string|null} pPanelHash - Hash of the panel whose tether to select, or null to deselect
2717
+ */},{key:"selectTether",value:function selectTether(pPanelHash){return this._SelectionManager.selectTether(pPanelHash);}// ---- Connection Handle Manager Delegations ----
2718
+ },{key:"updateConnectionHandle",value:function updateConnectionHandle(pConnectionHash,pHandleType,pX,pY){return this._ConnectionHandleManager.updateConnectionHandle(pConnectionHash,pHandleType,pX,pY);}},{key:"addConnectionHandle",value:function addConnectionHandle(pConnectionHash,pX,pY){return this._ConnectionHandleManager.addConnectionHandle(pConnectionHash,pX,pY);}},{key:"removeConnectionHandle",value:function removeConnectionHandle(pConnectionHash,pIndex){return this._ConnectionHandleManager.removeConnectionHandle(pConnectionHash,pIndex);}},{key:"_resetHandlesForNode",value:function _resetHandlesForNode(pNodeHash){return this._ConnectionHandleManager.resetHandlesForNode(pNodeHash);}},{key:"_resetHandlesForPanel",value:function _resetHandlesForPanel(pPanelHash){return this._ConnectionHandleManager.resetHandlesForPanel(pPanelHash);}/**
2719
+ * Add a bezier handle to a tether at the specified SVG position.
2720
+ * @param {string} pPanelHash
2721
+ * @param {number} pX
2722
+ * @param {number} pY
2723
+ */},{key:"addTetherHandle",value:function addTetherHandle(pPanelHash,pX,pY){var tmpPanel=this._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===pPanelHash;});if(!tmpPanel||!this._TetherService)return;var tmpNode=this.getNode(tmpPanel.NodeHash);if(!tmpNode)return;var tmpAnchors=this._TetherService.getSmartAnchors(tmpPanel,tmpNode);this._TetherService.addHandle(tmpPanel,pX,pY,tmpAnchors.panelAnchor,tmpAnchors.nodeAnchor);this.renderFlow();this.marshalFromView();if(this._EventHandlerProvider){this._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowData);}}/**
2724
+ * Remove a bezier handle from a tether by index.
2725
+ * @param {string} pPanelHash
2726
+ * @param {number} pIndex
2727
+ */},{key:"removeTetherHandle",value:function removeTetherHandle(pPanelHash,pIndex){var tmpPanel=this._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===pPanelHash;});if(!tmpPanel||!this._TetherService)return;this._TetherService.removeHandle(tmpPanel,pIndex);this.renderFlow();this.marshalFromView();if(this._EventHandlerProvider){this._EventHandlerProvider.fireEvent('onFlowChanged',this._FlowData);}}/**
2728
+ * Update a tether handle position during drag (for real-time feedback).
2729
+ * Delegates state update to the TetherService.
2730
+ * @param {string} pPanelHash
2731
+ * @param {string} pHandleType
2732
+ * @param {number} pX
2733
+ * @param {number} pY
2734
+ */},{key:"updateTetherHandle",value:function updateTetherHandle(pPanelHash,pHandleType,pX,pY){var tmpPanel=this._FlowData.OpenPanels.find(function(pPanel){return pPanel.Hash===pPanelHash;});if(!tmpPanel)return;if(this._TetherService){this._TetherService.updateHandlePosition(tmpPanel,pHandleType,pX,pY);}this._renderSingleTether(pPanelHash);}/**
2735
+ * Get a port's absolute position in SVG coordinates.
2736
+ *
2737
+ * For left and right side ports, positioning is offset below the title bar
2738
+ * so that connection endpoints match the rendered port circles.
2739
+ *
2740
+ * @param {string} pNodeHash
2741
+ * @param {string} pPortHash
2742
+ * @returns {{x: number, y: number, side: string}|null}
2743
+ */},{key:"getPortPosition",value:function getPortPosition(pNodeHash,pPortHash){var tmpNode=this.getNode(pNodeHash);if(!tmpNode)return null;var tmpPort=tmpNode.Ports.find(function(p){return p.Hash===pPortHash;});if(!tmpPort)return null;// Count ports on the same side (matching both direction and side)
2744
+ var tmpSameSidePorts=tmpNode.Ports.filter(function(p){return p.Side===tmpPort.Side;});var tmpPortIndex=tmpSameSidePorts.indexOf(tmpPort);var tmpPortCount=tmpSameSidePorts.length;var tmpTitleBarHeight=this._NodeView&&this._NodeView.options.NodeTitleBarHeight||28;// Use the adjusted node height that accounts for minimum port
2745
+ // spacing. Connections render before nodes, so the node renderer
2746
+ // may not have written back its adjusted height yet.
2747
+ var tmpHeight=tmpNode.Height||80;if(this._GeometryProvider&&tmpNode.Ports&&tmpNode.Ports.length>0){var tmpMinHeight=this._GeometryProvider.computeMinimumNodeHeight(tmpNode.Ports,tmpTitleBarHeight);if(tmpMinHeight>tmpHeight){tmpHeight=tmpMinHeight;}}// Build port counts map for adaptive zone sizing
2748
+ var tmpPortCountsBySide=this._GeometryProvider.buildPortCountsBySide(tmpNode.Ports);var tmpLocal=this._GeometryProvider.getPortLocalPosition(tmpPort.Side,tmpPortIndex,tmpPortCount,tmpNode.Width,tmpHeight,tmpTitleBarHeight,tmpPortCountsBySide);return{x:tmpNode.X+tmpLocal.x,y:tmpNode.Y+tmpLocal.y,side:tmpPort.Side||'right'};}/**
2749
+ * Convert screen coordinates to SVG viewport coordinates
2750
+ * @param {number} pScreenX
2751
+ * @param {number} pScreenY
2752
+ * @returns {{x: number, y: number}}
2753
+ */},{key:"screenToSVGCoords",value:function screenToSVGCoords(pScreenX,pScreenY){return this._ViewportManager.screenToSVGCoords(pScreenX,pScreenY);}// ---- Render Manager Delegations ----
2754
+ },{key:"renderFlow",value:function renderFlow(){return this._RenderManager.renderFlow();}},{key:"_renderSingleConnection",value:function _renderSingleConnection(pConnectionHash){return this._RenderManager.renderSingleConnection(pConnectionHash);}},{key:"_renderSingleTether",value:function _renderSingleTether(pPanelHash){return this._RenderManager.renderSingleTether(pPanelHash);}},{key:"updateNodePosition",value:function updateNodePosition(pNodeHash,pX,pY){return this._RenderManager.updateNodePosition(pNodeHash,pX,pY);}},{key:"_renderConnectionsForNode",value:function _renderConnectionsForNode(pNodeHash){return this._RenderManager.renderConnectionsForNode(pNodeHash);}},{key:"_renderTethersForNode",value:function _renderTethersForNode(pNodeHash){return this._RenderManager.renderTethersForNode(pNodeHash);}// ---- Properties Panel Management ----
2755
+ /**
2756
+ * Open a properties panel for a node.
2757
+ * @param {string} pNodeHash - The hash of the node to open a panel for
2758
+ * @returns {Object|false} The panel data, or false if the node has no PropertiesPanel config
2759
+ */},{key:"openPanel",value:function openPanel(pNodeHash){return this._PanelManager.openPanel(pNodeHash);}/**
2760
+ * Close a properties panel by panel hash.
2761
+ * @param {string} pPanelHash
2762
+ * @returns {boolean}
2763
+ */},{key:"closePanel",value:function closePanel(pPanelHash){return this._PanelManager.closePanel(pPanelHash);}/**
2764
+ * Close all panels for a given node.
2765
+ * @param {string} pNodeHash
2766
+ * @returns {boolean}
2767
+ */},{key:"closePanelForNode",value:function closePanelForNode(pNodeHash){return this._PanelManager.closePanelForNode(pNodeHash);}/**
2768
+ * Toggle a properties panel for a node (open if closed, close if open).
2769
+ * @param {string} pNodeHash
2770
+ * @returns {Object|false}
2771
+ */},{key:"togglePanel",value:function togglePanel(pNodeHash){return this._PanelManager.togglePanel(pNodeHash);}/**
2772
+ * Update a panel's position (for drag).
2773
+ * @param {string} pPanelHash
2774
+ * @param {number} pX
2775
+ * @param {number} pY
2776
+ */},{key:"updatePanelPosition",value:function updatePanelPosition(pPanelHash,pX,pY){return this._PanelManager.updatePanelPosition(pPanelHash,pX,pY);}}]);}(libPictView);module.exports=PictViewFlow;module.exports.default_configuration=_DefaultConfiguration;},{"../PictFlowCardPropertiesPanel.js":11,"../panels/FlowCardPropertiesPanel-Form.js":12,"../panels/FlowCardPropertiesPanel-Markdown.js":13,"../panels/FlowCardPropertiesPanel-Template.js":14,"../panels/FlowCardPropertiesPanel-View.js":15,"../providers/PictProvider-Flow-CSS.js":16,"../providers/PictProvider-Flow-ConnectorShapes.js":17,"../providers/PictProvider-Flow-EventHandler.js":18,"../providers/PictProvider-Flow-Geometry.js":19,"../providers/PictProvider-Flow-Icons.js":20,"../providers/PictProvider-Flow-Layouts.js":21,"../providers/PictProvider-Flow-NodeTypes.js":22,"../providers/PictProvider-Flow-Noise.js":23,"../providers/PictProvider-Flow-PanelChrome.js":24,"../providers/PictProvider-Flow-SVGHelpers.js":25,"../providers/PictProvider-Flow-Theme.js":26,"../services/PictService-Flow-ConnectionHandleManager.js":27,"../services/PictService-Flow-ConnectionRenderer.js":28,"../services/PictService-Flow-DataManager.js":29,"../services/PictService-Flow-InteractionManager.js":30,"../services/PictService-Flow-Layout.js":31,"../services/PictService-Flow-PanelManager.js":32,"../services/PictService-Flow-PathGenerator.js":33,"../services/PictService-Flow-PortRenderer.js":34,"../services/PictService-Flow-RenderManager.js":35,"../services/PictService-Flow-SelectionManager.js":36,"../services/PictService-Flow-Tether.js":37,"../services/PictService-Flow-ViewportManager.js":38,"./PictView-Flow-FloatingToolbar.js":39,"./PictView-Flow-Node.js":40,"./PictView-Flow-PropertiesPanel.js":41,"./PictView-Flow-Toolbar.js":42,"pict-view":45}],44:[function(require,module,exports){module.exports={"name":"pict-view","version":"1.0.67","description":"Pict View Base Class","main":"source/Pict-View.js","scripts":{"test":"npx quack test","tests":"npx quack test -g","start":"node source/Pict-View.js","coverage":"npx quack coverage","build":"npx quack build","docker-dev-build":"docker build ./ -f Dockerfile_LUXURYCode -t pict-view-image:local","docker-dev-run":"docker run -it -d --name pict-view-dev -p 30001:8080 -p 38086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/pict-view\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" pict-view-image:local","docker-dev-shell":"docker exec -it pict-view-dev /bin/bash","types":"tsc -p .","lint":"eslint source/**"},"types":"types/source/Pict-View.d.ts","repository":{"type":"git","url":"git+https://github.com/stevenvelozo/pict-view.git"},"author":"steven velozo <steven@velozo.com>","license":"MIT","bugs":{"url":"https://github.com/stevenvelozo/pict-view/issues"},"homepage":"https://github.com/stevenvelozo/pict-view#readme","devDependencies":{"@eslint/js":"^9.39.1","browser-env":"^3.3.0","eslint":"^9.39.1","pict":"^1.0.348","quackage":"^1.0.58","typescript":"^5.9.3"},"mocha":{"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"dependencies":{"fable":"^3.1.63","fable-serviceproviderbase":"^3.0.19"}};},{}],45:[function(require,module,exports){var libFableServiceBase=require('fable-serviceproviderbase');var libPackage=require('../package.json');var defaultPictViewSettings={DefaultRenderable:false,DefaultDestinationAddress:false,DefaultTemplateRecordAddress:false,ViewIdentifier:false,// If this is set to true, when the App initializes this will.
2777
+ // After the App initializes, initialize will be called as soon as it's added.
2778
+ AutoInitialize:true,AutoInitializeOrdinal:0,// If this is set to true, when the App autorenders (on load) this will.
2779
+ // After the App initializes, render will be called as soon as it's added.
2780
+ AutoRender:true,AutoRenderOrdinal:0,AutoSolveWithApp:true,AutoSolveOrdinal:0,CSSHash:false,CSS:false,CSSProvider:false,CSSPriority:500,Templates:[],DefaultTemplates:[],Renderables:[],Manifests:{}};/** @typedef {(error?: Error) => void} ErrorCallback *//** @typedef {number | boolean} PictTimestamp *//**
2781
+ * @typedef {'replace' | 'append' | 'prepend' | 'append_once' | 'virtual-assignment'} RenderMethod
2782
+ *//**
2783
+ * @typedef {Object} Renderable
2784
+ *
2785
+ * @property {string} RenderableHash - A unique hash for the renderable.
2786
+ * @property {string} TemplateHash - The hash of the template to use for rendering this renderable.
2787
+ * @property {string} [DefaultTemplateRecordAddress] - The default address for resolving the data record for this renderable.
2788
+ * @property {string} [ContentDestinationAddress] - The default address (DOM CSS selector) for rendering the content of this renderable.
2789
+ * @property {RenderMethod} [RenderMethod=replace] - The method to use when projecting the renderable to the DOM ('replace', 'append', 'prepend', 'append_once', 'virtual-assignment').
2790
+ * @property {string} [TestAddress] - The address to use for testing the renderable.
2791
+ * @property {string} [TransactionHash] - The transaction hash for the root renderable.
2792
+ * @property {string} [RootRenderableViewHash] - The hash of the root renderable.
2793
+ * @property {string} [Content] - The rendered content for this renderable, if applicable.
2794
+ *//**
2795
+ * Represents a view in the Pict ecosystem.
2796
+ */var PictView=/*#__PURE__*/function(_libFableServiceBase3){/**
2797
+ * @param {any} pFable - The Fable object that this service is attached to.
2798
+ * @param {any} [pOptions] - (optional) The options for this service.
2799
+ * @param {string} [pServiceHash] - (optional) The hash of the service.
2800
+ */function PictView(pFable,pOptions,pServiceHash){var _this67;_classCallCheck(this,PictView);// Intersect default options, parent constructor, service information
2801
+ var tmpOptions=Object.assign({},JSON.parse(JSON.stringify(defaultPictViewSettings)),pOptions);_this67=_callSuper(this,PictView,[pFable,tmpOptions,pServiceHash]);//FIXME: add types to fable and ancillaries
2802
+ /** @type {any} */_this67.fable;/** @type {any} */_this67.options;/** @type {String} */_this67.UUID;/** @type {String} */_this67.Hash;/** @type {any} */_this67.log;var tmpHashIsUUID=_this67.Hash===_this67.UUID;//NOTE: since many places are using the view UUID as the HTML element ID, we prefix it to avoid starting with a number
2803
+ _this67.UUID="V-".concat(_this67.UUID);if(tmpHashIsUUID){_this67.Hash=_this67.UUID;}if(!_this67.options.ViewIdentifier){_this67.options.ViewIdentifier="AutoViewID-".concat(_this67.fable.getUUID());}_this67.serviceType='PictView';/** @type {Record<string, any>} */_this67._Package=libPackage;// Convenience and consistency naming
2804
+ /** @type {import('pict') & { log: any, instantiateServiceProviderWithoutRegistration: (hash: String) => any, instantiateServiceProviderIfNotExists: (hash: string) => any, TransactionTracking: import('pict/types/source/services/Fable-Service-TransactionTracking') }} */_this67.pict=_this67.fable;// Wire in the essential Pict application state
2805
+ _this67.AppData=_this67.pict.AppData;_this67.Bundle=_this67.pict.Bundle;/** @type {PictTimestamp} */_this67.initializeTimestamp=false;/** @type {PictTimestamp} */_this67.lastSolvedTimestamp=false;/** @type {PictTimestamp} */_this67.lastRenderedTimestamp=false;/** @type {PictTimestamp} */_this67.lastMarshalFromViewTimestamp=false;/** @type {PictTimestamp} */_this67.lastMarshalToViewTimestamp=false;_this67.pict.instantiateServiceProviderIfNotExists('TransactionTracking');// Load all templates from the array in the options
2806
+ // Templates are in the form of {Hash:'Some-Template-Hash',Template:'Template content',Source:'TemplateSource'}
2807
+ for(var i=0;i<_this67.options.Templates.length;i++){var tmpTemplate=_this67.options.Templates[i];if(!('Hash'in tmpTemplate)||!('Template'in tmpTemplate)){_this67.log.error("PictView [".concat(_this67.UUID,"]::[").concat(_this67.Hash,"] ").concat(_this67.options.ViewIdentifier," could not load Template ").concat(i," in the options array."),tmpTemplate);}else{if(!tmpTemplate.Source){tmpTemplate.Source="PictView [".concat(_this67.UUID,"]::[").concat(_this67.Hash,"] ").concat(_this67.options.ViewIdentifier," options object.");}_this67.pict.TemplateProvider.addTemplate(tmpTemplate.Hash,tmpTemplate.Template,tmpTemplate.Source);}}// Load all default templates from the array in the options
2808
+ // Templates are in the form of {Prefix:'',Postfix:'-List-Row',Template:'Template content',Source:'TemplateSourceString'}
2809
+ for(var _i55=0;_i55<_this67.options.DefaultTemplates.length;_i55++){var tmpDefaultTemplate=_this67.options.DefaultTemplates[_i55];if(!('Postfix'in tmpDefaultTemplate)||!('Template'in tmpDefaultTemplate)){_this67.log.error("PictView [".concat(_this67.UUID,"]::[").concat(_this67.Hash,"] ").concat(_this67.options.ViewIdentifier," could not load Default Template ").concat(_i55," in the options array."),tmpDefaultTemplate);}else{if(!tmpDefaultTemplate.Source){tmpDefaultTemplate.Source="PictView [".concat(_this67.UUID,"]::[").concat(_this67.Hash,"] ").concat(_this67.options.ViewIdentifier," options object.");}_this67.pict.TemplateProvider.addDefaultTemplate(tmpDefaultTemplate.Prefix,tmpDefaultTemplate.Postfix,tmpDefaultTemplate.Template,tmpDefaultTemplate.Source);}}// Load the CSS if it's available
2810
+ if(_this67.options.CSS){var tmpCSSHash=_this67.options.CSSHash?_this67.options.CSSHash:"View-".concat(_this67.options.ViewIdentifier);var tmpCSSProvider=_this67.options.CSSProvider?_this67.options.CSSProvider:tmpCSSHash;_this67.pict.CSSMap.addCSS(tmpCSSHash,_this67.options.CSS,tmpCSSProvider,_this67.options.CSSPriority);}// Load all renderables
2811
+ // Renderables are launchable renderable instructions with templates
2812
+ // They look as such: {Identifier:'ContentEntry', TemplateHash:'Content-Entry-Section-Main', ContentDestinationAddress:'#ContentSection', RecordAddress:'AppData.Content.DefaultText', ManifestTransformation:'ManyfestHash', ManifestDestinationAddress:'AppData.Content.DataToTransformContent'}
2813
+ // The only parts that are necessary are Identifier and Template
2814
+ // A developer can then do render('ContentEntry') and it just kinda works. Or they can override the ContentDestinationAddress
2815
+ /** @type {Record<String, Renderable>} */_this67.renderables={};for(var _i56=0;_i56<_this67.options.Renderables.length;_i56++){/** @type {Renderable} */var tmpRenderable=_this67.options.Renderables[_i56];_this67.addRenderable(tmpRenderable);}return _this67;}/**
2816
+ * Adds a renderable to the view.
2817
+ *
2818
+ * @param {string | Renderable} pRenderableHash - The hash of the renderable, or a renderable object.
2819
+ * @param {string} [pTemplateHash] - (optional) The hash of the template for the renderable.
2820
+ * @param {string} [pDefaultTemplateRecordAddress] - (optional) The default data address for the template.
2821
+ * @param {string} [pDefaultDestinationAddress] - (optional) The default destination address for the renderable.
2822
+ * @param {RenderMethod} [pRenderMethod=replace] - (optional) The method to use when rendering the renderable (ex. 'replace').
2823
+ */_inherits(PictView,_libFableServiceBase3);return _createClass(PictView,[{key:"addRenderable",value:function addRenderable(pRenderableHash,pTemplateHash,pDefaultTemplateRecordAddress,pDefaultDestinationAddress,pRenderMethod){/** @type {Renderable} */var tmpRenderable;if(_typeof(pRenderableHash)=='object'){// The developer passed in the renderable as an object.
2824
+ // Use theirs instead!
2825
+ tmpRenderable=pRenderableHash;}else{/** @type {RenderMethod} */var tmpRenderMethod=typeof pRenderMethod!=='string'?pRenderMethod:'replace';tmpRenderable={RenderableHash:pRenderableHash,TemplateHash:pTemplateHash,DefaultTemplateRecordAddress:pDefaultTemplateRecordAddress,ContentDestinationAddress:pDefaultDestinationAddress,RenderMethod:tmpRenderMethod};}if(typeof tmpRenderable.RenderableHash!='string'||typeof tmpRenderable.TemplateHash!='string'){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not load Renderable; RenderableHash or TemplateHash are invalid."),tmpRenderable);}else{if(this.pict.LogNoisiness>0){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," adding renderable [").concat(tmpRenderable.RenderableHash,"] pointed to template ").concat(tmpRenderable.TemplateHash,"."));}this.renderables[tmpRenderable.RenderableHash]=tmpRenderable;}}/* -------------------------------------------------------------------------- *//* Code Section: Initialization *//* -------------------------------------------------------------------------- *//**
2826
+ * Lifecycle hook that triggers before the view is initialized.
2827
+ */},{key:"onBeforeInitialize",value:function onBeforeInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onBeforeInitialize:"));}return true;}/**
2828
+ * Lifecycle hook that triggers before the view is initialized (async flow).
2829
+ *
2830
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2831
+ */},{key:"onBeforeInitializeAsync",value:function onBeforeInitializeAsync(fCallback){this.onBeforeInitialize();return fCallback();}/**
2832
+ * Lifecycle hook that triggers when the view is initialized.
2833
+ */},{key:"onInitialize",value:function onInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onInitialize:"));}return true;}/**
2834
+ * Lifecycle hook that triggers when the view is initialized (async flow).
2835
+ *
2836
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2837
+ */},{key:"onInitializeAsync",value:function onInitializeAsync(fCallback){this.onInitialize();return fCallback();}/**
2838
+ * Performs view initialization.
2839
+ */},{key:"initialize",value:function initialize(){if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow VIEW [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," initialize:"));}if(!this.initializeTimestamp){this.onBeforeInitialize();this.onInitialize();this.onAfterInitialize();this.initializeTimestamp=this.pict.log.getTimeStamp();return true;}else{this.log.warn("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," initialize called but initialization is already completed. Aborting."));return false;}}/**
2840
+ * Performs view initialization (async flow).
2841
+ *
2842
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2843
+ */},{key:"initializeAsync",value:function initializeAsync(fCallback){var _this68=this;if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow VIEW [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," initializeAsync:"));}if(!this.initializeTimestamp){var tmpAnticipate=this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');if(this.pict.LogNoisiness>0){this.log.info("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," beginning initialization..."));}tmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));tmpAnticipate.anticipate(this.onInitializeAsync.bind(this));tmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));tmpAnticipate.wait(/** @param {Error} pError */function(pError){if(pError){_this68.log.error("PictView [".concat(_this68.UUID,"]::[").concat(_this68.Hash,"] ").concat(_this68.options.ViewIdentifier," initialization failed: ").concat(pError.message||pError),{stack:pError.stack});}_this68.initializeTimestamp=_this68.pict.log.getTimeStamp();if(_this68.pict.LogNoisiness>0){_this68.log.info("PictView [".concat(_this68.UUID,"]::[").concat(_this68.Hash,"] ").concat(_this68.options.ViewIdentifier," initialization complete."));}return fCallback();});}else{this.log.warn("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," async initialize called but initialization is already completed. Aborting."));// TODO: Should this be an error?
2844
+ return fCallback();}}},{key:"onAfterInitialize",value:function onAfterInitialize(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterInitialize:"));}return true;}/**
2845
+ * Lifecycle hook that triggers after the view is initialized (async flow).
2846
+ *
2847
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2848
+ */},{key:"onAfterInitializeAsync",value:function onAfterInitializeAsync(fCallback){this.onAfterInitialize();return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Render *//* -------------------------------------------------------------------------- *//**
2849
+ * Lifecycle hook that triggers before the view is rendered.
2850
+ *
2851
+ * @param {Renderable} pRenderable - The renderable that will be rendered.
2852
+ */},{key:"onBeforeRender",value:function onBeforeRender(pRenderable){// Overload this to mess with stuff before the content gets generated from the template
2853
+ if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onBeforeRender:"));}return true;}/**
2854
+ * Lifecycle hook that triggers before the view is rendered (async flow).
2855
+ *
2856
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2857
+ * @param {Renderable} pRenderable - The renderable that will be rendered.
2858
+ */},{key:"onBeforeRenderAsync",value:function onBeforeRenderAsync(fCallback,pRenderable){this.onBeforeRender(pRenderable);return fCallback();}/**
2859
+ * Lifecycle hook that triggers before the view is projected into the DOM.
2860
+ *
2861
+ * @param {Renderable} pRenderable - The renderable that will be projected.
2862
+ */},{key:"onBeforeProject",value:function onBeforeProject(pRenderable){// Overload this to mess with stuff before the content gets generated from the template
2863
+ if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onBeforeProject:"));}return true;}/**
2864
+ * Lifecycle hook that triggers before the view is projected into the DOM (async flow).
2865
+ *
2866
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2867
+ * @param {Renderable} pRenderable - The renderable that will be projected.
2868
+ */},{key:"onBeforeProjectAsync",value:function onBeforeProjectAsync(fCallback,pRenderable){this.onBeforeProject(pRenderable);return fCallback();}/**
2869
+ * Builds the render options for a renderable.
2870
+ *
2871
+ * For DRY purposes on the three flavors of render.
2872
+ *
2873
+ * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.
2874
+ * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2875
+ * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.
2876
+ */},{key:"buildRenderOptions",value:function buildRenderOptions(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress){var tmpRenderOptions={Valid:true};tmpRenderOptions.RenderableHash=typeof pRenderableHash==='string'?pRenderableHash:typeof this.options.DefaultRenderable=='string'?this.options.DefaultRenderable:false;if(!tmpRenderOptions.RenderableHash){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not find a suitable RenderableHash ").concat(tmpRenderOptions.RenderableHash," (param ").concat(pRenderableHash,"because it is not a valid renderable."));tmpRenderOptions.Valid=false;}tmpRenderOptions.Renderable=this.renderables[tmpRenderOptions.RenderableHash];if(!tmpRenderOptions.Renderable){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not render ").concat(tmpRenderOptions.RenderableHash," (param ").concat(pRenderableHash,") because it does not exist."));tmpRenderOptions.Valid=false;}tmpRenderOptions.DestinationAddress=typeof pRenderDestinationAddress==='string'?pRenderDestinationAddress:typeof tmpRenderOptions.Renderable.ContentDestinationAddress==='string'?tmpRenderOptions.Renderable.ContentDestinationAddress:typeof this.options.DefaultDestinationAddress==='string'?this.options.DefaultDestinationAddress:false;if(!tmpRenderOptions.DestinationAddress){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not render ").concat(tmpRenderOptions.RenderableHash," (param ").concat(pRenderableHash,") because it does not have a valid destination address (param ").concat(pRenderDestinationAddress,")."));tmpRenderOptions.Valid=false;}if(_typeof(pTemplateRecordAddress)==='object'){tmpRenderOptions.RecordAddress='Passed in as object';tmpRenderOptions.Record=pTemplateRecordAddress;}else{tmpRenderOptions.RecordAddress=typeof pTemplateRecordAddress==='string'?pTemplateRecordAddress:typeof tmpRenderOptions.Renderable.DefaultTemplateRecordAddress==='string'?tmpRenderOptions.Renderable.DefaultTemplateRecordAddress:typeof this.options.DefaultTemplateRecordAddress==='string'?this.options.DefaultTemplateRecordAddress:false;tmpRenderOptions.Record=typeof tmpRenderOptions.RecordAddress==='string'?this.pict.DataProvider.getDataByAddress(tmpRenderOptions.RecordAddress):undefined;}return tmpRenderOptions;}/**
2877
+ * Assigns the content to the destination address.
2878
+ *
2879
+ * For DRY purposes on the three flavors of render.
2880
+ *
2881
+ * @param {Renderable} pRenderable - The renderable to render.
2882
+ * @param {string} pRenderDestinationAddress - The address where the renderable will be rendered.
2883
+ * @param {string} pContent - The content to render.
2884
+ * @returns {boolean} - Returns true if the content was assigned successfully.
2885
+ * @memberof PictView
2886
+ */},{key:"assignRenderContent",value:function assignRenderContent(pRenderable,pRenderDestinationAddress,pContent){return this.pict.ContentAssignment.projectContent(pRenderable.RenderMethod,pRenderDestinationAddress,pContent,pRenderable.TestAddress);}/**
2887
+ * Render a renderable from this view.
2888
+ *
2889
+ * @param {string} [pRenderableHash] - The hash of the renderable to render.
2890
+ * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2891
+ * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.
2892
+ * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.
2893
+ * @return {boolean}
2894
+ */},{key:"render",value:function render(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,pRootRenderable){return this.renderWithScope(this,pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,pRootRenderable);}/**
2895
+ * Render a renderable from this view, providing a specifici scope for the template.
2896
+ *
2897
+ * @param {any} pScope - The scope to use for the template rendering.
2898
+ * @param {string} [pRenderableHash] - The hash of the renderable to render.
2899
+ * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2900
+ * @param {string|object} [pTemplateRecordAddress] - The address where the data for the template is stored.
2901
+ * @param {Renderable} [pRootRenderable] - The root renderable for the render operation, if applicable.
2902
+ * @return {boolean}
2903
+ */},{key:"renderWithScope",value:function renderWithScope(pScope,pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,pRootRenderable){var tmpRenderableHash=typeof pRenderableHash==='string'?pRenderableHash:typeof this.options.DefaultRenderable=='string'?this.options.DefaultRenderable:false;if(!tmpRenderableHash){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not render ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,") because it is not a valid renderable."));return false;}/** @type {Renderable} */var tmpRenderable;if(tmpRenderableHash=='__Virtual'){tmpRenderable={RenderableHash:'__Virtual',TemplateHash:this.renderables[this.options.DefaultRenderable].TemplateHash,ContentDestinationAddress:typeof pRenderDestinationAddress==='string'?pRenderDestinationAddress:typeof tmpRenderable.ContentDestinationAddress==='string'?tmpRenderable.ContentDestinationAddress:typeof this.options.DefaultDestinationAddress==='string'?this.options.DefaultDestinationAddress:null,RenderMethod:'virtual-assignment',TransactionHash:pRootRenderable&&pRootRenderable.TransactionHash,RootRenderableViewHash:pRootRenderable&&pRootRenderable.RootRenderableViewHash};}else{tmpRenderable=Object.assign({},this.renderables[tmpRenderableHash]);tmpRenderable.ContentDestinationAddress=typeof pRenderDestinationAddress==='string'?pRenderDestinationAddress:typeof tmpRenderable.ContentDestinationAddress==='string'?tmpRenderable.ContentDestinationAddress:typeof this.options.DefaultDestinationAddress==='string'?this.options.DefaultDestinationAddress:null;}if(!tmpRenderable.TransactionHash){tmpRenderable.TransactionHash="ViewRender-V-".concat(this.options.ViewIdentifier,"-R-").concat(tmpRenderableHash,"-U-").concat(this.pict.getUUID());tmpRenderable.RootRenderableViewHash=this.Hash;this.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);}if(!tmpRenderable){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not render ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,") because it does not exist."));return false;}if(!tmpRenderable.ContentDestinationAddress){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not render ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,") because it does not have a valid destination address."));return false;}var tmpRecordAddress;var tmpRecord;if(_typeof(pTemplateRecordAddress)==='object'){tmpRecord=pTemplateRecordAddress;tmpRecordAddress='Passed in as object';}else{tmpRecordAddress=typeof pTemplateRecordAddress==='string'?pTemplateRecordAddress:typeof tmpRenderable.DefaultTemplateRecordAddress==='string'?tmpRenderable.DefaultTemplateRecordAddress:typeof this.options.DefaultTemplateRecordAddress==='string'?this.options.DefaultTemplateRecordAddress:false;tmpRecord=typeof tmpRecordAddress==='string'?this.pict.DataProvider.getDataByAddress(tmpRecordAddress):undefined;}// Execute the developer-overridable pre-render behavior
2904
+ this.onBeforeRender(tmpRenderable);if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow VIEW [".concat(this.UUID,"]::[").concat(this.Hash,"] Renderable[").concat(tmpRenderableHash,"] Destination[").concat(tmpRenderable.ContentDestinationAddress,"] TemplateRecordAddress[").concat(tmpRecordAddress,"] render:"));}if(this.pict.LogNoisiness>0){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," Beginning Render of Renderable[").concat(tmpRenderableHash,"] to Destination [").concat(tmpRenderable.ContentDestinationAddress,"]..."));}// Generate the content output from the template and data
2905
+ tmpRenderable.Content=this.pict.parseTemplateByHash(tmpRenderable.TemplateHash,tmpRecord,null,[this],pScope,{RootRenderable:_typeof(pRootRenderable)==='object'?pRootRenderable:tmpRenderable});if(this.pict.LogNoisiness>0){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," Assigning Renderable[").concat(tmpRenderableHash,"] content length ").concat(tmpRenderable.Content.length," to Destination [").concat(tmpRenderable.ContentDestinationAddress,"] using render method [").concat(tmpRenderable.RenderMethod,"]."));}this.onBeforeProject(tmpRenderable);this.onProject(tmpRenderable);if(tmpRenderable.RenderMethod!=='virtual-assignment'){this.onAfterProject(tmpRenderable);// Execute the developer-overridable post-render behavior
2906
+ this.onAfterRender(tmpRenderable);}return true;}/**
2907
+ * Render a renderable from this view.
2908
+ *
2909
+ * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.
2910
+ * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2911
+ * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.
2912
+ * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.
2913
+ * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.
2914
+ *
2915
+ * @return {void}
2916
+ */},{key:"renderAsync",value:function renderAsync(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,pRootRenderable,fCallback){return this.renderWithScopeAsync(this,pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,pRootRenderable,fCallback);}/**
2917
+ * Render a renderable from this view.
2918
+ *
2919
+ * @param {any} pScope - The scope to use for the template rendering.
2920
+ * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.
2921
+ * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2922
+ * @param {string|object|ErrorCallback} [pTemplateRecordAddress] - The address where the data for the template is stored.
2923
+ * @param {Renderable|ErrorCallback} [pRootRenderable] - The root renderable for the render operation, if applicable.
2924
+ * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.
2925
+ *
2926
+ * @return {void}
2927
+ */},{key:"renderWithScopeAsync",value:function renderWithScopeAsync(pScope,pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,pRootRenderable,fCallback){var _this69=this;var tmpRenderableHash=typeof pRenderableHash==='string'?pRenderableHash:typeof this.options.DefaultRenderable=='string'?this.options.DefaultRenderable:false;// Allow the callback to be passed in as the last parameter no matter what
2928
+ /** @type {ErrorCallback} */var tmpCallback=typeof fCallback==='function'?fCallback:typeof pTemplateRecordAddress==='function'?pTemplateRecordAddress:typeof pRenderDestinationAddress==='function'?pRenderDestinationAddress:typeof pRenderableHash==='function'?pRenderableHash:typeof pRootRenderable==='function'?pRootRenderable:null;if(!tmpCallback){this.log.warn("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," renderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this69.log.error("PictView [".concat(_this69.UUID,"]::[").concat(_this69.Hash,"] ").concat(_this69.options.Name," renderAsync Auto Callback Error: ").concat(pError),pError);}};}if(!tmpRenderableHash){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not asynchronously render ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,"because it is not a valid renderable."));return tmpCallback(new Error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not asynchronously render ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,"because it is not a valid renderable.")));}/** @type {Renderable} */var tmpRenderable;if(tmpRenderableHash=='__Virtual'){tmpRenderable={RenderableHash:'__Virtual',TemplateHash:this.renderables[this.options.DefaultRenderable].TemplateHash,ContentDestinationAddress:typeof pRenderDestinationAddress==='string'?pRenderDestinationAddress:typeof this.options.DefaultDestinationAddress==='string'?this.options.DefaultDestinationAddress:null,RenderMethod:'virtual-assignment',TransactionHash:pRootRenderable&&typeof pRootRenderable!=='function'&&pRootRenderable.TransactionHash,RootRenderableViewHash:pRootRenderable&&typeof pRootRenderable!=='function'&&pRootRenderable.RootRenderableViewHash};}else{tmpRenderable=Object.assign({},this.renderables[tmpRenderableHash]);tmpRenderable.ContentDestinationAddress=typeof pRenderDestinationAddress==='string'?pRenderDestinationAddress:typeof tmpRenderable.ContentDestinationAddress==='string'?tmpRenderable.ContentDestinationAddress:typeof this.options.DefaultDestinationAddress==='string'?this.options.DefaultDestinationAddress:null;}if(!tmpRenderable.TransactionHash){tmpRenderable.TransactionHash="ViewRender-V-".concat(this.options.ViewIdentifier,"-R-").concat(tmpRenderableHash,"-U-").concat(this.pict.getUUID());tmpRenderable.RootRenderableViewHash=this.Hash;this.pict.TransactionTracking.registerTransaction(tmpRenderable.TransactionHash);}if(!tmpRenderable){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not render ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,") because it does not exist."));return tmpCallback(new Error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not render ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,") because it does not exist.")));}if(!tmpRenderable.ContentDestinationAddress){this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not render ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,") because it does not have a valid destination address."));return tmpCallback(new Error("Could not render ".concat(tmpRenderableHash)));}var tmpRecordAddress;var tmpRecord;if(_typeof(pTemplateRecordAddress)==='object'){tmpRecord=pTemplateRecordAddress;tmpRecordAddress='Passed in as object';}else{tmpRecordAddress=typeof pTemplateRecordAddress==='string'?pTemplateRecordAddress:typeof tmpRenderable.DefaultTemplateRecordAddress==='string'?tmpRenderable.DefaultTemplateRecordAddress:typeof this.options.DefaultTemplateRecordAddress==='string'?this.options.DefaultTemplateRecordAddress:false;tmpRecord=typeof tmpRecordAddress==='string'?this.pict.DataProvider.getDataByAddress(tmpRecordAddress):undefined;}if(this.pict.LogControlFlow){this.log.trace("PICT-ControlFlow VIEW [".concat(this.UUID,"]::[").concat(this.Hash,"] Renderable[").concat(tmpRenderableHash,"] Destination[").concat(tmpRenderable.ContentDestinationAddress,"] TemplateRecordAddress[").concat(tmpRecordAddress,"] renderAsync:"));}if(this.pict.LogNoisiness>2){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," Beginning Asynchronous Render (callback-style)..."));}var tmpAnticipate=this.fable.newAnticipate();tmpAnticipate.anticipate(function(fOnBeforeRenderCallback){_this69.onBeforeRenderAsync(fOnBeforeRenderCallback,tmpRenderable);});tmpAnticipate.anticipate(function(fAsyncTemplateCallback){// Render the template (asynchronously)
2929
+ _this69.pict.parseTemplateByHash(tmpRenderable.TemplateHash,tmpRecord,function(pError,pContent){if(pError){_this69.log.error("PictView [".concat(_this69.UUID,"]::[").concat(_this69.Hash,"] ").concat(_this69.options.ViewIdentifier," could not render (asynchronously) ").concat(tmpRenderableHash," (param ").concat(pRenderableHash,") because it did not parse the template."),pError);return fAsyncTemplateCallback(pError);}tmpRenderable.Content=pContent;return fAsyncTemplateCallback();},[_this69],pScope,{RootRenderable:_typeof(pRootRenderable)==='object'?pRootRenderable:tmpRenderable});});tmpAnticipate.anticipate(function(fNext){_this69.onBeforeProjectAsync(fNext,tmpRenderable);});tmpAnticipate.anticipate(function(fNext){_this69.onProjectAsync(fNext,tmpRenderable);});if(tmpRenderable.RenderMethod!=='virtual-assignment'){tmpAnticipate.anticipate(function(fNext){_this69.onAfterProjectAsync(fNext,tmpRenderable);});// Execute the developer-overridable post-render behavior
2930
+ tmpAnticipate.anticipate(function(fNext){_this69.onAfterRenderAsync(fNext,tmpRenderable);});}tmpAnticipate.wait(tmpCallback);}/**
2931
+ * Renders the default renderable.
2932
+ *
2933
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2934
+ */},{key:"renderDefaultAsync",value:function renderDefaultAsync(fCallback){// Render the default renderable
2935
+ this.renderAsync(fCallback);}/**
2936
+ * @param {string} [pRenderableHash] - The hash of the renderable to render.
2937
+ * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2938
+ * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.
2939
+ */},{key:"basicRender",value:function basicRender(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress){return this.basicRenderWithScope(this,pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress);}/**
2940
+ * @param {any} pScope - The scope to use for the template rendering.
2941
+ * @param {string} [pRenderableHash] - The hash of the renderable to render.
2942
+ * @param {string} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2943
+ * @param {string|object} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.
2944
+ */},{key:"basicRenderWithScope",value:function basicRenderWithScope(pScope,pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress){var tmpRenderOptions=this.buildRenderOptions(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress);if(tmpRenderOptions.Valid){this.assignRenderContent(tmpRenderOptions.Renderable,tmpRenderOptions.DestinationAddress,this.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash,tmpRenderOptions.Record,null,[this],pScope,{RootRenderable:tmpRenderOptions.Renderable}));return true;}else{this.log.error("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not perform a basic render of ").concat(tmpRenderOptions.RenderableHash," because it is not valid."));return false;}}/**
2945
+ * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.
2946
+ * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2947
+ * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.
2948
+ * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.
2949
+ */},{key:"basicRenderAsync",value:function basicRenderAsync(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,fCallback){return this.basicRenderWithScopeAsync(this,pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,fCallback);}/**
2950
+ * @param {any} pScope - The scope to use for the template rendering.
2951
+ * @param {string|ErrorCallback} [pRenderableHash] - The hash of the renderable to render.
2952
+ * @param {string|ErrorCallback} [pRenderDestinationAddress] - The address where the renderable will be rendered.
2953
+ * @param {string|Object|ErrorCallback} [pTemplateRecordAddress] - The address of (or actual obejct) where the data for the template is stored.
2954
+ * @param {ErrorCallback} [fCallback] - The callback to call when the async operation is complete.
2955
+ */},{key:"basicRenderWithScopeAsync",value:function basicRenderWithScopeAsync(pScope,pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress,fCallback){var _this70=this;// Allow the callback to be passed in as the last parameter no matter what
2956
+ /** @type {ErrorCallback} */var tmpCallback=typeof fCallback==='function'?fCallback:typeof pTemplateRecordAddress==='function'?pTemplateRecordAddress:typeof pRenderDestinationAddress==='function'?pRenderDestinationAddress:typeof pRenderableHash==='function'?pRenderableHash:null;if(!tmpCallback){this.log.warn("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," basicRenderAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this70.log.error("PictView [".concat(_this70.UUID,"]::[").concat(_this70.Hash,"] ").concat(_this70.options.Name," basicRenderAsync Auto Callback Error: ").concat(pError),pError);}};}var tmpRenderOptions=this.buildRenderOptions(pRenderableHash,pRenderDestinationAddress,pTemplateRecordAddress);if(tmpRenderOptions.Valid){this.pict.parseTemplateByHash(tmpRenderOptions.Renderable.TemplateHash,tmpRenderOptions.Record,/**
2957
+ * @param {Error} [pError] - The error that occurred during template parsing.
2958
+ * @param {string} [pContent] - The content that was rendered from the template.
2959
+ */function(pError,pContent){if(pError){_this70.log.error("PictView [".concat(_this70.UUID,"]::[").concat(_this70.Hash,"] ").concat(_this70.options.ViewIdentifier," could not render (asynchronously) ").concat(tmpRenderOptions.RenderableHash," because it did not parse the template."),pError);return tmpCallback(pError);}_this70.assignRenderContent(tmpRenderOptions.Renderable,tmpRenderOptions.DestinationAddress,pContent);return tmpCallback();},[this],pScope,{RootRenderable:tmpRenderOptions.Renderable});}else{var tmpErrorMessage="PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," could not perform a basic render of ").concat(tmpRenderOptions.RenderableHash," because it is not valid.");this.log.error(tmpErrorMessage);return tmpCallback(new Error(tmpErrorMessage));}}/**
2960
+ * @param {Renderable} pRenderable - The renderable that was rendered.
2961
+ */},{key:"onProject",value:function onProject(pRenderable){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onProject:"));}if(pRenderable.RenderMethod==='virtual-assignment'){this.pict.TransactionTracking.pushToTransactionQueue(pRenderable.TransactionHash,{ViewHash:this.Hash,Renderable:pRenderable},'Deferred-Post-Content-Assignment');}if(this.pict.LogNoisiness>0){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," Assigning Renderable[").concat(pRenderable.RenderableHash,"] content length ").concat(pRenderable.Content.length," to Destination [").concat(pRenderable.ContentDestinationAddress,"] using Async render method ").concat(pRenderable.RenderMethod,"."));}// Assign the content to the destination address
2962
+ this.pict.ContentAssignment.projectContent(pRenderable.RenderMethod,pRenderable.ContentDestinationAddress,pRenderable.Content,pRenderable.TestAddress);this.lastRenderedTimestamp=this.pict.log.getTimeStamp();}/**
2963
+ * Lifecycle hook that triggers after the view is projected into the DOM (async flow).
2964
+ *
2965
+ * @param {(error?: Error, content?: string) => void} fCallback - The callback to call when the async operation is complete.
2966
+ * @param {Renderable} pRenderable - The renderable that is being projected.
2967
+ */},{key:"onProjectAsync",value:function onProjectAsync(fCallback,pRenderable){this.onProject(pRenderable);return fCallback();}/**
2968
+ * Lifecycle hook that triggers after the view is rendered.
2969
+ *
2970
+ * @param {Renderable} pRenderable - The renderable that was rendered.
2971
+ */},{key:"onAfterRender",value:function 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){var tmpTransactionQueue=this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash)||[];var _iterator=_createForOfIteratorHelper(tmpTransactionQueue),_step;try{for(_iterator.s();!(_step=_iterator.n()).done;){var tmpEvent=_step.value;var 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
2972
+ tmpView.onAfterRender(tmpEvent.Data.Renderable);}}catch(err){_iterator.e(err);}finally{_iterator.f();}}return true;}/**
2973
+ * Lifecycle hook that triggers after the view is rendered (async flow).
2974
+ *
2975
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2976
+ * @param {Renderable} pRenderable - The renderable that was rendered.
2977
+ */},{key:"onAfterRenderAsync",value:function onAfterRenderAsync(fCallback,pRenderable){var _this71=this;this.onAfterRender(pRenderable);var tmpAnticipate=this.fable.newAnticipate();if(pRenderable&&pRenderable.RootRenderableViewHash===this.Hash){var queue=this.pict.TransactionTracking.clearTransactionQueue(pRenderable.TransactionHash)||[];var _iterator2=_createForOfIteratorHelper(queue),_step2;try{var _loop5=function _loop5(){var event=_step2.value;/** @type {PictView} */var tmpView=_this71.pict.views[event.Data.ViewHash];if(!tmpView){_this71.log.error("PictView [".concat(_this71.UUID,"]::[").concat(_this71.Hash,"] ").concat(_this71.options.ViewIdentifier," onAfterRenderAsync: Could not find view for transaction hash ").concat(pRenderable.TransactionHash," and ViewHash ").concat(event.Data.ViewHash,"."));return 1;// continue
2978
+ }tmpAnticipate.anticipate(tmpView.onAfterProjectAsync.bind(tmpView));tmpAnticipate.anticipate(function(fNext){tmpView.onAfterRenderAsync(fNext,event.Data.Renderable);});// Execute the developer-overridable post-render behavior
2979
+ };for(_iterator2.s();!(_step2=_iterator2.n()).done;){if(_loop5())continue;}}catch(err){_iterator2.e(err);}finally{_iterator2.f();}}return tmpAnticipate.wait(fCallback);}/**
2980
+ * Lifecycle hook that triggers after the view is projected into the DOM.
2981
+ *
2982
+ * @param {Renderable} pRenderable - The renderable that was projected.
2983
+ */},{key:"onAfterProject",value:function onAfterProject(pRenderable){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterProject:"));}return true;}/**
2984
+ * Lifecycle hook that triggers after the view is projected into the DOM (async flow).
2985
+ *
2986
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2987
+ * @param {Renderable} pRenderable - The renderable that was projected.
2988
+ */},{key:"onAfterProjectAsync",value:function onAfterProjectAsync(fCallback,pRenderable){return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Solver *//* -------------------------------------------------------------------------- *//**
2989
+ * Lifecycle hook that triggers before the view is solved.
2990
+ */},{key:"onBeforeSolve",value:function onBeforeSolve(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onBeforeSolve:"));}return true;}/**
2991
+ * Lifecycle hook that triggers before the view is solved (async flow).
2992
+ *
2993
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
2994
+ */},{key:"onBeforeSolveAsync",value:function onBeforeSolveAsync(fCallback){this.onBeforeSolve();return fCallback();}/**
2995
+ * Lifecycle hook that triggers when the view is solved.
2996
+ */},{key:"onSolve",value:function onSolve(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onSolve:"));}return true;}/**
2997
+ * Lifecycle hook that triggers when the view is solved (async flow).
2998
+ *
2999
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3000
+ */},{key:"onSolveAsync",value:function onSolveAsync(fCallback){this.onSolve();return fCallback();}/**
3001
+ * Performs view solving and triggers lifecycle hooks.
3002
+ *
3003
+ * @return {boolean} - True if the view was solved successfully, false otherwise.
3004
+ */},{key:"solve",value:function solve(){if(this.pict.LogNoisiness>2){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," executing solve() function..."));}this.onBeforeSolve();this.onSolve();this.onAfterSolve();this.lastSolvedTimestamp=this.pict.log.getTimeStamp();return true;}/**
3005
+ * Performs view solving and triggers lifecycle hooks (async flow).
3006
+ *
3007
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3008
+ */},{key:"solveAsync",value:function solveAsync(fCallback){var _this72=this;var tmpAnticipate=this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');/** @type {ErrorCallback} */var tmpCallback=typeof fCallback==='function'?fCallback:null;if(!tmpCallback){this.log.warn("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," solveAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this72.log.error("PictView [".concat(_this72.UUID,"]::[").concat(_this72.Hash,"] ").concat(_this72.options.Name," solveAsync Auto Callback Error: ").concat(pError),pError);}};}tmpAnticipate.anticipate(this.onBeforeSolveAsync.bind(this));tmpAnticipate.anticipate(this.onSolveAsync.bind(this));tmpAnticipate.anticipate(this.onAfterSolveAsync.bind(this));tmpAnticipate.wait(function(pError){if(_this72.pict.LogNoisiness>2){_this72.log.trace("PictView [".concat(_this72.UUID,"]::[").concat(_this72.Hash,"] ").concat(_this72.options.ViewIdentifier," solveAsync() complete."));}_this72.lastSolvedTimestamp=_this72.pict.log.getTimeStamp();return tmpCallback(pError);});}/**
3009
+ * Lifecycle hook that triggers after the view is solved.
3010
+ */},{key:"onAfterSolve",value:function onAfterSolve(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterSolve:"));}return true;}/**
3011
+ * Lifecycle hook that triggers after the view is solved (async flow).
3012
+ *
3013
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3014
+ */},{key:"onAfterSolveAsync",value:function onAfterSolveAsync(fCallback){this.onAfterSolve();return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Marshal From View *//* -------------------------------------------------------------------------- *//**
3015
+ * Lifecycle hook that triggers before data is marshaled from the view.
3016
+ *
3017
+ * @return {boolean} - True if the operation was successful, false otherwise.
3018
+ */},{key:"onBeforeMarshalFromView",value:function onBeforeMarshalFromView(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onBeforeMarshalFromView:"));}return true;}/**
3019
+ * Lifecycle hook that triggers before data is marshaled from the view (async flow).
3020
+ *
3021
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3022
+ */},{key:"onBeforeMarshalFromViewAsync",value:function onBeforeMarshalFromViewAsync(fCallback){this.onBeforeMarshalFromView();return fCallback();}/**
3023
+ * Lifecycle hook that triggers when data is marshaled from the view.
3024
+ */},{key:"onMarshalFromView",value:function onMarshalFromView(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onMarshalFromView:"));}return true;}/**
3025
+ * Lifecycle hook that triggers when data is marshaled from the view (async flow).
3026
+ *
3027
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3028
+ */},{key:"onMarshalFromViewAsync",value:function onMarshalFromViewAsync(fCallback){this.onMarshalFromView();return fCallback();}/**
3029
+ * Marshals data from the view.
3030
+ *
3031
+ * @return {boolean} - True if the operation was successful, false otherwise.
3032
+ */},{key:"marshalFromView",value:function marshalFromView(){if(this.pict.LogNoisiness>2){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," executing solve() function..."));}this.onBeforeMarshalFromView();this.onMarshalFromView();this.onAfterMarshalFromView();this.lastMarshalFromViewTimestamp=this.pict.log.getTimeStamp();return true;}/**
3033
+ * Marshals data from the view (async flow).
3034
+ *
3035
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3036
+ */},{key:"marshalFromViewAsync",value:function marshalFromViewAsync(fCallback){var _this73=this;var tmpAnticipate=this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');/** @type {ErrorCallback} */var tmpCallback=typeof fCallback==='function'?fCallback:null;if(!tmpCallback){this.log.warn("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," marshalFromViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this73.log.error("PictView [".concat(_this73.UUID,"]::[").concat(_this73.Hash,"] ").concat(_this73.options.Name," marshalFromViewAsync Auto Callback Error: ").concat(pError),pError);}};}tmpAnticipate.anticipate(this.onBeforeMarshalFromViewAsync.bind(this));tmpAnticipate.anticipate(this.onMarshalFromViewAsync.bind(this));tmpAnticipate.anticipate(this.onAfterMarshalFromViewAsync.bind(this));tmpAnticipate.wait(function(pError){if(_this73.pict.LogNoisiness>2){_this73.log.trace("PictView [".concat(_this73.UUID,"]::[").concat(_this73.Hash,"] ").concat(_this73.options.ViewIdentifier," marshalFromViewAsync() complete."));}_this73.lastMarshalFromViewTimestamp=_this73.pict.log.getTimeStamp();return tmpCallback(pError);});}/**
3037
+ * Lifecycle hook that triggers after data is marshaled from the view.
3038
+ */},{key:"onAfterMarshalFromView",value:function onAfterMarshalFromView(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterMarshalFromView:"));}return true;}/**
3039
+ * Lifecycle hook that triggers after data is marshaled from the view (async flow).
3040
+ *
3041
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3042
+ */},{key:"onAfterMarshalFromViewAsync",value:function onAfterMarshalFromViewAsync(fCallback){this.onAfterMarshalFromView();return fCallback();}/* -------------------------------------------------------------------------- *//* Code Section: Marshal To View *//* -------------------------------------------------------------------------- *//**
3043
+ * Lifecycle hook that triggers before data is marshaled into the view.
3044
+ */},{key:"onBeforeMarshalToView",value:function onBeforeMarshalToView(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onBeforeMarshalToView:"));}return true;}/**
3045
+ * Lifecycle hook that triggers before data is marshaled into the view (async flow).
3046
+ *
3047
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3048
+ */},{key:"onBeforeMarshalToViewAsync",value:function onBeforeMarshalToViewAsync(fCallback){this.onBeforeMarshalToView();return fCallback();}/**
3049
+ * Lifecycle hook that triggers when data is marshaled into the view.
3050
+ */},{key:"onMarshalToView",value:function onMarshalToView(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onMarshalToView:"));}return true;}/**
3051
+ * Lifecycle hook that triggers when data is marshaled into the view (async flow).
3052
+ *
3053
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3054
+ */},{key:"onMarshalToViewAsync",value:function onMarshalToViewAsync(fCallback){this.onMarshalToView();return fCallback();}/**
3055
+ * Marshals data into the view.
3056
+ *
3057
+ * @return {boolean} - True if the operation was successful, false otherwise.
3058
+ */},{key:"marshalToView",value:function marshalToView(){if(this.pict.LogNoisiness>2){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," executing solve() function..."));}this.onBeforeMarshalToView();this.onMarshalToView();this.onAfterMarshalToView();this.lastMarshalToViewTimestamp=this.pict.log.getTimeStamp();return true;}/**
3059
+ * Marshals data into the view (async flow).
3060
+ *
3061
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3062
+ */},{key:"marshalToViewAsync",value:function marshalToViewAsync(fCallback){var _this74=this;var tmpAnticipate=this.pict.instantiateServiceProviderWithoutRegistration('Anticipate');/** @type {ErrorCallback} */var tmpCallback=typeof fCallback==='function'?fCallback:null;if(!tmpCallback){this.log.warn("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.Name," marshalToViewAsync was called without a valid callback. A callback will be generated but this could lead to race conditions."));tmpCallback=function tmpCallback(pError){if(pError){_this74.log.error("PictView [".concat(_this74.UUID,"]::[").concat(_this74.Hash,"] ").concat(_this74.options.Name," marshalToViewAsync Auto Callback Error: ").concat(pError),pError);}};}tmpAnticipate.anticipate(this.onBeforeMarshalToViewAsync.bind(this));tmpAnticipate.anticipate(this.onMarshalToViewAsync.bind(this));tmpAnticipate.anticipate(this.onAfterMarshalToViewAsync.bind(this));tmpAnticipate.wait(function(pError){if(_this74.pict.LogNoisiness>2){_this74.log.trace("PictView [".concat(_this74.UUID,"]::[").concat(_this74.Hash,"] ").concat(_this74.options.ViewIdentifier," marshalToViewAsync() complete."));}_this74.lastMarshalToViewTimestamp=_this74.pict.log.getTimeStamp();return tmpCallback(pError);});}/**
3063
+ * Lifecycle hook that triggers after data is marshaled into the view.
3064
+ */},{key:"onAfterMarshalToView",value:function onAfterMarshalToView(){if(this.pict.LogNoisiness>3){this.log.trace("PictView [".concat(this.UUID,"]::[").concat(this.Hash,"] ").concat(this.options.ViewIdentifier," onAfterMarshalToView:"));}return true;}/**
3065
+ * Lifecycle hook that triggers after data is marshaled into the view (async flow).
3066
+ *
3067
+ * @param {ErrorCallback} fCallback - The callback to call when the async operation is complete.
3068
+ */},{key:"onAfterMarshalToViewAsync",value:function onAfterMarshalToViewAsync(fCallback){this.onAfterMarshalToView();return fCallback();}/** @return {boolean} - True if the object is a PictView. */},{key:"isPictView",get:function get(){return true;}}]);}(libFableServiceBase);module.exports=PictView;},{"../package.json":44,"fable-serviceproviderbase":4}],46:[function(require,module,exports){var MICRODDL_TYPE_MAP={'@':{DataType:'AutoIdentity',Label:'Auto ID',HasSize:false},'%':{DataType:'GUID',Label:'GUID',HasSize:false},'$':{DataType:'String',Label:'String',HasSize:true},'*':{DataType:'Text',Label:'Text',HasSize:false},'#':{DataType:'Numeric',Label:'Numeric',HasSize:false},'.':{DataType:'Decimal',Label:'Decimal',HasSize:true},'&':{DataType:'DateTime',Label:'Date/Time',HasSize:false},'^':{DataType:'Boolean',Label:'Boolean',HasSize:false}};var DATATYPE_TO_SYMBOL={};for(var tmpSymbol in MICRODDL_TYPE_MAP){DATATYPE_TO_SYMBOL[MICRODDL_TYPE_MAP[tmpSymbol].DataType]=tmpSymbol;}function columnsToMicroDDL(pColumns,pTableName){var tmpTableName=(pTableName||'Untitled').replace(/[^a-zA-Z0-9_]/g,'');var tmpLines=['!'+tmpTableName];for(var i=0;i<pColumns.length;i++){var tmpCol=pColumns[i];var _tmpSymbol=DATATYPE_TO_SYMBOL[tmpCol.DataType]||'$';var tmpLine=_tmpSymbol+(tmpCol.Name||'Column'+i);if(MICRODDL_TYPE_MAP[_tmpSymbol].HasSize&&tmpCol.Size){tmpLine+=' '+tmpCol.Size;}tmpLines.push(tmpLine);}return tmpLines.join('\n');}function microDDLToColumns(pDDL){var tmpLines=pDDL.split('\n');var tmpColumns=[];for(var i=0;i<tmpLines.length;i++){var tmpLine=tmpLines[i].trim();if(!tmpLine||tmpLine.startsWith('!')||tmpLine.startsWith('//')||tmpLine.startsWith('--')||tmpLine.startsWith('->')){continue;}var _tmpSymbol2=tmpLine.charAt(0);if(MICRODDL_TYPE_MAP.hasOwnProperty(_tmpSymbol2)){var tmpRest=tmpLine.substring(1).trim();var tmpParts=tmpRest.split(/\s+/);tmpColumns.push({Name:tmpParts[0]||'',DataType:MICRODDL_TYPE_MAP[_tmpSymbol2].DataType,Size:tmpParts[1]||''});}}return tmpColumns;}module.exports={MICRODDL_TYPE_MAP:MICRODDL_TYPE_MAP,DATATYPE_TO_SYMBOL:DATATYPE_TO_SYMBOL,columnsToMicroDDL:columnsToMicroDDL,microDDLToColumns:microDDLToColumns};},{}],47:[function(require,module,exports){var libPictView=require('pict-view');var libSchemaUtils=require('./MappingEditor-SchemaUtils.js');var _ViewConfiguration={ViewIdentifier:"MeadowMappingEditor",DefaultRenderable:"MeadowMappingEditor-Content",DefaultDestinationAddress:"#MeadowMap-Editor-Container",AutoRender:false,CSS:/*css*/"\n\t\t/* Meadow Mapping Editor */\n\t\t.meadow-mapping-editor {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.meadow-mapping-editor.active {\n\t\t\tdisplay: block;\n\t\t}\n\t\t.meadow-mapping-header {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 1em;\n\t\t\tmargin-bottom: 1em;\n\t\t}\n\t\t.meadow-mapping-header h3 {\n\t\t\tmargin: 0;\n\t\t\tflex: 1;\n\t\t}\n\t\t.meadow-mapping-list-table {\n\t\t\twidth: 100%;\n\t\t\tborder-collapse: collapse;\n\t\t\tmargin-bottom: 1em;\n\t\t}\n\t\t.meadow-mapping-list-table th {\n\t\t\ttext-align: left;\n\t\t\tfont-size: 0.72em;\n\t\t\tfont-weight: 600;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.5px;\n\t\t\tcolor: var(--facto-text-tertiary, #a09070);\n\t\t\tpadding: 0.5em 0.4em;\n\t\t\tborder-bottom: 1px solid var(--facto-border, #d6c8ae);\n\t\t}\n\t\t.meadow-mapping-list-table td {\n\t\t\tpadding: 0.35em 0.4em;\n\t\t\tborder-bottom: 1px solid var(--facto-border-subtle, #e8ddc8);\n\t\t\tvertical-align: middle;\n\t\t}\n\t\t.meadow-flow-container {\n\t\t\twidth: 100%;\n\t\t\theight: 500px;\n\t\t\tborder: 1px solid var(--facto-border, #d6c8ae);\n\t\t\tborder-radius: 6px;\n\t\t\tbackground: var(--facto-bg-surface, #fcf8f0);\n\t\t\tmargin-bottom: 0.75em;\n\t\t}\n\t\t.meadow-mapping-json-editor {\n\t\t\twidth: 100%;\n\t\t\tmin-height: 300px;\n\t\t\tfont-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;\n\t\t\tfont-size: 0.85em;\n\t\t\tpadding: 0.75em;\n\t\t\tborder: 1px solid var(--facto-border, #d6c8ae);\n\t\t\tborder-radius: 6px;\n\t\t\tbackground: var(--facto-bg-input, #fcf8f0);\n\t\t\tcolor: var(--facto-text, #3a3020);\n\t\t\tresize: vertical;\n\t\t\ttab-size: 4;\n\t\t}\n\t\t.meadow-mapping-store-checklist {\n\t\t\tdisplay: flex;\n\t\t\tflex-wrap: wrap;\n\t\t\tgap: 0.5em;\n\t\t\tmargin-top: 0.25em;\n\t\t}\n\t\t.meadow-mapping-store-checklist label {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.35em;\n\t\t\tfont-size: 0.82em;\n\t\t\tcursor: pointer;\n\t\t\tpadding: 0.3em 0.5em;\n\t\t\tborder: 1px solid var(--facto-border-subtle, #e8ddc8);\n\t\t\tborder-radius: 4px;\n\t\t\tbackground: var(--facto-bg-input, #fcf8f0);\n\t\t}\n\t\t.meadow-mapping-store-checklist label:has(input:checked) {\n\t\t\tborder-color: var(--facto-brand, #18a5a0);\n\t\t\tbackground: var(--facto-brand-a12, rgba(24,165,160,0.12));\n\t\t}\n\t\t.meadow-mapping-btn {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tpadding: 0.35em 0.9em;\n\t\t\tfont-size: 0.82em;\n\t\t\tfont-weight: 500;\n\t\t\tborder-radius: 4px;\n\t\t\tborder: 1px solid transparent;\n\t\t\tcursor: pointer;\n\t\t\ttext-decoration: none;\n\t\t\tline-height: 1.4;\n\t\t}\n\t\t.meadow-mapping-btn-primary {\n\t\t\tbackground: var(--facto-brand, #18a5a0);\n\t\t\tcolor: #fff;\n\t\t\tborder-color: var(--facto-brand, #18a5a0);\n\t\t}\n\t\t.meadow-mapping-btn-primary:hover {\n\t\t\topacity: 0.88;\n\t\t}\n\t\t.meadow-mapping-btn-secondary {\n\t\t\tbackground: var(--facto-bg-input, #fcf8f0);\n\t\t\tcolor: var(--facto-text, #3a3020);\n\t\t\tborder-color: var(--facto-border, #d6c8ae);\n\t\t}\n\t\t.meadow-mapping-btn-secondary:hover {\n\t\t\tbackground: var(--facto-border-subtle, #e8ddc8);\n\t\t}\n\t\t.meadow-mapping-btn-danger {\n\t\t\tbackground: #e74c3c;\n\t\t\tcolor: #fff;\n\t\t\tborder-color: #e74c3c;\n\t\t}\n\t\t.meadow-mapping-btn-danger:hover {\n\t\t\topacity: 0.88;\n\t\t}\n\t\t.meadow-mapping-btn-small {\n\t\t\tpadding: 0.2em 0.6em;\n\t\t\tfont-size: 0.78em;\n\t\t}\n\t\t.meadow-schema-mode-tabs {\n\t\t\tdisplay: flex;\n\t\t\tgap: 0.25em;\n\t\t}\n\t\t.meadow-schema-mode-tab {\n\t\t\tpadding: 0.25em 0.75em;\n\t\t\tfont-size: 0.8em;\n\t\t\tborder: 1px solid var(--facto-border, #d6c8ae);\n\t\t\tborder-radius: 4px;\n\t\t\tcursor: pointer;\n\t\t\tbackground: var(--facto-bg-input, #fcf8f0);\n\t\t\tcolor: var(--facto-text, #3a3020);\n\t\t}\n\t\t.meadow-schema-mode-tab.active {\n\t\t\tbackground: var(--facto-brand, #18a5a0);\n\t\t\tcolor: #fff;\n\t\t\tborder-color: var(--facto-brand, #18a5a0);\n\t\t}\n\t\t.meadow-section-title {\n\t\t\tfont-size: 0.72em;\n\t\t\tfont-weight: 600;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.5px;\n\t\t\tcolor: var(--facto-text-tertiary, #a09070);\n\t\t}\n\t",Templates:[{Hash:"MeadowMappingEditor-Template",Template:/*html*/"\n<div>\n\t<div id=\"MeadowMap-Editor\" class=\"meadow-mapping-editor\">\n\t\t<div class=\"meadow-mapping-header\">\n\t\t\t<button class=\"meadow-mapping-btn meadow-mapping-btn-secondary meadow-mapping-btn-small\" onclick=\"{~P~}.views['MeadowMappingEditor'].closeMappingEditor()\">&larr; Back</button>\n\t\t\t<h3 id=\"MeadowMap-Title\">Mapping Editor</h3>\n\t\t\t<div class=\"meadow-schema-mode-tabs\">\n\t\t\t\t<button class=\"meadow-schema-mode-tab active\" id=\"MeadowMap-Mode-Flow\" onclick=\"{~P~}.views['MeadowMappingEditor'].switchMapMode('flow')\">Visual Mapper</button>\n\t\t\t\t<button class=\"meadow-schema-mode-tab\" id=\"MeadowMap-Mode-JSON\" onclick=\"{~P~}.views['MeadowMappingEditor'].switchMapMode('json')\">JSON Config</button>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<div id=\"MeadowMap-List-Wrap\">\n\t\t\t<div style=\"display:flex; align-items:center; justify-content:space-between; margin-bottom:0.75em;\">\n\t\t\t\t<div class=\"meadow-section-title\" style=\"margin:0;\">Existing Mappings</div>\n\t\t\t\t<button class=\"meadow-mapping-btn meadow-mapping-btn-primary meadow-mapping-btn-small\" onclick=\"{~P~}.views['MeadowMappingEditor'].newMapping()\">+ New Mapping</button>\n\t\t\t</div>\n\t\t\t<div id=\"MeadowMap-List\"></div>\n\t\t</div>\n\n\t\t<div id=\"MeadowMap-Detail\" style=\"display:none;\">\n\t\t\t<div style=\"display:flex; gap:0.5em; align-items:center; margin-bottom:0.75em;\">\n\t\t\t\t<label style=\"font-size:0.78em; font-weight:600;\">Mapping Name</label>\n\t\t\t\t<input type=\"text\" id=\"MeadowMap-Name\" placeholder=\"Mapping name\" style=\"flex:1; padding:0.3em 0.5em; font-size:0.85em; border:1px solid var(--facto-border); border-radius:4px; background:var(--facto-bg-input); color:var(--facto-text);\">\n\t\t\t</div>\n\n\t\t\t<div style=\"display:flex; gap:0.5em; align-items:center; margin-bottom:0.75em;\">\n\t\t\t\t<label style=\"font-size:0.78em; font-weight:600;\">Source</label>\n\t\t\t\t<select id=\"MeadowMap-Source\" style=\"flex:1; padding:0.3em 0.5em; font-size:0.85em; border:1px solid var(--facto-border); border-radius:4px;\"></select>\n\t\t\t\t<button class=\"meadow-mapping-btn meadow-mapping-btn-secondary meadow-mapping-btn-small\" onclick=\"{~P~}.views['MeadowMappingEditor'].discoverSourceFields()\">Discover Fields</button>\n\t\t\t</div>\n\n\t\t\t<div id=\"MeadowMap-Flow-Wrap\">\n\t\t\t\t<div id=\"MeadowMap-Flow-Container\" class=\"meadow-flow-container\"></div>\n\t\t\t</div>\n\n\t\t\t<div id=\"MeadowMap-JSON-Wrap\" style=\"display:none;\">\n\t\t\t\t<textarea class=\"meadow-mapping-json-editor\" id=\"MeadowMap-JSON\" placeholder='{\"Entity\":\"MyTable\",\"GUIDTemplate\":\"{~D:Record.IDRecord~}\",\"Mappings\":{},\"Solvers\":[],\"ManyfestAddresses\":false}'></textarea>\n\t\t\t</div>\n\n\t\t\t<div style=\"margin-top:0.75em;\">\n\t\t\t\t<div style=\"font-size:0.72em; font-weight:600; text-transform:uppercase; letter-spacing:0.5px; color:var(--facto-text-tertiary); margin-bottom:0.35em;\">Target Stores</div>\n\t\t\t\t<div id=\"MeadowMap-Stores\" class=\"meadow-mapping-store-checklist\"></div>\n\t\t\t</div>\n\n\t\t\t<div style=\"margin-top:0.75em; display:flex; gap:0.5em; flex-wrap:wrap; align-items:center;\">\n\t\t\t\t<button class=\"meadow-mapping-btn meadow-mapping-btn-primary\" onclick=\"{~P~}.views['MeadowMappingEditor'].saveMapping()\">Save Mapping</button>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n"}],Renderables:[{RenderableHash:"MeadowMappingEditor-Content",TemplateHash:"MeadowMappingEditor-Template",DestinationAddress:"#MeadowMap-Editor-Container",RenderMethod:"replace"}]};var MeadowMappingEditorView=/*#__PURE__*/function(_libPictView6){function MeadowMappingEditorView(pFable,pOptions,pServiceHash){var _this75;_classCallCheck(this,MeadowMappingEditorView);_this75=_callSuper(this,MeadowMappingEditorView,[pFable,pOptions,pServiceHash]);_this75._EditingContextID=0;_this75._EditingName='';_this75._CurrentMappings=[];_this75._SelectedMappingID=0;_this75._DiscoveredFields={};_this75._FlowView=null;_this75._MapEditorMode='flow';_this75._MappingSources=[];_this75._MappingStores=[];_this75._CurrentTargetSchema=null;return _this75;}// ── Overridable data methods ─────────────────────────────────────────────
3069
+ // Embedding apps override these to wire up their own persistence layer.
3070
+ /** Load all mappings for a context (e.g. dataset). Must return a Promise
3071
+ * that resolves to { Mappings: [...] }. */_inherits(MeadowMappingEditorView,_libPictView6);return _createClass(MeadowMappingEditorView,[{key:"_doLoadMappings",value:function _doLoadMappings(pContextID){return Promise.resolve({Mappings:[]});}/** Load all available sources. Must return a Promise that resolves to an
3072
+ * array of source objects with at least { IDSource, Name }. */},{key:"_doLoadSources",value:function _doLoadSources(){return Promise.resolve([]);}/** Load all available target stores for a context. Must return a Promise
3073
+ * that resolves to { Stores: [...] }. */},{key:"_doLoadStores",value:function _doLoadStores(pContextID){return Promise.resolve({Stores:[]});}/** Load the target schema for a context. Must return a Promise that
3074
+ * resolves to { SchemaDefinition: "<micro-DDL string>" }. */},{key:"_doLoadTargetSchema",value:function _doLoadTargetSchema(pContextID){return Promise.resolve({SchemaDefinition:''});}/** Load a single mapping by ID. Must return a Promise that resolves to
3075
+ * { Mapping: { Name, IDSource, IDProjectionStore, MappingConfiguration,
3076
+ * FlowDiagramState, Active, ... } }. */},{key:"_doLoadMapping",value:function _doLoadMapping(pMappingID){return Promise.resolve({Mapping:null});}/** Delete a mapping by ID. Must return a Promise. */},{key:"_doDeleteMapping",value:function _doDeleteMapping(pMappingID){return Promise.resolve({});}/** Discover fields from a source dataset. Must return a Promise that
3077
+ * resolves to { Headers: [...], SampleSize: N }. */},{key:"_doDiscoverSourceFields",value:function _doDiscoverSourceFields(pContextID,pSourceID,pRecordLimit){return Promise.resolve({Headers:[],SampleSize:0});}/** Create a new mapping. Must return a Promise that resolves to
3078
+ * { Mapping: { IDProjectionMapping, ... } }. */},{key:"_doCreateMapping",value:function _doCreateMapping(pContextID,pData){return Promise.resolve({Mapping:{}});}/** Update an existing mapping. Must return a Promise that resolves to
3079
+ * { Mapping: { ... } }. */},{key:"_doUpdateMapping",value:function _doUpdateMapping(pMappingID,pData){return Promise.resolve({Mapping:{}});}/** Called when the editor is closed. Override to notify the parent view. */},{key:"_onClose",value:function _onClose(){// Default: no-op. Override in embedding app.
3080
+ }/** Show a toast notification. */},{key:"_doToast",value:function _doToast(pMessage,pOptions){var tmpModal=this.pict.views&&this.pict.views['Pict-Section-Modal'];if(tmpModal&&typeof tmpModal.toast==='function'){tmpModal.toast(pMessage,pOptions);}else{this.log.info('[MeadowMappingEditor] '+pMessage);}}/** Show a confirmation dialog. Returns a Promise<boolean>. */},{key:"_doConfirm",value:function _doConfirm(pMessage,pOptions){var tmpModal=this.pict.views&&this.pict.views['Pict-Section-Modal'];if(tmpModal&&typeof tmpModal.confirm==='function'){return tmpModal.confirm(pMessage,pOptions);}// Fallback to native confirm
3081
+ return Promise.resolve(typeof window!=='undefined'?window.confirm(pMessage):false);}// ── Public API ───────────────────────────────────────────────────────────
3082
+ },{key:"editMappings",value:function editMappings(pContextID,pName){var _this76=this;this._EditingContextID=pContextID;this._EditingName=pName||'';// Render the sub-view so its DOM exists
3083
+ this.render();var tmpEditor=document.getElementById('MeadowMap-Editor');var tmpTitle=document.getElementById('MeadowMap-Title');if(tmpEditor){tmpEditor.classList.add('active');tmpEditor.scrollIntoView({behavior:'smooth',block:'nearest'});}if(tmpTitle)tmpTitle.textContent='Mappings: '+(pName||'Untitled');// Show the mapping list, hide detail
3084
+ var tmpMappingListWrap=document.getElementById('MeadowMap-List-Wrap');var tmpMappingDetail=document.getElementById('MeadowMap-Detail');if(tmpMappingListWrap)tmpMappingListWrap.style.display='';if(tmpMappingDetail)tmpMappingDetail.style.display='none';// Load mappings, sources, stores, and fresh schema in parallel
3085
+ Promise.all([this._doLoadMappings(pContextID),this._doLoadSources(),this._doLoadStores(pContextID),this._doLoadTargetSchema(pContextID)]).then(function(pResults){_this76._CurrentMappings=pResults[0]&&pResults[0].Mappings?pResults[0].Mappings:[];_this76._MappingSources=Array.isArray(pResults[1])?pResults[1]:[];_this76._MappingStores=pResults[2]&&pResults[2].Stores?pResults[2].Stores:[];// Pre-populate _DiscoveredFields from source Columns (config-driven).
3086
+ // Sources that include a Columns array provide field names without
3087
+ // requiring a separate "Discover Fields" API call.
3088
+ for(var i=0;i<_this76._MappingSources.length;i++){var tmpSrc=_this76._MappingSources[i];if(Array.isArray(tmpSrc.Columns)&&tmpSrc.Columns.length>0){_this76._DiscoveredFields[tmpSrc.IDSource]=tmpSrc.Columns;}}// Store the fresh schema locally for use by flow nodes
3089
+ var tmpSchema=pResults[3];if(tmpSchema&&tmpSchema.SchemaDefinition){_this76._CurrentTargetSchema=tmpSchema.SchemaDefinition;}_this76.refreshMappingList();});}},{key:"closeMappingEditor",value:function closeMappingEditor(){// Clean up flow view
3090
+ if(this._FlowView){this._FlowView=null;}this._SelectedMappingID=0;this._onClose();}},{key:"refreshMappingList",value:function refreshMappingList(){var tmpContainer=document.getElementById('MeadowMap-List');if(!tmpContainer)return;if(this._CurrentMappings.length===0){tmpContainer.innerHTML='<div style="text-align:center; padding:1.5em; color:var(--facto-text-tertiary, #a09070);">No mappings yet. Create one to map source fields to target columns.</div>';return;}var tmpViewID=this.options.ViewIdentifier;var tmpHtml='<table class="meadow-mapping-list-table"><thead><tr>';tmpHtml+='<th>ID</th><th>Name</th><th>Source</th><th>Active</th><th>Actions</th>';tmpHtml+='</tr></thead><tbody>';for(var i=0;i<this._CurrentMappings.length;i++){var tmpMap=this._CurrentMappings[i];var tmpSourceName="\u2014";for(var j=0;j<this._MappingSources.length;j++){if(this._MappingSources[j].IDSource===tmpMap.IDSource){tmpSourceName=this._MappingSources[j].Name||'Source '+tmpMap.IDSource;break;}}tmpHtml+='<tr>';tmpHtml+='<td>'+tmpMap.IDProjectionMapping+'</td>';tmpHtml+='<td><strong>'+(tmpMap.Name||"\u2014")+'</strong></td>';tmpHtml+='<td>'+tmpSourceName+'</td>';tmpHtml+='<td>'+(tmpMap.Active?"\u2713":"\u2717")+'</td>';tmpHtml+='<td>';tmpHtml+='<button class="meadow-mapping-btn meadow-mapping-btn-primary meadow-mapping-btn-small" onclick="window._Pict.views[\''+tmpViewID+'\'].openMappingDetail('+tmpMap.IDProjectionMapping+')">Edit</button> ';tmpHtml+='<button class="meadow-mapping-btn meadow-mapping-btn-danger meadow-mapping-btn-small" onclick="window._Pict.views[\''+tmpViewID+'\'].deleteMapping('+tmpMap.IDProjectionMapping+')">Delete</button>';tmpHtml+='</td>';tmpHtml+='</tr>';}tmpHtml+='</tbody></table>';tmpContainer.innerHTML=tmpHtml;}},{key:"newMapping",value:function newMapping(){var _this77=this;this._SelectedMappingID=0;var tmpMappingListWrap=document.getElementById('MeadowMap-List-Wrap');var tmpMappingDetail=document.getElementById('MeadowMap-Detail');if(tmpMappingListWrap)tmpMappingListWrap.style.display='none';if(tmpMappingDetail)tmpMappingDetail.style.display='';// Reset fields
3091
+ var tmpNameInput=document.getElementById('MeadowMap-Name');if(tmpNameInput)tmpNameInput.value='';// Populate source dropdown -- auto-select the first source if one exists.
3092
+ // _DiscoveredFields for that source is already populated from the
3093
+ // source Columns loaded in editMappings(), so _rebuildFlowNodes
3094
+ // will immediately show the source fields on the SRC node.
3095
+ var tmpAutoSourceID=this._MappingSources.length>0?this._MappingSources[0].IDSource:undefined;this._populateSourceDropdown(tmpAutoSourceID);this._populateStoreChecklist();// Clear JSON editor
3096
+ var tmpJSONTextarea=document.getElementById('MeadowMap-JSON');if(tmpJSONTextarea){var tmpNewEntityName=(this._EditingName||'Record').replace(/[^a-zA-Z0-9_]/g,'');var tmpNewGUIDCol='GUID'+tmpNewEntityName;var tmpNewIDCol='ID'+tmpNewEntityName;var tmpNewMappings={};tmpNewMappings[tmpNewGUIDCol]='{~D:Record.IDRecord~}';tmpNewMappings[tmpNewIDCol]='{~D:Record.IDRecord~}';tmpJSONTextarea.value=JSON.stringify({Entity:tmpNewEntityName,GUIDTemplate:'{~D:Record.IDRecord~}',GUIDName:tmpNewGUIDCol,Mappings:tmpNewMappings,Solvers:[],ManyfestAddresses:false},null,'\t');}// Clear flow container
3097
+ var tmpFlowContainer=document.getElementById('MeadowMap-Flow-Container');if(tmpFlowContainer)tmpFlowContainer.innerHTML='';this._FlowView=null;// Switch to flow mode and initialize the flow editor
3098
+ this.switchMapMode('flow');this.initFlowView();// Fetch fresh schema then build TGT node ports from schema columns
3099
+ this._doLoadTargetSchema(this._EditingContextID).then(function(pSchema){if(pSchema&&pSchema.SchemaDefinition){_this77._CurrentTargetSchema=pSchema.SchemaDefinition;}_this77._rebuildFlowNodes();});}},{key:"openMappingDetail",value:function openMappingDetail(pMappingID){var _this78=this;this._SelectedMappingID=pMappingID;this._doLoadMapping(pMappingID).then(function(pResponse){if(!pResponse||!pResponse.Mapping){_this78._doToast('Mapping not found.','error');return;}var tmpMapping=pResponse.Mapping;var tmpMappingListWrap=document.getElementById('MeadowMap-List-Wrap');var tmpMappingDetail=document.getElementById('MeadowMap-Detail');if(tmpMappingListWrap)tmpMappingListWrap.style.display='none';if(tmpMappingDetail)tmpMappingDetail.style.display='';// Set name
3100
+ var tmpNameInput=document.getElementById('MeadowMap-Name');if(tmpNameInput)tmpNameInput.value=tmpMapping.Name||'';// Populate dropdowns
3101
+ _this78._populateSourceDropdown(tmpMapping.IDSource);// Parse TargetStores from config, fall back to legacy IDProjectionStore
3102
+ var tmpTargetStores=null;try{var tmpParsedConfig=JSON.parse(tmpMapping.MappingConfiguration||'{}');if(Array.isArray(tmpParsedConfig.TargetStores)&&tmpParsedConfig.TargetStores.length>0){tmpTargetStores=tmpParsedConfig.TargetStores;}}catch(e){/* ignore */}if(!tmpTargetStores&&tmpMapping.IDProjectionStore){tmpTargetStores=[tmpMapping.IDProjectionStore];}_this78._populateStoreChecklist(tmpTargetStores);// Parse mapping config
3103
+ var tmpConfig={};try{tmpConfig=JSON.parse(tmpMapping.MappingConfiguration||'{}');}catch(e){/* ignore */}// Restore discovered source fields from config (config-driven approach).
3104
+ // sourceColumns is written by saveMapping() so the SRC node shows
3105
+ // all fields immediately without an extra API call.
3106
+ if(Array.isArray(tmpConfig.sourceColumns)&&tmpConfig.sourceColumns.length>0){_this78._DiscoveredFields[tmpMapping.IDSource]=tmpConfig.sourceColumns;}// Set JSON editor
3107
+ var tmpJSONTextarea=document.getElementById('MeadowMap-JSON');if(tmpJSONTextarea){tmpJSONTextarea.value=JSON.stringify(tmpConfig,null,'\t');}// Clear flow container and re-initialize
3108
+ var tmpFlowContainer=document.getElementById('MeadowMap-Flow-Container');if(tmpFlowContainer)tmpFlowContainer.innerHTML='';_this78._FlowView=null;// Switch to flow mode and initialize the flow editor
3109
+ _this78.switchMapMode('flow');_this78.initFlowView();// Fetch fresh schema then build TGT node ports from schema columns
3110
+ _this78._doLoadTargetSchema(_this78._EditingContextID).then(function(pSchema){if(pSchema&&pSchema.SchemaDefinition){_this78._CurrentTargetSchema=pSchema.SchemaDefinition;}// Restore saved flow diagram state if available,
3111
+ // then rebuild ports from current schema (schema is
3112
+ // the source of truth for ports, not saved state).
3113
+ if(_this78._FlowView){var tmpFlowState=null;try{tmpFlowState=JSON.parse(tmpMapping.FlowDiagramState||'null');}catch(pParseError){/* ignore invalid JSON */}if(tmpFlowState&&tmpFlowState.Nodes&&tmpFlowState.Nodes.length>0){if(typeof _this78._FlowView.setFlowData==='function'){_this78._FlowView.setFlowData(tmpFlowState);}}}// Always rebuild SRC/TGT ports from current schema
3114
+ // after restoring positions and connections
3115
+ _this78._rebuildFlowNodes();});});}},{key:"deleteMapping",value:function(){var _deleteMapping=_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(pMappingID){var _this79=this;var tmpConfirmed;return _regenerator().w(function(_context){while(1)switch(_context.n){case 0:_context.n=1;return this._doConfirm('Delete this mapping?',{title:'Delete Mapping',confirmLabel:'Delete',dangerous:true});case 1:tmpConfirmed=_context.v;if(tmpConfirmed){_context.n=2;break;}return _context.a(2);case 2:this._doDeleteMapping(pMappingID).then(function(){_this79._doLoadMappings(_this79._EditingContextID).then(function(pResult){_this79._CurrentMappings=pResult&&pResult.Mappings?pResult.Mappings:[];_this79.refreshMappingList();});});case 3:return _context.a(2);}},_callee,this);}));function deleteMapping(_x){return _deleteMapping.apply(this,arguments);}return deleteMapping;}()},{key:"switchMapMode",value:function switchMapMode(pMode){this._MapEditorMode=pMode;var tmpFlowWrap=document.getElementById('MeadowMap-Flow-Wrap');var tmpJSONWrap=document.getElementById('MeadowMap-JSON-Wrap');var tmpFlowTab=document.getElementById('MeadowMap-Mode-Flow');var tmpJSONTab=document.getElementById('MeadowMap-Mode-JSON');if(pMode==='flow'){if(tmpFlowWrap)tmpFlowWrap.style.display='';if(tmpJSONWrap)tmpJSONWrap.style.display='none';if(tmpFlowTab)tmpFlowTab.classList.add('active');if(tmpJSONTab)tmpJSONTab.classList.remove('active');}else{if(tmpFlowWrap)tmpFlowWrap.style.display='none';if(tmpJSONWrap)tmpJSONWrap.style.display='';if(tmpFlowTab)tmpFlowTab.classList.remove('active');if(tmpJSONTab)tmpJSONTab.classList.add('active');// If there's a flow view, serialize flow -> JSON
3116
+ if(this._FlowView&&typeof this._FlowView.getFlowData==='function'){var tmpConfig=this.flowToMappingConfig();var tmpJSONTextarea=document.getElementById('MeadowMap-JSON');if(tmpJSONTextarea){tmpJSONTextarea.value=JSON.stringify(tmpConfig,null,'\t');}}}}},{key:"_populateSourceDropdown",value:function _populateSourceDropdown(pSelectedIDSource){var tmpSelect=document.getElementById('MeadowMap-Source');if(!tmpSelect)return;var tmpHtml='<option value="0">Select a source...</option>';for(var i=0;i<this._MappingSources.length;i++){var tmpSrc=this._MappingSources[i];var tmpSelected=tmpSrc.IDSource===pSelectedIDSource?' selected':'';tmpHtml+='<option value="'+tmpSrc.IDSource+'"'+tmpSelected+'>'+(tmpSrc.Name||'Source '+tmpSrc.IDSource)+'</option>';}tmpSelect.innerHTML=tmpHtml;}},{key:"_populateStoreChecklist",value:function _populateStoreChecklist(pSelectedStoreIDs){var tmpContainer=document.getElementById('MeadowMap-Stores');if(!tmpContainer)return;var tmpSelectedSet={};if(Array.isArray(pSelectedStoreIDs)){for(var i=0;i<pSelectedStoreIDs.length;i++){tmpSelectedSet[pSelectedStoreIDs[i]]=true;}}else if(pSelectedStoreIDs){// Backwards compat: single IDProjectionStore value
3117
+ tmpSelectedSet[pSelectedStoreIDs]=true;}if(this._MappingStores.length===0){tmpContainer.innerHTML='<div style="font-size:0.82em; color:var(--facto-text-tertiary, #a09070);">No stores configured yet.</div>';return;}var tmpHtml='';for(var _i57=0;_i57<this._MappingStores.length;_i57++){var tmpStore=this._MappingStores[_i57];var tmpChecked=tmpSelectedSet[tmpStore.IDProjectionStore]?' checked':'';var tmpLabel=(tmpStore.TargetTableName||'Store '+tmpStore.IDProjectionStore)+' ('+(tmpStore.Status||'Unknown')+')';tmpHtml+='<label>';tmpHtml+='<input type="checkbox" value="'+tmpStore.IDProjectionStore+'"'+tmpChecked+'>';tmpHtml+=' '+tmpLabel;tmpHtml+='</label>';}tmpContainer.innerHTML=tmpHtml;}},{key:"_getCheckedStoreIDs",value:function _getCheckedStoreIDs(){var tmpContainer=document.getElementById('MeadowMap-Stores');if(!tmpContainer)return[];var tmpChecked=tmpContainer.querySelectorAll('input[type="checkbox"]:checked');var tmpIDs=[];for(var i=0;i<tmpChecked.length;i++){tmpIDs.push(parseInt(tmpChecked[i].value,10));}return tmpIDs;}},{key:"discoverSourceFields",value:function discoverSourceFields(){var _this80=this;var tmpSourceSelect=document.getElementById('MeadowMap-Source');var tmpIDSource=tmpSourceSelect?parseInt(tmpSourceSelect.value,10):0;if(!tmpIDSource){this._doToast('Select a source first.',{type:'warning'});return;}this._doDiscoverSourceFields(this._EditingContextID,tmpIDSource,50).then(function(pResponse){if(pResponse&&pResponse.Error){_this80._doToast('Error: '+pResponse.Error,{type:'error'});return;}var tmpHeaders=pResponse&&pResponse.Headers?pResponse.Headers:[];_this80._DiscoveredFields[tmpIDSource]=tmpHeaders;_this80._doToast('Discovered '+tmpHeaders.length+' fields from '+(pResponse.SampleSize||0)+' records: '+tmpHeaders.join(', '),{type:'success',duration:6000});// Rebuild the flow if it exists
3118
+ _this80._rebuildFlowNodes();});}},{key:"_rebuildFlowNodes",value:function _rebuildFlowNodes(){// Get current source and schema columns
3119
+ var tmpSourceSelect=document.getElementById('MeadowMap-Source');var tmpIDSource=tmpSourceSelect?parseInt(tmpSourceSelect.value,10):0;var tmpFields=this._DiscoveredFields[tmpIDSource]||[];// Get schema columns from the target
3120
+ var tmpSchemaColumns=this._getSchemaColumns();// Initialize the flow view if needed
3121
+ this.initFlowView();if(!this._FlowView)return;var tmpSourceTitle='Source: '+(tmpSourceSelect&&tmpSourceSelect.selectedIndex>=0?tmpSourceSelect.options[tmpSourceSelect.selectedIndex].text:'Source');var tmpTargetTitle='Target: '+(this._EditingName||'Target');// Build deterministic source ports (Whole Record + discovered fields)
3122
+ var tmpSourcePorts=[{Hash:'src-whole-record',Direction:'output',Side:'right',Label:'Whole Record'}];for(var i=0;i<tmpFields.length;i++){tmpSourcePorts.push({Hash:'src-field-'+tmpFields[i].replace(/[^a-zA-Z0-9_-]/g,'_'),Direction:'output',Side:'right',Label:tmpFields[i]});}// Build deterministic target ports -- entity-specific GUID and ID are always present
3123
+ var tmpEntityName=(this._EditingName||'Record').replace(/[^a-zA-Z0-9_]/g,'');var tmpGUIDColumnName='GUID'+tmpEntityName;var tmpIDColumnName='ID'+tmpEntityName;var tmpTargetPorts=[{Hash:'tgt-col-'+tmpGUIDColumnName,Direction:'input',Side:'left',Label:tmpGUIDColumnName},{Hash:'tgt-col-'+tmpIDColumnName,Direction:'input',Side:'left',Label:tmpIDColumnName}];for(var _i58=0;_i58<tmpSchemaColumns.length;_i58++){// Skip entity GUID/ID if they appear in schema columns (already added above)
3124
+ if(tmpSchemaColumns[_i58]===tmpGUIDColumnName||tmpSchemaColumns[_i58]===tmpIDColumnName)continue;tmpTargetPorts.push({Hash:'tgt-col-'+tmpSchemaColumns[_i58].replace(/[^a-zA-Z0-9_-]/g,'_'),Direction:'input',Side:'left',Label:tmpSchemaColumns[_i58]});}// Find existing SRC and TGT nodes (preserve user-added TPL/SOL nodes)
3125
+ var tmpFlowData=this._FlowView.getFlowData();var tmpSrcNode=null;var tmpTgtNode=null;for(var _i59=0;_i59<tmpFlowData.Nodes.length;_i59++){if(tmpFlowData.Nodes[_i59].Type==='SRC')tmpSrcNode=tmpFlowData.Nodes[_i59];if(tmpFlowData.Nodes[_i59].Type==='TGT')tmpTgtNode=tmpFlowData.Nodes[_i59];}if(tmpSrcNode){// Merge source ports: start with newly built ports, then preserve
3126
+ // any existing ports from the saved state (e.g. previously discovered
3127
+ // fields) that aren't already in the new set.
3128
+ var tmpMergedSrcPorts=tmpSourcePorts.slice();var tmpSrcPortHashes={};for(var p=0;p<tmpMergedSrcPorts.length;p++){tmpSrcPortHashes[tmpMergedSrcPorts[p].Hash]=true;}var tmpExistingPorts=tmpSrcNode.Ports||[];for(var _p=0;_p<tmpExistingPorts.length;_p++){if(!tmpSrcPortHashes[tmpExistingPorts[_p].Hash]){tmpMergedSrcPorts.push(tmpExistingPorts[_p]);}}// Update existing source node in-place
3129
+ var tmpInternalNodes=this._FlowView._FlowData.Nodes;for(var _i60=0;_i60<tmpInternalNodes.length;_i60++){if(tmpInternalNodes[_i60].Hash===tmpSrcNode.Hash){tmpInternalNodes[_i60].Ports=tmpMergedSrcPorts;tmpInternalNodes[_i60].Title=tmpSourceTitle;break;}}}else{// Push directly into _FlowData.Nodes to avoid addNode() rendering with empty ports
3130
+ this._FlowView._FlowData.Nodes.push({Hash:'node-src-'+this.fable.getUUID(),Type:'SRC',X:50,Y:50,Width:200,Height:100,Title:tmpSourceTitle,Ports:tmpSourcePorts,Data:{}});}if(tmpTgtNode){// Target ports: schema is the source of truth. Start with schema-
3131
+ // derived ports, then preserve any extra existing ports (e.g. user-
3132
+ // added custom columns) that aren't already in the new set.
3133
+ var tmpMergedTgtPorts=tmpTargetPorts.slice();var tmpTgtPortHashes={};for(var _p2=0;_p2<tmpMergedTgtPorts.length;_p2++){tmpTgtPortHashes[tmpMergedTgtPorts[_p2].Hash]=true;}var tmpExistingTgtPorts=tmpTgtNode.Ports||[];for(var _p3=0;_p3<tmpExistingTgtPorts.length;_p3++){if(!tmpTgtPortHashes[tmpExistingTgtPorts[_p3].Hash]){tmpMergedTgtPorts.push(tmpExistingTgtPorts[_p3]);}}// Update existing target node in-place
3134
+ var _tmpInternalNodes=this._FlowView._FlowData.Nodes;for(var _i61=0;_i61<_tmpInternalNodes.length;_i61++){if(_tmpInternalNodes[_i61].Hash===tmpTgtNode.Hash){_tmpInternalNodes[_i61].Ports=tmpMergedTgtPorts;_tmpInternalNodes[_i61].Title=tmpTargetTitle;break;}}}else{// Push directly into _FlowData.Nodes to avoid addNode() rendering with empty ports
3135
+ this._FlowView._FlowData.Nodes.push({Hash:'node-tgt-'+this.fable.getUUID(),Type:'TGT',X:550,Y:50,Width:200,Height:100,Title:tmpTargetTitle,Ports:tmpTargetPorts,Data:{}});}// Render the flow once with all ports correctly set
3136
+ if(typeof this._FlowView.renderFlow==='function'){this._FlowView.renderFlow();}else if(typeof this._FlowView.render==='function'){this._FlowView.render();}}},{key:"_getSchemaColumns",value:function _getSchemaColumns(){// Use the locally cached schema definition
3137
+ var tmpColumns=[];var tmpDDL=this._CurrentTargetSchema||'';if(tmpDDL){var tmpParsedColumns=libSchemaUtils.microDDLToColumns(tmpDDL);for(var j=0;j<tmpParsedColumns.length;j++){tmpColumns.push(tmpParsedColumns[j].Name);}}return tmpColumns;}},{key:"initFlowView",value:function initFlowView(){if(this._FlowView)return;var tmpFlowContainer=document.getElementById('MeadowMap-Flow-Container');if(!tmpFlowContainer)return;try{var libPictSectionFlow=require('pict-section-flow');this._FlowView=this.pict.addView('MeadowMapping-Flow',{ViewIdentifier:'MeadowMapping-Flow',DefaultDestinationAddress:'#MeadowMap-Flow-Container',EnableToolbar:true,EnablePanning:true,EnableZooming:true,EnableNodeDragging:true,EnableConnectionCreation:true},libPictSectionFlow);// Register card types
3138
+ var libFlowCardSource=require('./flow-cards/FlowCard-MappingSource.js');var libFlowCardTarget=require('./flow-cards/FlowCard-MappingTarget.js');var libFlowCardTemplate=require('./flow-cards/FlowCard-TemplateExpression.js');var libFlowCardSolver=require('./flow-cards/FlowCard-SolverExpression.js');this.pict.addServiceType('FlowCardMappingSource',libFlowCardSource);this.pict.addServiceType('FlowCardMappingTarget',libFlowCardTarget);this.pict.addServiceType('FlowCardTemplateExpression',libFlowCardTemplate);this.pict.addServiceType('FlowCardSolverExpression',libFlowCardSolver);// Render the flow view first so _NodeTypeProvider is initialized
3139
+ if(typeof this._FlowView.render==='function'){this._FlowView.render();}// Register card types with the flow view (must happen after render
3140
+ // so _NodeTypeProvider exists)
3141
+ var tmpSourceCard=this.pict.instantiateServiceProviderWithoutRegistration('FlowCardMappingSource',{});var tmpTargetCard=this.pict.instantiateServiceProviderWithoutRegistration('FlowCardMappingTarget',{});var tmpTemplateCard=this.pict.instantiateServiceProviderWithoutRegistration('FlowCardTemplateExpression',{});var tmpSolverCard=this.pict.instantiateServiceProviderWithoutRegistration('FlowCardSolverExpression',{});tmpSourceCard.registerWithFlowView(this._FlowView);tmpTargetCard.registerWithFlowView(this._FlowView);tmpTemplateCard.registerWithFlowView(this._FlowView);tmpSolverCard.registerWithFlowView(this._FlowView);}catch(pFlowError){this.log.error('Failed to initialize flow view: '+pFlowError.message);tmpFlowContainer.innerHTML='<div style="padding:2em; text-align:center; color:var(--facto-text-tertiary, #a09070);">Flow editor could not be loaded. Use JSON Config mode instead.</div>';}}},{key:"flowToMappingConfig",value:function flowToMappingConfig(){var tmpEntityName=(this._EditingName||'Record').replace(/[^a-zA-Z0-9_]/g,'');var tmpGUIDColumnName='GUID'+tmpEntityName;var tmpIDColumnName='ID'+tmpEntityName;var tmpConfig={Entity:tmpEntityName,GUIDTemplate:'{~D:Record.IDRecord~}',GUIDName:tmpGUIDColumnName,Mappings:{},Solvers:[],ManyfestAddresses:false};if(!this._FlowView||typeof this._FlowView.getFlowData!=='function'){return tmpConfig;}var tmpFlowData=this._FlowView.getFlowData();if(!tmpFlowData||!tmpFlowData.Connections)return tmpConfig;// Build node hash->node map and port hash->{Label, NodeHash, NodeType} map
3142
+ var tmpNodeMap={};var tmpPortMap={};if(tmpFlowData.Nodes){for(var i=0;i<tmpFlowData.Nodes.length;i++){var tmpNode=tmpFlowData.Nodes[i];tmpNodeMap[tmpNode.Hash]=tmpNode;if(tmpNode.Ports){for(var j=0;j<tmpNode.Ports.length;j++){tmpPortMap[tmpNode.Ports[j].Hash]={Label:tmpNode.Ports[j].Label,NodeHash:tmpNode.Hash,NodeType:tmpNode.Type};}}}}// Track solver nodes that connect to multiple target columns
3143
+ var tmpSolverEntries={};// Process each connection where the target is a TGT node
3144
+ for(var _i62=0;_i62<tmpFlowData.Connections.length;_i62++){var tmpConn=tmpFlowData.Connections[_i62];var tmpSourcePort=tmpPortMap[tmpConn.SourcePortHash];var tmpTargetPort=tmpPortMap[tmpConn.TargetPortHash];if(!tmpSourcePort||!tmpTargetPort)continue;// Only process connections that end at a TGT node
3145
+ if(tmpTargetPort.NodeType!=='TGT')continue;var tmpTargetColumn=tmpTargetPort.Label;if(!tmpTargetColumn)continue;var tmpSourceNode=tmpNodeMap[tmpSourcePort.NodeHash];if(!tmpSourceNode)continue;if(tmpSourceNode.Type==='SRC'){// Direct mapping: SRC field -> TGT column
3146
+ var tmpSourceField=tmpSourcePort.Label;// Skip "Whole Record" direct connections to TGT (need intermediate node)
3147
+ if(tmpSourceField==='Whole Record')continue;var tmpTemplate=tmpConn.Data&&tmpConn.Data.Template?tmpConn.Data.Template:'{~D:Record.'+tmpSourceField+'~}';// Connection to the entity GUID port sets the GUIDTemplate for upsert uniqueness
3148
+ if(tmpTargetColumn===tmpGUIDColumnName){tmpConfig.GUIDTemplate=tmpTemplate;}tmpConfig.Mappings[tmpTargetColumn]=tmpTemplate;}else if(tmpSourceNode.Type==='TPL'){// Template expression: TPL result -> TGT column
3149
+ var tmpExpression=tmpSourceNode.Data&&tmpSourceNode.Data.TemplateExpression?tmpSourceNode.Data.TemplateExpression:'';if(tmpExpression){// TPL connected to entity GUID sets the GUIDTemplate
3150
+ if(tmpTargetColumn===tmpGUIDColumnName){tmpConfig.GUIDTemplate=tmpExpression;}tmpConfig.Mappings[tmpTargetColumn]=tmpExpression;}}else if(tmpSourceNode.Type==='SOL'){// Solver expression: SOL result -> TGT column
3151
+ var _tmpExpression=tmpSourceNode.Data&&tmpSourceNode.Data.SolverExpression?tmpSourceNode.Data.SolverExpression:'';if(_tmpExpression){// Group outputs for the same solver node
3152
+ if(!tmpSolverEntries[tmpSourceNode.Hash]){tmpSolverEntries[tmpSourceNode.Hash]={expression:_tmpExpression,outputs:{}};}tmpSolverEntries[tmpSourceNode.Hash].outputs[tmpTargetColumn]=true;}}}// Ensure entity-specific GUID and ID are always present in Mappings
3153
+ if(!tmpConfig.Mappings.hasOwnProperty(tmpGUIDColumnName)){tmpConfig.Mappings[tmpGUIDColumnName]=tmpConfig.GUIDTemplate;}if(!tmpConfig.Mappings.hasOwnProperty(tmpIDColumnName)){tmpConfig.Mappings[tmpIDColumnName]='{~D:Record.IDRecord~}';}// Add grouped solver entries
3154
+ var tmpSolverKeys=Object.keys(tmpSolverEntries);for(var _i63=0;_i63<tmpSolverKeys.length;_i63++){tmpConfig.Solvers.push(tmpSolverEntries[tmpSolverKeys[_i63]]);}return tmpConfig;}},{key:"saveMapping",value:function saveMapping(){var _this81=this;var tmpNameInput=document.getElementById('MeadowMap-Name');var tmpSourceSelect=document.getElementById('MeadowMap-Source');var tmpName=tmpNameInput?tmpNameInput.value.trim():'';var tmpIDSource=tmpSourceSelect?parseInt(tmpSourceSelect.value,10):0;var tmpCheckedStoreIDs=this._getCheckedStoreIDs();var tmpIDProjectionStore=tmpCheckedStoreIDs.length>0?tmpCheckedStoreIDs[0]:0;if(!tmpName){this._doToast('Enter a mapping name.',{type:'warning'});return;}// Get mapping config
3155
+ var tmpMappingConfig;if(this._MapEditorMode==='json'){var tmpJSONTextarea=document.getElementById('MeadowMap-JSON');var tmpJSON=tmpJSONTextarea?tmpJSONTextarea.value:'{}';try{tmpMappingConfig=JSON.parse(tmpJSON);}catch(e){this._doToast('Invalid JSON: '+e.message,{type:'error'});return;}}else{tmpMappingConfig=this.flowToMappingConfig();}// Store target stores in the mapping config
3156
+ tmpMappingConfig.TargetStores=tmpCheckedStoreIDs;// Persist discovered source columns so the SRC node loads correctly
3157
+ // on next open without requiring a separate API call.
3158
+ var tmpSavedColumns=this._DiscoveredFields[tmpIDSource];if(Array.isArray(tmpSavedColumns)&&tmpSavedColumns.length>0){tmpMappingConfig.sourceColumns=tmpSavedColumns;}// Get flow diagram state
3159
+ var tmpFlowState={};if(this._FlowView&&typeof this._FlowView.getFlowData==='function'){tmpFlowState=this._FlowView.getFlowData();}var tmpData={Name:tmpName,IDSource:tmpIDSource,IDProjectionStore:tmpIDProjectionStore,MappingConfiguration:JSON.stringify(tmpMappingConfig),FlowDiagramState:JSON.stringify(tmpFlowState),Active:1};var tmpPromise;if(this._SelectedMappingID){tmpPromise=this._doUpdateMapping(this._SelectedMappingID,tmpData);}else{tmpPromise=this._doCreateMapping(this._EditingContextID,tmpData);}tmpPromise.then(function(pResponse){if(pResponse&&pResponse.Error){_this81._doToast('Error: '+pResponse.Error,{type:'error'});return;}// Update the selected mapping ID if it was a create
3160
+ if(pResponse&&pResponse.Mapping&&pResponse.Mapping.IDProjectionMapping){_this81._SelectedMappingID=pResponse.Mapping.IDProjectionMapping;}_this81._doToast('Mapping saved.',{type:'success'});// Refresh mapping list
3161
+ _this81._doLoadMappings(_this81._EditingContextID).then(function(pResult){_this81._CurrentMappings=pResult&&pResult.Mappings?pResult.Mappings:[];});});}}]);}(libPictView);module.exports=MeadowMappingEditorView;module.exports.default_configuration=_ViewConfiguration;},{"./MappingEditor-SchemaUtils.js":46,"./flow-cards/FlowCard-MappingSource.js":48,"./flow-cards/FlowCard-MappingTarget.js":49,"./flow-cards/FlowCard-SolverExpression.js":50,"./flow-cards/FlowCard-TemplateExpression.js":51,"pict-section-flow":9,"pict-view":45}],48:[function(require,module,exports){var libPictFlowCard=require('pict-section-flow').PictFlowCard;/**
3162
+ * FlowCard-MappingSource
3163
+ *
3164
+ * Represents a source dataset in the mapping flow.
3165
+ * Output ports are dynamically generated from discovered fields.
3166
+ */var FlowCardMappingSource=/*#__PURE__*/function(_libPictFlowCard){function FlowCardMappingSource(pFable,pOptions,pServiceHash){var _this82;_classCallCheck(this,FlowCardMappingSource);var tmpOptions=Object.assign({},{Title:'Mapping Source',Name:'Mapping Source',Code:'SRC',Category:'Data Source',Description:'Source dataset with discovered record fields',TitleBarColor:'#2980b9',Width:200,Height:100,Inputs:[],Outputs:[{Name:'Whole Record',Side:'right'}],ShowTypeLabel:true,PortLabelsOnHover:false,PortLabelsOutside:true},pOptions);_this82=_callSuper(this,FlowCardMappingSource,[pFable,tmpOptions,pServiceHash]);_this82.serviceType='FlowCardMappingSource';return _this82;}_inherits(FlowCardMappingSource,_libPictFlowCard);return _createClass(FlowCardMappingSource);}(libPictFlowCard);module.exports=FlowCardMappingSource;module.exports.default_configuration={Title:'Mapping Source',Code:'SRC',Category:'Data Source',TitleBarColor:'#2980b9',Width:200,Height:100};},{"pict-section-flow":9}],49:[function(require,module,exports){var libPictFlowCard=require('pict-section-flow').PictFlowCard;/**
3167
+ * FlowCard-MappingTarget
3168
+ *
3169
+ * Represents the mapping target table in the mapping flow.
3170
+ * Input ports are dynamically generated from schema columns.
3171
+ */var FlowCardMappingTarget=/*#__PURE__*/function(_libPictFlowCard2){function FlowCardMappingTarget(pFable,pOptions,pServiceHash){var _this83;_classCallCheck(this,FlowCardMappingTarget);var tmpOptions=Object.assign({},{Title:'Mapping Target',Name:'Mapping Target',Code:'TGT',Category:'Data Target',Description:'Mapping target table with schema columns',TitleBarColor:'#27ae60',Width:200,Height:100,Inputs:[],Outputs:[],ShowTypeLabel:true,PortLabelsOnHover:false,PortLabelsOutside:true},pOptions);_this83=_callSuper(this,FlowCardMappingTarget,[pFable,tmpOptions,pServiceHash]);_this83.serviceType='FlowCardMappingTarget';return _this83;}_inherits(FlowCardMappingTarget,_libPictFlowCard2);return _createClass(FlowCardMappingTarget);}(libPictFlowCard);module.exports=FlowCardMappingTarget;module.exports.default_configuration={Title:'Mapping Target',Code:'TGT',Category:'Data Target',TitleBarColor:'#27ae60',Width:200,Height:100};},{"pict-section-flow":9}],50:[function(require,module,exports){var libPictFlowCard=require('pict-section-flow').PictFlowCard;/**
3172
+ * FlowCard-SolverExpression
3173
+ *
3174
+ * A transform card that applies a Fable ExpressionParser solver expression
3175
+ * to compute a derived value from the whole incoming record. Connect the
3176
+ * Source "Whole Record" output to this card's input, then connect this
3177
+ * card's output to a target column.
3178
+ *
3179
+ * Double-click the node to edit the solver expression in the properties panel.
3180
+ *
3181
+ * @class FlowCardSolverExpression
3182
+ * @extends PictFlowCard
3183
+ */var FlowCardSolverExpression=/*#__PURE__*/function(_libPictFlowCard3){function FlowCardSolverExpression(pFable,pOptions,pServiceHash){var _this84;_classCallCheck(this,FlowCardSolverExpression);var tmpOptions=Object.assign({},{Title:'Solver Expression',Name:'Solver Expression',Code:'SOL',Category:'Transform',Description:'Apply a Fable solver expression for conditional logic and computed values',TitleBarColor:'#d35400',Width:220,Height:90,Inputs:[{Name:'Whole Record',Side:'left'}],Outputs:[{Name:'Result',Side:'right'}],ShowTypeLabel:true,PortLabelsOnHover:false,PortLabelsOutside:true,LabelsInFront:true,Enabled:true,BodyContent:{ContentType:'html',Template:'<div style="font-size:10px; padding:2px 4px; color:#ccc; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; max-width:200px;">{~D:Record.Data.SolverExpression~}</div>'},PropertiesPanel:{PanelType:'Template',DefaultWidth:420,DefaultHeight:160,Title:'Solver Expression',Configuration:{Template:'<div style="padding:8px;"><label style="display:block; margin-bottom:4px; font-weight:bold; font-size:12px;">Solver Expression</label><textarea id="FlowCard-SOL-{~D:Record.Hash~}" style="width:100%; height:80px; font-family:monospace; font-size:12px; resize:vertical; background:#1a1a2e; color:#e0e0e0; border:1px solid #444; border-radius:4px; padding:6px;" onchange="(function(el){var n=pict.views[\'MeadowMapping-Flow\'];if(n&&n._FlowData){for(var i=0;i<n._FlowData.Nodes.length;i++){if(n._FlowData.Nodes[i].Hash===\'{~D:Record.Hash~}\'){n._FlowData.Nodes[i].Data.SolverExpression=el.value;if(typeof n.renderFlow===\'function\')n.renderFlow();break;}}}})(this)">{~D:Record.Data.SolverExpression~}</textarea><div style="font-size:10px; color:#888; margin-top:4px;">Example: IF(IncomingRecord.Type == \'Premium\', \'GOLD\', \'SILVER\')</div></div>'}}},pOptions);_this84=_callSuper(this,FlowCardSolverExpression,[pFable,tmpOptions,pServiceHash]);_this84.serviceType='FlowCardSolverExpression';return _this84;}_inherits(FlowCardSolverExpression,_libPictFlowCard3);return _createClass(FlowCardSolverExpression);}(libPictFlowCard);module.exports=FlowCardSolverExpression;module.exports.default_configuration={Title:'Solver Expression',Code:'SOL',Category:'Transform',TitleBarColor:'#d35400',Width:220,Height:90};},{"pict-section-flow":9}],51:[function(require,module,exports){var libPictFlowCard=require('pict-section-flow').PictFlowCard;/**
3184
+ * FlowCard-TemplateExpression
3185
+ *
3186
+ * A transform card that applies a Manyfest template expression to the
3187
+ * whole incoming record. Connect the Source "Whole Record" output to this
3188
+ * card's input, then connect this card's output to a target column.
3189
+ *
3190
+ * Double-click the node to edit the template expression in the properties panel.
3191
+ *
3192
+ * @class FlowCardTemplateExpression
3193
+ * @extends PictFlowCard
3194
+ */var FlowCardTemplateExpression=/*#__PURE__*/function(_libPictFlowCard4){function FlowCardTemplateExpression(pFable,pOptions,pServiceHash){var _this85;_classCallCheck(this,FlowCardTemplateExpression);var tmpOptions=Object.assign({},{Title:'Template Expression',Name:'Template Expression',Code:'TPL',Category:'Transform',Description:'Apply a Manyfest template expression to map source fields to a target column',TitleBarColor:'#8e44ad',Width:220,Height:90,Inputs:[{Name:'Whole Record',Side:'left'}],Outputs:[{Name:'Result',Side:'right'}],ShowTypeLabel:true,PortLabelsOnHover:false,PortLabelsOutside:true,LabelsInFront:true,Enabled:true,BodyContent:{ContentType:'html',Template:'<div style="font-size:10px; padding:2px 4px; color:#ccc; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; max-width:200px;">{~D:Record.Data.TemplateExpression~}</div>'},PropertiesPanel:{PanelType:'Template',DefaultWidth:420,DefaultHeight:160,Title:'Template Expression',Configuration:{Template:'<div style="padding:8px;"><label style="display:block; margin-bottom:4px; font-weight:bold; font-size:12px;">Template Expression</label><textarea id="FlowCard-TPL-{~D:Record.Hash~}" style="width:100%; height:80px; font-family:monospace; font-size:12px; resize:vertical; background:#1a1a2e; color:#e0e0e0; border:1px solid #444; border-radius:4px; padding:6px;" onchange="(function(el){var n=pict.views[\'MeadowMapping-Flow\'];if(n&&n._FlowData){for(var i=0;i<n._FlowData.Nodes.length;i++){if(n._FlowData.Nodes[i].Hash===\'{~D:Record.Hash~}\'){n._FlowData.Nodes[i].Data.TemplateExpression=el.value;if(typeof n.renderFlow===\'function\')n.renderFlow();break;}}}})(this)">{~D:Record.Data.TemplateExpression~}</textarea><div style="font-size:10px; color:#888; margin-top:4px;">Use {~D:Record.FieldName~} syntax. Example: {~D:Record.Name~} in {~D:Record.City~}</div></div>'}}},pOptions);_this85=_callSuper(this,FlowCardTemplateExpression,[pFable,tmpOptions,pServiceHash]);_this85.serviceType='FlowCardTemplateExpression';return _this85;}_inherits(FlowCardTemplateExpression,_libPictFlowCard4);return _createClass(FlowCardTemplateExpression);}(libPictFlowCard);module.exports=FlowCardTemplateExpression;module.exports.default_configuration={Title:'Template Expression',Code:'TPL',Category:'Transform',TitleBarColor:'#8e44ad',Width:220,Height:90};},{"pict-section-flow":9}]},{},[1])(1);});
3195
+ //# sourceMappingURL=mapping-demo-editor.js.map