meadow-integration 1.0.20 → 1.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/example-applications/mapping-demo/.quackage.json +10 -0
- package/example-applications/mapping-demo/README.md +99 -0
- package/example-applications/mapping-demo/data/books-sample.csv +21 -0
- package/example-applications/mapping-demo/generate-build-config.js +44 -0
- package/example-applications/mapping-demo/mappings/books-to-book.json +14 -0
- package/example-applications/mapping-demo/package.json +14 -0
- package/example-applications/mapping-demo/server.js +814 -0
- package/example-applications/mapping-demo/source/MappingDemoApp.js +52 -0
- package/example-applications/mapping-demo/source/views/MappingDemoEditorView.js +186 -0
- package/example-applications/mapping-demo/web/index.html +892 -0
- package/example-applications/mapping-demo/web/mapping-demo-editor.js +3195 -0
- package/example-applications/mapping-demo/web/mapping-demo-editor.js.map +1 -0
- package/example-applications/mapping-demo/web/mapping-demo-editor.min.js +2 -0
- package/example-applications/mapping-demo/web/mapping-demo-editor.min.js.map +1 -0
- package/example-applications/mapping-demo/web/pict.min.js +12 -0
- package/package.json +8 -4
- package/source/Meadow-Integration-Browser.js +31 -0
- package/source/Meadow-Integration.js +16 -1
- package/source/services/certainty/Service-CertaintyAccumulator.js +402 -0
- package/source/services/clone/Meadow-Service-Sync-Entity-Initial.js +16 -3
- package/source/services/clone/Meadow-Service-Sync-Entity-Ongoing.js +15 -2
- package/source/services/clone/Meadow-Service-Sync.js +21 -0
- package/source/views/MappingEditor-SchemaUtils.js +71 -0
- package/source/views/PictView-MeadowMappingEditor.js +1299 -0
- package/source/views/flow-cards/FlowCard-MappingSource.js +50 -0
- package/source/views/flow-cards/FlowCard-MappingTarget.js +49 -0
- package/source/views/flow-cards/FlowCard-SolverExpression.js +78 -0
- package/source/views/flow-cards/FlowCard-TemplateExpression.js +77 -0
- 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()\">← 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='⛶ 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()\">← 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
|