@blockly/block-dynamic-connection
Advanced tools
Comparing version 0.4.3 to 0.5.0
/*! For license information please see index.js.LICENSE.txt */ | ||
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("blockly/core"));else if("function"==typeof define&&define.amd)define(["blockly/core"],e);else{var n="object"==typeof exports?e(require("blockly/core")):e(t.Blockly);for(var i in n)("object"==typeof exports?exports:t)[i]=n[i]}}(this,(t=>(()=>{"use strict";var e={573:e=>{e.exports=t}},n={};function i(t){var s=n[t];if(void 0!==s)return s.exports;var o=n[t]={exports:{}};return e[t](o,o.exports,i),o.exports}i.d=(t,e)=>{for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var s={};return(()=>{i.r(s),i.d(s,{overrideOldBlockDefinitions:()=>p});var t=i(573);t.InsertionMarkerManager.prototype.update=function(e,n){var i;const s=this.getCandidate(e);this.wouldDeleteBlock=this.shouldDelete(!!s,n),(this.wouldDeleteBlock||this.shouldUpdatePreviews(s,e))&&((null===(i=null==s?void 0:s.closest)||void 0===i?void 0:i.sourceBlock_.onPendingConnection)&&(s.closest.sourceBlock_.onPendingConnection(s.closest),this.pendingBlocks||(this.pendingBlocks=new Set),this.pendingBlocks.add(s.closest.sourceBlock_)),t.Events.disable(),this.maybeHidePreview(s),this.maybeShowPreview(s),t.Events.enable())};const e=t.InsertionMarkerManager.prototype.dispose;t.InsertionMarkerManager.prototype.dispose=function(){this.pendingBlocks&&this.pendingBlocks.forEach((t=>{t.finalizeConnections&&t.finalizeConnections()})),e.call(this)};const n={inputCounter:1,minInputs:1,init(){this.setHelpUrl(t.Msg.CONTROLS_IF_HELPURL),this.setStyle("logic_blocks"),this.appendValueInput("IF0").setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"),this.appendStatementInput("DO0").appendField(t.Msg.CONTROLS_IF_MSG_THEN),this.setNextStatement(!0),this.setPreviousStatement(!0),this.setTooltip(t.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom(){const e=t.utils.xml.createElement("mutation"),n=this.inputList.filter((t=>t.name.includes("IF"))).map((t=>t.name.replace("IF",""))).join(",");e.setAttribute("inputs",n);const i=!!this.getInput("ELSE");return e.setAttribute("else",String(i)),e.setAttribute("next",String(this.inputCounter)),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){var n;const i=e.getAttribute("inputs");if(i){const e=i.split(",");this.getInput("IF0")&&this.removeInput("IF0"),this.getInput("DO0")&&this.removeInput("DO0");const n=e[0];this.appendValueInput("IF"+n).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"),this.appendStatementInput("DO"+n).appendField(t.Msg.CONTROLS_IF_MSG_THEN);for(let n=1;n<e.length;n++)this.appendValueInput("IF"+e[n]).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF,"elseif"),this.appendStatementInput("DO"+e[n]).appendField(t.Msg.CONTROLS_IF_MSG_THEN)}"true"==e.getAttribute("else")&&this.appendStatementInput("ELSE").appendField(t.Msg.CONTROLS_IF_MSG_ELSE,"else");const s=parseInt(null!==(n=e.getAttribute("next"))&&void 0!==n?n:"0",10)||0;this.inputCounter=s},deserializeCounts(e){var n,i;const s=parseInt(null!==(n=e.getAttribute("elseif"))&&void 0!==n?n:"0",10)||0,o=parseInt(null!==(i=e.getAttribute("else"))&&void 0!==i?i:"0",10)||0;for(let e=1;e<=s;e++)this.appendValueInput("IF"+e).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF),this.appendStatementInput("DO"+e).appendField(t.Msg.CONTROLS_IF_MSG_THEN);o&&this.appendStatementInput("ELSE").appendField(t.Msg.CONTROLS_IF_MSG_ELSE),this.inputCounter=s+1},findInputIndexForConnection(t){for(let e=0;e<this.inputList.length;e++)if(this.inputList[e].connection==t)return e;return null},insertElseIf(e){const n=this.inputCounter;this.appendValueInput("IF"+n).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF,"elseif"),this.appendStatementInput("DO"+n).appendField(t.Msg.CONTROLS_IF_MSG_THEN),this.moveInputBefore("IF"+n,this.inputList[e].name),this.moveInputBefore("DO"+n,this.inputList[e+1].name),this.inputCounter++},onPendingConnection(e){e.type!==t.NEXT_STATEMENT||this.getInput("ELSE")||this.appendStatementInput("ELSE").appendField(t.Msg.CONTROLS_IF_MSG_ELSE,"else");const n=this.findInputIndexForConnection(e);if(null===n)return;const i=this.inputList[n];if(e.targetConnection&&i.name.includes("IF")){const t=this.inputList[n+2];if(t&&"ELSE"!=t.name){const e=t&&t.connection&&t.connection.targetConnection;e&&!e.getSourceBlock().isInsertionMarker()&&this.insertElseIf(n+2)}else this.insertElseIf(n+2)}},finalizeConnections(){var e,n,i,s,o;const u=[];for(let t=2;t<this.inputList.length-1;t+=2){const i=this.inputList[t],s=this.inputList[t+1];(null===(e=i.connection)||void 0===e?void 0:e.targetConnection)||(null===(n=s.connection)||void 0===n?void 0:n.targetConnection)||(u.push(i.name),u.push(s.name))}u.forEach((t=>this.removeInput(t)));const p=this.getInput("ELSE");if(p&&!(null===(i=p.connection)||void 0===i?void 0:i.targetConnection)&&this.removeInput(p.name),this.inputList.length>2){const e=this.inputList[0],n=this.inputList[1],i=this.inputList[2];!i.name.includes("IF")||(null===(s=e.connection)||void 0===s?void 0:s.targetConnection)||(null===(o=n.connection)||void 0===o?void 0:o.targetConnection)||(this.removeInput(e.name),this.removeInput(n.name),i.removeField("elseif"),i.appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"))}}};t.Blocks.dynamic_if=n;const o={inputCounter:2,minInputs:2,init(){this.setHelpUrl(t.Msg.TEXT_JOIN_HELPURL),this.setStyle("text_blocks"),this.appendValueInput("ADD0").appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH),this.appendValueInput("ADD1"),this.setOutput(!0,"String"),this.setTooltip(t.Msg.TEXT_JOIN_TOOLTIP)},mutationToDom(){const e=t.utils.xml.createElement("mutation"),n=this.inputList.map((t=>t.name)).join(",");return e.setAttribute("inputs",n),e.setAttribute("next",String(this.inputCounter)),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){var n;const i=e.getAttribute("inputs");if(i){const e=i.split(",");this.inputList=[],e.forEach((t=>this.appendValueInput(t))),this.inputList[0].appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH)}const s=parseInt(null!==(n=e.getAttribute("next"))&&void 0!==n?n:"0",10)||0;this.inputCounter=s},deserializeCounts(t){var e;const n=Math.max(parseInt(null!==(e=t.getAttribute("items"))&&void 0!==e?e:"0",10),this.minInputs);for(let t=this.minInputs;t<n;t++)this.appendValueInput("ADD"+t);this.inputCounter=n},getIndexForNewInput(t){var e;if(!t.targetConnection)return null;let n=-1;for(let e=0;e<this.inputList.length;e++)this.inputList[e].connection==t&&(n=e);if(n==this.inputList.length-1)return this.inputList.length+1;const i=this.inputList[n+1],s=null===(e=null==i?void 0:i.connection)||void 0===e?void 0:e.targetConnection;return s&&!s.getSourceBlock().isInsertionMarker()?n+1:null},onPendingConnection(t){const e=this.getIndexForNewInput(t);null!=e&&(this.appendValueInput("ADD"+this.inputCounter++),this.moveNumberedInputBefore(this.inputList.length-1,e))},finalizeConnections(){if(this.inputList.length>this.minInputs){let e=[];this.inputList.forEach((t=>{var n;(null===(n=t.connection)||void 0===n?void 0:n.targetConnection)||e.push(t.name)})),this.inputList.length-e.length<this.minInputs&&(e=e.slice(this.minInputs)),e.forEach((t=>this.removeInput(t))),0==this.inputList[0].fieldRow.length&&this.inputList[0].appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH)}}};t.Blocks.dynamic_text_join=o;const u={inputCounter:2,minInputs:2,init(){this.setHelpUrl(t.Msg.LISTS_CREATE_WITH_HELPURL),this.setStyle("list_blocks"),this.appendValueInput("ADD0").appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH),this.appendValueInput("ADD1"),this.setOutput(!0,"Array"),this.setTooltip(t.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom(){const e=t.utils.xml.createElement("mutation"),n=this.inputList.map((t=>t.name)).join(",");return e.setAttribute("inputs",n),e.setAttribute("next",String(this.inputCounter)),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){var n;const i=e.getAttribute("inputs");if(i){const e=i.split(",");this.inputList=[],e.forEach((t=>this.appendValueInput(t))),this.inputList[0].appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH)}const s=parseInt(null!==(n=e.getAttribute("next"))&&void 0!==n?n:"0",10)||0;this.inputCounter=s},deserializeCounts(t){var e;const n=Math.max(parseInt(null!==(e=t.getAttribute("items"))&&void 0!==e?e:"0",10),this.minInputs);for(let t=this.minInputs;t<n;t++)this.appendValueInput("ADD"+t);this.inputCounter=n},getIndexForNewInput(t){var e;if(!t.targetConnection)return null;let n=-1;for(let e=0;e<this.inputList.length;e++)this.inputList[e].connection==t&&(n=e);if(n==this.inputList.length-1)return this.inputList.length+1;const i=this.inputList[n+1],s=null===(e=null==i?void 0:i.connection)||void 0===e?void 0:e.targetConnection;return s&&!s.getSourceBlock().isInsertionMarker()?n+1:null},onPendingConnection(t){const e=this.getIndexForNewInput(t);null!=e&&(this.appendValueInput("ADD"+this.inputCounter++),this.moveNumberedInputBefore(this.inputList.length-1,e))},finalizeConnections(){if(this.inputList.length>this.minInputs){let e=[];this.inputList.forEach((t=>{var n;(null===(n=t.connection)||void 0===n?void 0:n.targetConnection)||e.push(t.name)})),this.inputList.length-e.length<this.minInputs&&(e=e.slice(this.minInputs)),e.forEach((t=>this.removeInput(t))),0==this.inputList[0].fieldRow.length&&this.inputList[0].appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH)}}};t.Blocks.dynamic_list_create=u;const p=function(){t.Blocks.lists_create_with=t.Blocks.dynamic_list_create,t.Blocks.text_join=t.Blocks.dynamic_text_join,t.Blocks.controls_if=t.Blocks.dynamic_if}})(),s})())); | ||
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("blockly/core"));else if("function"==typeof define&&define.amd)define(["blockly/core"],e);else{var n="object"==typeof exports?e(require("blockly/core")):e(t.Blockly);for(var i in n)("object"==typeof exports?exports:t)[i]=n[i]}}(this,(t=>(()=>{"use strict";var e={573:e=>{e.exports=t}},n={};function i(t){var s=n[t];if(void 0!==s)return s.exports;var o=n[t]={exports:{}};return e[t](o,o.exports,i),o.exports}i.d=(t,e)=>{for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var s={};return(()=>{i.r(s),i.d(s,{overrideOldBlockDefinitions:()=>u});var t=i(573);t.InsertionMarkerManager.prototype.update=function(e,n){var i;const s=this.getCandidate(e);this.wouldDeleteBlock=this.shouldDelete(!!s,n),(this.wouldDeleteBlock||this.shouldUpdatePreviews(s,e))&&((null===(i=null==s?void 0:s.closest)||void 0===i?void 0:i.sourceBlock_.onPendingConnection)&&(s.closest.sourceBlock_.onPendingConnection(s.closest),this.pendingBlocks||(this.pendingBlocks=new Set),this.pendingBlocks.add(s.closest.sourceBlock_)),t.Events.disable(),this.maybeHidePreview(s),this.maybeShowPreview(s),t.Events.enable())};const e=t.InsertionMarkerManager.prototype.dispose;t.InsertionMarkerManager.prototype.dispose=function(){this.pendingBlocks&&this.pendingBlocks.forEach((t=>{t.finalizeConnections&&t.finalizeConnections()})),e.call(this)};const n={minInputs:1,elseifCount:0,elseCount:0,init(){this.setHelpUrl(t.Msg.CONTROLS_IF_HELPURL),this.setStyle("logic_blocks"),this.addFirstCase(),this.setNextStatement(!0),this.setPreviousStatement(!0),this.setTooltip(t.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom(){if(t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable(),!this.elseifCount&&!this.elseCount)return null;const e=t.utils.xml.createElement("mutation");return this.elseifCount&&e.setAttribute("elseif",`${this.elseifCount}`),this.elseCount&&e.setAttribute("else","1"),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){const n=e.getAttribute("inputs");if(n){const e=n.split(",");this.getInput("IF0")&&this.removeInput("IF0"),this.getInput("DO0")&&this.removeInput("DO0");const i=e[0];this.appendValueInput("IF"+i).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"),this.appendStatementInput("DO"+i).appendField(t.Msg.CONTROLS_IF_MSG_THEN);for(let n=1;n<e.length;n++)this.appendValueInput("IF"+e[n]).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF,"elseif"),this.appendStatementInput("DO"+e[n]).appendField(t.Msg.CONTROLS_IF_MSG_THEN)}"true"==e.getAttribute("else")&&this.addElseInput()},deserializeCounts(t){var e,n;this.elseifCount=parseInt(null!==(e=t.getAttribute("elseif"))&&void 0!==e?e:"0",10)||0,this.elseCount=parseInt(null!==(n=t.getAttribute("else"))&&void 0!==n?n:"0",10)||0;for(let t=1;t<=this.elseifCount;t++)this.insertElseIf(this.inputList.length,t);this.elseCount&&this.addElseInput()},saveExtraState:function(){if(t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable(),!this.elseifCount&&!this.elseCount)return null;const e=Object.create(null);return this.elseifCount&&(e.elseIfCount=this.elseifCount),this.elseCount&&(e.hasElse=!0),e},loadExtraState:function(e){if("string"!=typeof e){this.elseifCount=e.elseIfCount||0,this.elseCount=e.hasElse?1:0;for(let t=1;t<=this.elseifCount;t++)this.insertElseIf(this.inputList.length,t);this.elseCount&&this.addElseInput()}else this.domToMutation(t.utils.xml.textToDom(e))},findInputIndexForConnection(t){for(let e=0;e<this.inputList.length;e++)if(this.inputList[e].connection==t)return e;return null},insertElseIf(e,n){const i=this.appendValueInput("IF"+n).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF,"elseif"),s=this.appendStatementInput("DO"+n).appendField(t.Msg.CONTROLS_IF_MSG_THEN);return this.moveInputBefore("IF"+n,this.inputList[e].name),this.moveInputBefore("DO"+n,this.inputList[e+1].name),{ifInput:i,doInput:s}},onPendingConnection(e){e.type!==t.NEXT_STATEMENT||this.getInput("ELSE")||this.addElseInput();const n=this.findInputIndexForConnection(e);if(null===n)return;const i=this.inputList[n];if(e.targetConnection&&i.name.includes("IF")){const e=this.inputList[n+2];if(e&&"ELSE"!=e.name){const i=e&&e.connection&&e.connection.targetConnection;i&&!i.getSourceBlock().isInsertionMarker()&&this.insertElseIf(n+2,t.utils.idGenerator.genUid())}else this.insertElseIf(n+2,t.utils.idGenerator.genUid())}},finalizeConnections(){var t,e,n;const i=this.collectTargetCaseConns(),s=null===(e=null===(t=this.getInput("ELSE"))||void 0===t?void 0:t.connection)||void 0===e?void 0:e.targetConnection;this.tearDownBlock(),this.addFirstCase(),this.addCaseInputs(i),s&&(null===(n=this.addElseInput().connection)||void 0===n||n.connect(s)),this.elseifCount=Math.max(i.length-1,0),this.elseCount=s?1:0},collectTargetCaseConns(){var t,e;const n=[];for(let i=0;i<this.inputList.length-1;i+=2){const s=null===(t=this.inputList[i].connection)||void 0===t?void 0:t.targetConnection,o=null===(e=this.inputList[i+1].connection)||void 0===e?void 0:e.targetConnection;(s||o)&&n.push({ifTarget:s,doTarget:o})}return n},tearDownBlock(){for(let t=this.inputList.length-1;t>=0;t--)this.removeInput(this.inputList[t].name)},addCaseInputs(t){var e,n;for(let i=0;i<t.length;i++){let s=this.getInput(`IF${i}`),o=this.getInput(`DO${i}`);s&&o||({ifInput:s,doInput:o}=this.insertElseIf(2*i,i));const{ifTarget:l,doTarget:u}=t[i];l&&(null===(e=s.connection)||void 0===e||e.connect(l)),u&&(null===(n=o.connection)||void 0===n||n.connect(u))}},addElseInput(){return this.appendStatementInput("ELSE").appendField(t.Msg.CONTROLS_IF_MSG_ELSE)},addFirstCase(){this.appendValueInput("IF0").setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"),this.appendStatementInput("DO0").appendField(t.Msg.CONTROLS_IF_MSG_THEN)}};t.Blocks.dynamic_if=n;const o={minInputs:2,itemCount:0,init(){this.itemCount=this.minInputs,this.setHelpUrl(t.Msg.TEXT_JOIN_HELPURL),this.setStyle("text_blocks"),this.addFirstInput();for(let t=1;t<this.minInputs;t++)this.appendValueInput(`ADD${t}`);this.setOutput(!0,"String"),this.setTooltip(t.Msg.TEXT_JOIN_TOOLTIP)},mutationToDom(){t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable();const e=t.utils.xml.createElement("mutation");return e.setAttribute("items",`${this.itemCount}`),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){const n=e.getAttribute("inputs");if(n){const e=n.split(",");this.inputList=[],e.forEach((t=>this.appendValueInput(t))),this.inputList[0].appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH)}},deserializeCounts(t){var e;this.itemCount=Math.max(parseInt(null!==(e=t.getAttribute("items"))&&void 0!==e?e:"0",10),this.minInputs);for(let t=this.minInputs;t<this.itemCount;t++)this.appendValueInput("ADD"+t)},saveExtraState:function(){return t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable(),{itemCount:this.itemCount}},loadExtraState:function(e){if("string"!=typeof e){this.itemCount=e.itemCount;for(let t=this.minInputs;t<this.itemCount;t++)this.appendValueInput("ADD"+t)}else this.domToMutation(t.utils.xml.textToDom(e))},findInputIndexForConnection(t){var e;if(!t.targetConnection)return null;let n=-1;for(let e=0;e<this.inputList.length;e++)this.inputList[e].connection==t&&(n=e);if(n==this.inputList.length-1)return this.inputList.length+1;const i=this.inputList[n+1],s=null===(e=null==i?void 0:i.connection)||void 0===e?void 0:e.targetConnection;return s&&!s.getSourceBlock().isInsertionMarker()?n+1:null},onPendingConnection(e){const n=this.findInputIndexForConnection(e);null!=n&&(this.appendValueInput(`ADD${t.utils.idGenerator.genUid()}`),this.moveNumberedInputBefore(this.inputList.length-1,n))},finalizeConnections(){const t=this.removeUnnecessaryEmptyConns(this.inputList.map((t=>{var e;return null===(e=t.connection)||void 0===e?void 0:e.targetConnection})));this.tearDownBlock(),this.addItemInputs(t),this.itemCount=t.length},tearDownBlock(){for(let t=this.inputList.length-1;t>=0;t--)this.removeInput(this.inputList[t].name)},removeUnnecessaryEmptyConns(t){const e=[...t];for(let t=e.length-1;t>=0;t--)!e[t]&&e.length>this.minInputs&&e.splice(t,1);return e},addItemInputs(t){var e,n;const i=this.addFirstInput(),s=t[0];s&&(null===(e=i.connection)||void 0===e||e.connect(s));for(let e=1;e<t.length;e++){const i=this.appendValueInput(`ADD${e}`),s=t[e];s&&(null===(n=i.connection)||void 0===n||n.connect(s))}},addFirstInput(){return this.appendValueInput("ADD0").appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH)}};t.Blocks.dynamic_text_join=o;const l={minInputs:2,itemCount:0,init(){this.itemCount=this.minInputs,this.setHelpUrl(t.Msg.LISTS_CREATE_WITH_HELPURL),this.setStyle("list_blocks"),this.addFirstInput();for(let t=1;t<this.minInputs;t++)this.appendValueInput(`ADD${t}`);this.setOutput(!0,"Array"),this.setTooltip(t.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom(){t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable();const e=t.utils.xml.createElement("mutation");return e.setAttribute("items",`${this.itemCount}`),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){const n=e.getAttribute("inputs");if(n){const e=n.split(",");this.inputList=[],e.forEach((t=>this.appendValueInput(t))),this.inputList[0].appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH)}},deserializeCounts(t){var e;this.itemCount=Math.max(parseInt(null!==(e=t.getAttribute("items"))&&void 0!==e?e:"0",10),this.minInputs);for(let t=this.minInputs;t<this.itemCount;t++)this.appendValueInput("ADD"+t)},saveExtraState:function(){return t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable(),{itemCount:this.itemCount}},loadExtraState:function(e){if("string"!=typeof e){this.itemCount=e.itemCount;for(let t=this.minInputs;t<this.itemCount;t++)this.appendValueInput("ADD"+t)}else this.domToMutation(t.utils.xml.textToDom(e))},findInputIndexForConnection(t){var e;if(!t.targetConnection)return null;let n=-1;for(let e=0;e<this.inputList.length;e++)this.inputList[e].connection==t&&(n=e);if(n==this.inputList.length-1)return this.inputList.length+1;const i=this.inputList[n+1],s=null===(e=null==i?void 0:i.connection)||void 0===e?void 0:e.targetConnection;return s&&!s.getSourceBlock().isInsertionMarker()?n+1:null},onPendingConnection(e){const n=this.findInputIndexForConnection(e);null!=n&&(this.appendValueInput(`ADD${t.utils.idGenerator.genUid()}`),this.moveNumberedInputBefore(this.inputList.length-1,n))},finalizeConnections(){const t=this.removeUnnecessaryEmptyConns(this.inputList.map((t=>{var e;return null===(e=t.connection)||void 0===e?void 0:e.targetConnection})));this.tearDownBlock(),this.addItemInputs(t),this.itemCount=t.length},tearDownBlock(){for(let t=this.inputList.length-1;t>=0;t--)this.removeInput(this.inputList[t].name)},removeUnnecessaryEmptyConns(t){const e=[...t];for(let t=e.length-1;t>=0;t--)!e[t]&&e.length>this.minInputs&&e.splice(t,1);return e},addItemInputs(t){var e,n;const i=this.addFirstInput(),s=t[0];s&&(null===(e=i.connection)||void 0===e||e.connect(s));for(let e=1;e<t.length;e++){const i=this.appendValueInput(`ADD${e}`),s=t[e];s&&(null===(n=i.connection)||void 0===n||n.connect(s))}},addFirstInput(){return this.appendValueInput("ADD0").appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH)}};t.Blocks.dynamic_list_create=l;const u=function(){t.Blocks.lists_create_with=t.Blocks.dynamic_list_create,t.Blocks.text_join=t.Blocks.dynamic_text_join,t.Blocks.controls_if=t.Blocks.dynamic_if}})(),s})())); | ||
//# sourceMappingURL=index.js.map |
/*! For license information please see index.js.LICENSE.txt */ | ||
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("blockly/core"));else if("function"==typeof define&&define.amd)define(["blockly/core"],e);else{var n="object"==typeof exports?e(require("blockly/core")):e(t.Blockly);for(var i in n)("object"==typeof exports?exports:t)[i]=n[i]}}(this,(t=>(()=>{"use strict";var e={573:e=>{e.exports=t}},n={};function i(t){var s=n[t];if(void 0!==s)return s.exports;var o=n[t]={exports:{}};return e[t](o,o.exports,i),o.exports}i.d=(t,e)=>{for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var s={};return(()=>{i.r(s),i.d(s,{overrideOldBlockDefinitions:()=>p});var t=i(573);t.InsertionMarkerManager.prototype.update=function(e,n){var i;const s=this.getCandidate(e);this.wouldDeleteBlock=this.shouldDelete(!!s,n),(this.wouldDeleteBlock||this.shouldUpdatePreviews(s,e))&&((null===(i=null==s?void 0:s.closest)||void 0===i?void 0:i.sourceBlock_.onPendingConnection)&&(s.closest.sourceBlock_.onPendingConnection(s.closest),this.pendingBlocks||(this.pendingBlocks=new Set),this.pendingBlocks.add(s.closest.sourceBlock_)),t.Events.disable(),this.maybeHidePreview(s),this.maybeShowPreview(s),t.Events.enable())};const e=t.InsertionMarkerManager.prototype.dispose;t.InsertionMarkerManager.prototype.dispose=function(){this.pendingBlocks&&this.pendingBlocks.forEach((t=>{t.finalizeConnections&&t.finalizeConnections()})),e.call(this)};const n={inputCounter:1,minInputs:1,init(){this.setHelpUrl(t.Msg.CONTROLS_IF_HELPURL),this.setStyle("logic_blocks"),this.appendValueInput("IF0").setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"),this.appendStatementInput("DO0").appendField(t.Msg.CONTROLS_IF_MSG_THEN),this.setNextStatement(!0),this.setPreviousStatement(!0),this.setTooltip(t.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom(){const e=t.utils.xml.createElement("mutation"),n=this.inputList.filter((t=>t.name.includes("IF"))).map((t=>t.name.replace("IF",""))).join(",");e.setAttribute("inputs",n);const i=!!this.getInput("ELSE");return e.setAttribute("else",String(i)),e.setAttribute("next",String(this.inputCounter)),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){var n;const i=e.getAttribute("inputs");if(i){const e=i.split(",");this.getInput("IF0")&&this.removeInput("IF0"),this.getInput("DO0")&&this.removeInput("DO0");const n=e[0];this.appendValueInput("IF"+n).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"),this.appendStatementInput("DO"+n).appendField(t.Msg.CONTROLS_IF_MSG_THEN);for(let n=1;n<e.length;n++)this.appendValueInput("IF"+e[n]).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF,"elseif"),this.appendStatementInput("DO"+e[n]).appendField(t.Msg.CONTROLS_IF_MSG_THEN)}"true"==e.getAttribute("else")&&this.appendStatementInput("ELSE").appendField(t.Msg.CONTROLS_IF_MSG_ELSE,"else");const s=parseInt(null!==(n=e.getAttribute("next"))&&void 0!==n?n:"0",10)||0;this.inputCounter=s},deserializeCounts(e){var n,i;const s=parseInt(null!==(n=e.getAttribute("elseif"))&&void 0!==n?n:"0",10)||0,o=parseInt(null!==(i=e.getAttribute("else"))&&void 0!==i?i:"0",10)||0;for(let e=1;e<=s;e++)this.appendValueInput("IF"+e).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF),this.appendStatementInput("DO"+e).appendField(t.Msg.CONTROLS_IF_MSG_THEN);o&&this.appendStatementInput("ELSE").appendField(t.Msg.CONTROLS_IF_MSG_ELSE),this.inputCounter=s+1},findInputIndexForConnection(t){for(let e=0;e<this.inputList.length;e++)if(this.inputList[e].connection==t)return e;return null},insertElseIf(e){const n=this.inputCounter;this.appendValueInput("IF"+n).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF,"elseif"),this.appendStatementInput("DO"+n).appendField(t.Msg.CONTROLS_IF_MSG_THEN),this.moveInputBefore("IF"+n,this.inputList[e].name),this.moveInputBefore("DO"+n,this.inputList[e+1].name),this.inputCounter++},onPendingConnection(e){e.type!==t.NEXT_STATEMENT||this.getInput("ELSE")||this.appendStatementInput("ELSE").appendField(t.Msg.CONTROLS_IF_MSG_ELSE,"else");const n=this.findInputIndexForConnection(e);if(null===n)return;const i=this.inputList[n];if(e.targetConnection&&i.name.includes("IF")){const t=this.inputList[n+2];if(t&&"ELSE"!=t.name){const e=t&&t.connection&&t.connection.targetConnection;e&&!e.getSourceBlock().isInsertionMarker()&&this.insertElseIf(n+2)}else this.insertElseIf(n+2)}},finalizeConnections(){var e,n,i,s,o;const u=[];for(let t=2;t<this.inputList.length-1;t+=2){const i=this.inputList[t],s=this.inputList[t+1];(null===(e=i.connection)||void 0===e?void 0:e.targetConnection)||(null===(n=s.connection)||void 0===n?void 0:n.targetConnection)||(u.push(i.name),u.push(s.name))}u.forEach((t=>this.removeInput(t)));const p=this.getInput("ELSE");if(p&&!(null===(i=p.connection)||void 0===i?void 0:i.targetConnection)&&this.removeInput(p.name),this.inputList.length>2){const e=this.inputList[0],n=this.inputList[1],i=this.inputList[2];!i.name.includes("IF")||(null===(s=e.connection)||void 0===s?void 0:s.targetConnection)||(null===(o=n.connection)||void 0===o?void 0:o.targetConnection)||(this.removeInput(e.name),this.removeInput(n.name),i.removeField("elseif"),i.appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"))}}};t.Blocks.dynamic_if=n;const o={inputCounter:2,minInputs:2,init(){this.setHelpUrl(t.Msg.TEXT_JOIN_HELPURL),this.setStyle("text_blocks"),this.appendValueInput("ADD0").appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH),this.appendValueInput("ADD1"),this.setOutput(!0,"String"),this.setTooltip(t.Msg.TEXT_JOIN_TOOLTIP)},mutationToDom(){const e=t.utils.xml.createElement("mutation"),n=this.inputList.map((t=>t.name)).join(",");return e.setAttribute("inputs",n),e.setAttribute("next",String(this.inputCounter)),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){var n;const i=e.getAttribute("inputs");if(i){const e=i.split(",");this.inputList=[],e.forEach((t=>this.appendValueInput(t))),this.inputList[0].appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH)}const s=parseInt(null!==(n=e.getAttribute("next"))&&void 0!==n?n:"0",10)||0;this.inputCounter=s},deserializeCounts(t){var e;const n=Math.max(parseInt(null!==(e=t.getAttribute("items"))&&void 0!==e?e:"0",10),this.minInputs);for(let t=this.minInputs;t<n;t++)this.appendValueInput("ADD"+t);this.inputCounter=n},getIndexForNewInput(t){var e;if(!t.targetConnection)return null;let n=-1;for(let e=0;e<this.inputList.length;e++)this.inputList[e].connection==t&&(n=e);if(n==this.inputList.length-1)return this.inputList.length+1;const i=this.inputList[n+1],s=null===(e=null==i?void 0:i.connection)||void 0===e?void 0:e.targetConnection;return s&&!s.getSourceBlock().isInsertionMarker()?n+1:null},onPendingConnection(t){const e=this.getIndexForNewInput(t);null!=e&&(this.appendValueInput("ADD"+this.inputCounter++),this.moveNumberedInputBefore(this.inputList.length-1,e))},finalizeConnections(){if(this.inputList.length>this.minInputs){let e=[];this.inputList.forEach((t=>{var n;(null===(n=t.connection)||void 0===n?void 0:n.targetConnection)||e.push(t.name)})),this.inputList.length-e.length<this.minInputs&&(e=e.slice(this.minInputs)),e.forEach((t=>this.removeInput(t))),0==this.inputList[0].fieldRow.length&&this.inputList[0].appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH)}}};t.Blocks.dynamic_text_join=o;const u={inputCounter:2,minInputs:2,init(){this.setHelpUrl(t.Msg.LISTS_CREATE_WITH_HELPURL),this.setStyle("list_blocks"),this.appendValueInput("ADD0").appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH),this.appendValueInput("ADD1"),this.setOutput(!0,"Array"),this.setTooltip(t.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom(){const e=t.utils.xml.createElement("mutation"),n=this.inputList.map((t=>t.name)).join(",");return e.setAttribute("inputs",n),e.setAttribute("next",String(this.inputCounter)),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){var n;const i=e.getAttribute("inputs");if(i){const e=i.split(",");this.inputList=[],e.forEach((t=>this.appendValueInput(t))),this.inputList[0].appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH)}const s=parseInt(null!==(n=e.getAttribute("next"))&&void 0!==n?n:"0",10)||0;this.inputCounter=s},deserializeCounts(t){var e;const n=Math.max(parseInt(null!==(e=t.getAttribute("items"))&&void 0!==e?e:"0",10),this.minInputs);for(let t=this.minInputs;t<n;t++)this.appendValueInput("ADD"+t);this.inputCounter=n},getIndexForNewInput(t){var e;if(!t.targetConnection)return null;let n=-1;for(let e=0;e<this.inputList.length;e++)this.inputList[e].connection==t&&(n=e);if(n==this.inputList.length-1)return this.inputList.length+1;const i=this.inputList[n+1],s=null===(e=null==i?void 0:i.connection)||void 0===e?void 0:e.targetConnection;return s&&!s.getSourceBlock().isInsertionMarker()?n+1:null},onPendingConnection(t){const e=this.getIndexForNewInput(t);null!=e&&(this.appendValueInput("ADD"+this.inputCounter++),this.moveNumberedInputBefore(this.inputList.length-1,e))},finalizeConnections(){if(this.inputList.length>this.minInputs){let e=[];this.inputList.forEach((t=>{var n;(null===(n=t.connection)||void 0===n?void 0:n.targetConnection)||e.push(t.name)})),this.inputList.length-e.length<this.minInputs&&(e=e.slice(this.minInputs)),e.forEach((t=>this.removeInput(t))),0==this.inputList[0].fieldRow.length&&this.inputList[0].appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH)}}};t.Blocks.dynamic_list_create=u;const p=function(){t.Blocks.lists_create_with=t.Blocks.dynamic_list_create,t.Blocks.text_join=t.Blocks.dynamic_text_join,t.Blocks.controls_if=t.Blocks.dynamic_if}})(),s})())); | ||
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("blockly/core"));else if("function"==typeof define&&define.amd)define(["blockly/core"],e);else{var n="object"==typeof exports?e(require("blockly/core")):e(t.Blockly);for(var i in n)("object"==typeof exports?exports:t)[i]=n[i]}}(this,(t=>(()=>{"use strict";var e={573:e=>{e.exports=t}},n={};function i(t){var s=n[t];if(void 0!==s)return s.exports;var o=n[t]={exports:{}};return e[t](o,o.exports,i),o.exports}i.d=(t,e)=>{for(var n in e)i.o(e,n)&&!i.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var s={};return(()=>{i.r(s),i.d(s,{overrideOldBlockDefinitions:()=>u});var t=i(573);t.InsertionMarkerManager.prototype.update=function(e,n){var i;const s=this.getCandidate(e);this.wouldDeleteBlock=this.shouldDelete(!!s,n),(this.wouldDeleteBlock||this.shouldUpdatePreviews(s,e))&&((null===(i=null==s?void 0:s.closest)||void 0===i?void 0:i.sourceBlock_.onPendingConnection)&&(s.closest.sourceBlock_.onPendingConnection(s.closest),this.pendingBlocks||(this.pendingBlocks=new Set),this.pendingBlocks.add(s.closest.sourceBlock_)),t.Events.disable(),this.maybeHidePreview(s),this.maybeShowPreview(s),t.Events.enable())};const e=t.InsertionMarkerManager.prototype.dispose;t.InsertionMarkerManager.prototype.dispose=function(){this.pendingBlocks&&this.pendingBlocks.forEach((t=>{t.finalizeConnections&&t.finalizeConnections()})),e.call(this)};const n={minInputs:1,elseifCount:0,elseCount:0,init(){this.setHelpUrl(t.Msg.CONTROLS_IF_HELPURL),this.setStyle("logic_blocks"),this.addFirstCase(),this.setNextStatement(!0),this.setPreviousStatement(!0),this.setTooltip(t.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom(){if(t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable(),!this.elseifCount&&!this.elseCount)return null;const e=t.utils.xml.createElement("mutation");return this.elseifCount&&e.setAttribute("elseif",`${this.elseifCount}`),this.elseCount&&e.setAttribute("else","1"),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){const n=e.getAttribute("inputs");if(n){const e=n.split(",");this.getInput("IF0")&&this.removeInput("IF0"),this.getInput("DO0")&&this.removeInput("DO0");const i=e[0];this.appendValueInput("IF"+i).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"),this.appendStatementInput("DO"+i).appendField(t.Msg.CONTROLS_IF_MSG_THEN);for(let n=1;n<e.length;n++)this.appendValueInput("IF"+e[n]).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF,"elseif"),this.appendStatementInput("DO"+e[n]).appendField(t.Msg.CONTROLS_IF_MSG_THEN)}"true"==e.getAttribute("else")&&this.addElseInput()},deserializeCounts(t){var e,n;this.elseifCount=parseInt(null!==(e=t.getAttribute("elseif"))&&void 0!==e?e:"0",10)||0,this.elseCount=parseInt(null!==(n=t.getAttribute("else"))&&void 0!==n?n:"0",10)||0;for(let t=1;t<=this.elseifCount;t++)this.insertElseIf(this.inputList.length,t);this.elseCount&&this.addElseInput()},saveExtraState:function(){if(t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable(),!this.elseifCount&&!this.elseCount)return null;const e=Object.create(null);return this.elseifCount&&(e.elseIfCount=this.elseifCount),this.elseCount&&(e.hasElse=!0),e},loadExtraState:function(e){if("string"!=typeof e){this.elseifCount=e.elseIfCount||0,this.elseCount=e.hasElse?1:0;for(let t=1;t<=this.elseifCount;t++)this.insertElseIf(this.inputList.length,t);this.elseCount&&this.addElseInput()}else this.domToMutation(t.utils.xml.textToDom(e))},findInputIndexForConnection(t){for(let e=0;e<this.inputList.length;e++)if(this.inputList[e].connection==t)return e;return null},insertElseIf(e,n){const i=this.appendValueInput("IF"+n).setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_ELSEIF,"elseif"),s=this.appendStatementInput("DO"+n).appendField(t.Msg.CONTROLS_IF_MSG_THEN);return this.moveInputBefore("IF"+n,this.inputList[e].name),this.moveInputBefore("DO"+n,this.inputList[e+1].name),{ifInput:i,doInput:s}},onPendingConnection(e){e.type!==t.NEXT_STATEMENT||this.getInput("ELSE")||this.addElseInput();const n=this.findInputIndexForConnection(e);if(null===n)return;const i=this.inputList[n];if(e.targetConnection&&i.name.includes("IF")){const e=this.inputList[n+2];if(e&&"ELSE"!=e.name){const i=e&&e.connection&&e.connection.targetConnection;i&&!i.getSourceBlock().isInsertionMarker()&&this.insertElseIf(n+2,t.utils.idGenerator.genUid())}else this.insertElseIf(n+2,t.utils.idGenerator.genUid())}},finalizeConnections(){var t,e,n;const i=this.collectTargetCaseConns(),s=null===(e=null===(t=this.getInput("ELSE"))||void 0===t?void 0:t.connection)||void 0===e?void 0:e.targetConnection;this.tearDownBlock(),this.addFirstCase(),this.addCaseInputs(i),s&&(null===(n=this.addElseInput().connection)||void 0===n||n.connect(s)),this.elseifCount=Math.max(i.length-1,0),this.elseCount=s?1:0},collectTargetCaseConns(){var t,e;const n=[];for(let i=0;i<this.inputList.length-1;i+=2){const s=null===(t=this.inputList[i].connection)||void 0===t?void 0:t.targetConnection,o=null===(e=this.inputList[i+1].connection)||void 0===e?void 0:e.targetConnection;(s||o)&&n.push({ifTarget:s,doTarget:o})}return n},tearDownBlock(){for(let t=this.inputList.length-1;t>=0;t--)this.removeInput(this.inputList[t].name)},addCaseInputs(t){var e,n;for(let i=0;i<t.length;i++){let s=this.getInput(`IF${i}`),o=this.getInput(`DO${i}`);s&&o||({ifInput:s,doInput:o}=this.insertElseIf(2*i,i));const{ifTarget:l,doTarget:u}=t[i];l&&(null===(e=s.connection)||void 0===e||e.connect(l)),u&&(null===(n=o.connection)||void 0===n||n.connect(u))}},addElseInput(){return this.appendStatementInput("ELSE").appendField(t.Msg.CONTROLS_IF_MSG_ELSE)},addFirstCase(){this.appendValueInput("IF0").setCheck("Boolean").appendField(t.Msg.CONTROLS_IF_MSG_IF,"if"),this.appendStatementInput("DO0").appendField(t.Msg.CONTROLS_IF_MSG_THEN)}};t.Blocks.dynamic_if=n;const o={minInputs:2,itemCount:0,init(){this.itemCount=this.minInputs,this.setHelpUrl(t.Msg.TEXT_JOIN_HELPURL),this.setStyle("text_blocks"),this.addFirstInput();for(let t=1;t<this.minInputs;t++)this.appendValueInput(`ADD${t}`);this.setOutput(!0,"String"),this.setTooltip(t.Msg.TEXT_JOIN_TOOLTIP)},mutationToDom(){t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable();const e=t.utils.xml.createElement("mutation");return e.setAttribute("items",`${this.itemCount}`),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){const n=e.getAttribute("inputs");if(n){const e=n.split(",");this.inputList=[],e.forEach((t=>this.appendValueInput(t))),this.inputList[0].appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH)}},deserializeCounts(t){var e;this.itemCount=Math.max(parseInt(null!==(e=t.getAttribute("items"))&&void 0!==e?e:"0",10),this.minInputs);for(let t=this.minInputs;t<this.itemCount;t++)this.appendValueInput("ADD"+t)},saveExtraState:function(){return t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable(),{itemCount:this.itemCount}},loadExtraState:function(e){if("string"!=typeof e){this.itemCount=e.itemCount;for(let t=this.minInputs;t<this.itemCount;t++)this.appendValueInput("ADD"+t)}else this.domToMutation(t.utils.xml.textToDom(e))},findInputIndexForConnection(t){var e;if(!t.targetConnection)return null;let n=-1;for(let e=0;e<this.inputList.length;e++)this.inputList[e].connection==t&&(n=e);if(n==this.inputList.length-1)return this.inputList.length+1;const i=this.inputList[n+1],s=null===(e=null==i?void 0:i.connection)||void 0===e?void 0:e.targetConnection;return s&&!s.getSourceBlock().isInsertionMarker()?n+1:null},onPendingConnection(e){const n=this.findInputIndexForConnection(e);null!=n&&(this.appendValueInput(`ADD${t.utils.idGenerator.genUid()}`),this.moveNumberedInputBefore(this.inputList.length-1,n))},finalizeConnections(){const t=this.removeUnnecessaryEmptyConns(this.inputList.map((t=>{var e;return null===(e=t.connection)||void 0===e?void 0:e.targetConnection})));this.tearDownBlock(),this.addItemInputs(t),this.itemCount=t.length},tearDownBlock(){for(let t=this.inputList.length-1;t>=0;t--)this.removeInput(this.inputList[t].name)},removeUnnecessaryEmptyConns(t){const e=[...t];for(let t=e.length-1;t>=0;t--)!e[t]&&e.length>this.minInputs&&e.splice(t,1);return e},addItemInputs(t){var e,n;const i=this.addFirstInput(),s=t[0];s&&(null===(e=i.connection)||void 0===e||e.connect(s));for(let e=1;e<t.length;e++){const i=this.appendValueInput(`ADD${e}`),s=t[e];s&&(null===(n=i.connection)||void 0===n||n.connect(s))}},addFirstInput(){return this.appendValueInput("ADD0").appendField(t.Msg.TEXT_JOIN_TITLE_CREATEWITH)}};t.Blocks.dynamic_text_join=o;const l={minInputs:2,itemCount:0,init(){this.itemCount=this.minInputs,this.setHelpUrl(t.Msg.LISTS_CREATE_WITH_HELPURL),this.setStyle("list_blocks"),this.addFirstInput();for(let t=1;t<this.minInputs;t++)this.appendValueInput(`ADD${t}`);this.setOutput(!0,"Array"),this.setTooltip(t.Msg.LISTS_CREATE_WITH_TOOLTIP)},mutationToDom(){t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable();const e=t.utils.xml.createElement("mutation");return e.setAttribute("items",`${this.itemCount}`),e},domToMutation(t){t.getAttribute("inputs")?this.deserializeInputs(t):this.deserializeCounts(t)},deserializeInputs(e){const n=e.getAttribute("inputs");if(n){const e=n.split(",");this.inputList=[],e.forEach((t=>this.appendValueInput(t))),this.inputList[0].appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH)}},deserializeCounts(t){var e;this.itemCount=Math.max(parseInt(null!==(e=t.getAttribute("items"))&&void 0!==e?e:"0",10),this.minInputs);for(let t=this.minInputs;t<this.itemCount;t++)this.appendValueInput("ADD"+t)},saveExtraState:function(){return t.Events.disable(),this.finalizeConnections(),this instanceof t.BlockSvg&&this.initSvg(),t.Events.enable(),{itemCount:this.itemCount}},loadExtraState:function(e){if("string"!=typeof e){this.itemCount=e.itemCount;for(let t=this.minInputs;t<this.itemCount;t++)this.appendValueInput("ADD"+t)}else this.domToMutation(t.utils.xml.textToDom(e))},findInputIndexForConnection(t){var e;if(!t.targetConnection)return null;let n=-1;for(let e=0;e<this.inputList.length;e++)this.inputList[e].connection==t&&(n=e);if(n==this.inputList.length-1)return this.inputList.length+1;const i=this.inputList[n+1],s=null===(e=null==i?void 0:i.connection)||void 0===e?void 0:e.targetConnection;return s&&!s.getSourceBlock().isInsertionMarker()?n+1:null},onPendingConnection(e){const n=this.findInputIndexForConnection(e);null!=n&&(this.appendValueInput(`ADD${t.utils.idGenerator.genUid()}`),this.moveNumberedInputBefore(this.inputList.length-1,n))},finalizeConnections(){const t=this.removeUnnecessaryEmptyConns(this.inputList.map((t=>{var e;return null===(e=t.connection)||void 0===e?void 0:e.targetConnection})));this.tearDownBlock(),this.addItemInputs(t),this.itemCount=t.length},tearDownBlock(){for(let t=this.inputList.length-1;t>=0;t--)this.removeInput(this.inputList[t].name)},removeUnnecessaryEmptyConns(t){const e=[...t];for(let t=e.length-1;t>=0;t--)!e[t]&&e.length>this.minInputs&&e.splice(t,1);return e},addItemInputs(t){var e,n;const i=this.addFirstInput(),s=t[0];s&&(null===(e=i.connection)||void 0===e||e.connect(s));for(let e=1;e<t.length;e++){const i=this.appendValueInput(`ADD${e}`),s=t[e];s&&(null===(n=i.connection)||void 0===n||n.connect(s))}},addFirstInput(){return this.appendValueInput("ADD0").appendField(t.Msg.LISTS_CREATE_WITH_INPUT_WITH)}};t.Blocks.dynamic_list_create=l;const u=function(){t.Blocks.lists_create_with=t.Blocks.dynamic_list_create,t.Blocks.text_join=t.Blocks.dynamic_text_join,t.Blocks.controls_if=t.Blocks.dynamic_if}})(),s})())); | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@blockly/block-dynamic-connection", | ||
"version": "0.4.3", | ||
"version": "0.5.0", | ||
"description": "A group of blocks that add connections dynamically.", | ||
@@ -45,3 +45,3 @@ "scripts": { | ||
"@blockly/dev-tools": "^7.1.0", | ||
"blockly": "^10.0.0", | ||
"blockly": "^10.2.0", | ||
"chai": "^4.2.0", | ||
@@ -51,3 +51,3 @@ "mocha": "^10.2.0" | ||
"peerDependencies": { | ||
"blockly": "^10.0.0" | ||
"blockly": "^10.2.0" | ||
}, | ||
@@ -64,3 +64,3 @@ "publishConfig": { | ||
}, | ||
"gitHead": "9aa7cd200a6b1a396b5b3b908c7b9d574ddf8805" | ||
"gitHead": "90bef04779f022f2650508a2e565274fdc1fb99c" | ||
} |
@@ -21,15 +21,12 @@ # @blockly/block-dynamic-connection [![Built on Blockly](https://tinyurl.com/built-on-blockly)](https://github.com/google/blockly) | ||
dynamic connection blocks. This enables projects to use the dynamic block | ||
plugin without changing existing XML. | ||
Note that if you enable this, you will **never** be able to switch back to | ||
non-dynamic connections, because this changes the way mutations are | ||
serialized. | ||
plugin without changing existing XML/JSON. | ||
## XML | ||
```xml | ||
<block type="dynamic_text_join"></block> | ||
<block type="dynamic_list_create"></block> | ||
<block type="dynamic_if"></block> | ||
``` | ||
## Blocks | ||
* `dynamic_text_join` replaces `text_join` | ||
* `dynamic_list_create` replaces `lists_create_with` | ||
* `dynamic_if` replaces `controls_if` | ||
## License | ||
Apache 2.0 |
@@ -22,11 +22,32 @@ /** | ||
interface CaseConnectionPair { | ||
ifTarget?: Blockly.Connection | null; | ||
doTarget?: Blockly.Connection | null; | ||
} | ||
interface CaseInputPair { | ||
ifInput: Blockly.Input; | ||
doInput: Blockly.Input; | ||
} | ||
/** Extra state for serializing controls_if blocks. */ | ||
interface IfExtraState { | ||
elseIfCount?: number; | ||
hasElse?: boolean; | ||
} | ||
/* eslint-disable @typescript-eslint/naming-convention */ | ||
const DYNAMIC_IF_MIXIN = { | ||
/* eslint-enable @typescript-eslint/naming-convention */ | ||
/** Counter for the next input to add to this block. */ | ||
inputCounter: 1, | ||
/** Minimum number of inputs for this block. */ | ||
/** | ||
* Minimum number of inputs for this block. | ||
* @deprecated This is unused. | ||
*/ | ||
minInputs: 1, | ||
/** Count of else-if cases. */ | ||
elseifCount: 0, | ||
/** Count of else cases (either 0 or 1). */ | ||
elseCount: 0, | ||
/** | ||
@@ -39,9 +60,3 @@ * Block for if/elseif/else statements. Must have one if input. | ||
this.setStyle('logic_blocks'); | ||
this.appendValueInput('IF0') | ||
.setCheck('Boolean') | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_IF'], 'if'); | ||
this.appendStatementInput('DO0') | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_THEN']); | ||
this.addFirstCase(); | ||
this.setNextStatement(true); | ||
@@ -56,11 +71,19 @@ this.setPreviousStatement(true); | ||
*/ | ||
mutationToDom(this: DynamicIfBlock): Element { | ||
mutationToDom(this: DynamicIfBlock): Element|null { | ||
// If we call finalizeConnections here without disabling events, we get into | ||
// an event loop. | ||
Blockly.Events.disable(); | ||
this.finalizeConnections(); | ||
if (this instanceof Blockly.BlockSvg) this.initSvg(); | ||
Blockly.Events.enable(); | ||
if (!this.elseifCount && !this.elseCount) return null; | ||
const container = Blockly.utils.xml.createElement('mutation'); | ||
const inputNames = this.inputList | ||
.filter((input: Blockly.Input) => input.name.includes('IF')) | ||
.map((input: Blockly.Input) => input.name.replace('IF', '')).join(','); | ||
container.setAttribute('inputs', inputNames); | ||
const hasElse = !!this.getInput('ELSE'); | ||
container.setAttribute('else', String(hasElse)); | ||
container.setAttribute('next', String(this.inputCounter)); | ||
if (this.elseifCount) { | ||
container.setAttribute('elseif', `${this.elseifCount}`); | ||
} | ||
if (this.elseCount) { | ||
container.setAttribute('else', '1'); | ||
} | ||
return container; | ||
@@ -112,7 +135,4 @@ }, | ||
if (hasElse == 'true') { | ||
this.appendStatementInput('ELSE') | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSE'], 'else'); | ||
this.addElseInput(); | ||
} | ||
const next = parseInt(xmlElement.getAttribute('next') ?? '0', 10) || 0; | ||
this.inputCounter = next; | ||
}, | ||
@@ -125,19 +145,60 @@ | ||
deserializeCounts(this: DynamicIfBlock, xmlElement: Element): void { | ||
const elseifCount = parseInt( | ||
this.elseifCount = parseInt( | ||
xmlElement.getAttribute('elseif') ?? '0', 10) || 0; | ||
const elseCount = parseInt(xmlElement.getAttribute('else') ?? '0', 10) || 0; | ||
for (let i = 1; i <= elseifCount; i++) { | ||
this.appendValueInput('IF' + i).setCheck('Boolean').appendField( | ||
Blockly.Msg['CONTROLS_IF_MSG_ELSEIF']); | ||
this.appendStatementInput('DO' + i).appendField( | ||
Blockly.Msg['CONTROLS_IF_MSG_THEN']); | ||
this.elseCount = parseInt(xmlElement.getAttribute('else') ?? '0', 10) || 0; | ||
for (let i = 1; i <= this.elseifCount; i++) { | ||
this.insertElseIf(this.inputList.length, i); | ||
} | ||
if (elseCount) { | ||
this.appendStatementInput('ELSE').appendField( | ||
Blockly.Msg['CONTROLS_IF_MSG_ELSE']); | ||
if (this.elseCount) { | ||
this.addElseInput(); | ||
} | ||
this.inputCounter = elseifCount + 1; | ||
}, | ||
/** | ||
* Returns the state of this block as a JSON serializable object. | ||
* @returns The state of this block, ie the else if count and else state. | ||
*/ | ||
saveExtraState: function(this: DynamicIfBlock): IfExtraState | null { | ||
// If we call finalizeConnections here without disabling events, we get into | ||
// an event loop. | ||
Blockly.Events.disable(); | ||
this.finalizeConnections(); | ||
if (this instanceof Blockly.BlockSvg) this.initSvg(); | ||
Blockly.Events.enable(); | ||
if (!this.elseifCount && !this.elseCount) { | ||
return null; | ||
} | ||
const state = Object.create(null); | ||
if (this.elseifCount) { | ||
state['elseIfCount'] = this.elseifCount; | ||
} | ||
if (this.elseCount) { | ||
state['hasElse'] = true; | ||
} | ||
return state; | ||
}, | ||
/** | ||
* Applies the given state to this block. | ||
* @param state The state to apply to this block, ie the else if count | ||
* and else state. | ||
*/ | ||
loadExtraState: function(this: DynamicIfBlock, state: IfExtraState | string) { | ||
if (typeof state === 'string') { | ||
this.domToMutation(Blockly.utils.xml.textToDom(state)); | ||
return; | ||
} | ||
this.elseifCount = state['elseIfCount'] || 0; | ||
this.elseCount = state['hasElse'] ? 1 : 0; | ||
for (let i = 1; i <= this.elseifCount; i++) { | ||
this.insertElseIf(this.inputList.length, i); | ||
} | ||
if (this.elseCount) { | ||
this.addElseInput(); | ||
} | ||
}, | ||
/** | ||
* Finds the index of a connection. Used to determine where in the block to | ||
@@ -162,14 +223,17 @@ * insert new inputs. | ||
* @param index Index of the input before which to add new inputs. | ||
* @param id An ID to append to the case statement input names to make them | ||
* unique. | ||
* @returns The added inputs. | ||
*/ | ||
insertElseIf(this: DynamicIfBlock, index: number): void { | ||
const caseNumber = this.inputCounter; | ||
this | ||
.appendValueInput('IF' + caseNumber) | ||
insertElseIf( | ||
this: DynamicIfBlock, index: number, id: string | number | ||
): CaseInputPair { | ||
const ifInput = this.appendValueInput('IF' + id) | ||
.setCheck('Boolean') | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSEIF'], 'elseif'); | ||
this.appendStatementInput('DO' + caseNumber) | ||
const doInput = this.appendStatementInput('DO' + id) | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_THEN']); | ||
this.moveInputBefore('IF' + caseNumber, this.inputList[index].name); | ||
this.moveInputBefore('DO' + caseNumber, this.inputList[index + 1].name); | ||
this.inputCounter++; | ||
this.moveInputBefore('IF' + id, this.inputList[index].name); | ||
this.moveInputBefore('DO' + id, this.inputList[index + 1].name); | ||
return {ifInput, doInput}; | ||
}, | ||
@@ -186,4 +250,3 @@ | ||
if (connection.type === Blockly.NEXT_STATEMENT && !this.getInput('ELSE')) { | ||
this.appendStatementInput('ELSE') | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSE'], 'else'); | ||
this.addElseInput(); | ||
} | ||
@@ -198,3 +261,3 @@ const inputIndex = this.findInputIndexForConnection(connection); | ||
if (!nextIfInput || nextIfInput.name == 'ELSE') { | ||
this.insertElseIf(inputIndex + 2); | ||
this.insertElseIf(inputIndex + 2, Blockly.utils.idGenerator.genUid()); | ||
} else { | ||
@@ -209,3 +272,3 @@ const nextIfConnection = | ||
) { | ||
this.insertElseIf(inputIndex + 2); | ||
this.insertElseIf(inputIndex + 2, Blockly.utils.idGenerator.genUid()); | ||
} | ||
@@ -221,38 +284,88 @@ } | ||
finalizeConnections(this: DynamicIfBlock): void { | ||
const toRemove = []; | ||
// Remove Else If inputs if neither the if nor the do has a connected block. | ||
for (let i = 2; i < this.inputList.length - 1; i += 2) { | ||
const ifConnection = this.inputList[i]; | ||
const doConnection = this.inputList[i + 1]; | ||
if (!ifConnection.connection?.targetConnection && | ||
!doConnection.connection?.targetConnection) { | ||
toRemove.push(ifConnection.name); | ||
toRemove.push(doConnection.name); | ||
} | ||
const targetCaseConns = this.collectTargetCaseConns(); | ||
const targetElseConn = this.getInput('ELSE')?.connection?.targetConnection; | ||
this.tearDownBlock(); | ||
this.addFirstCase(); | ||
this.addCaseInputs(targetCaseConns); | ||
if (targetElseConn) { | ||
this.addElseInput().connection?.connect(targetElseConn); | ||
} | ||
toRemove.forEach((input) => this.removeInput(input)); | ||
// Remove Else input if it doesn't have a connected block. | ||
const elseInput = this.getInput('ELSE'); | ||
if (elseInput && !elseInput.connection?.targetConnection) { | ||
this.removeInput(elseInput.name); | ||
this.elseifCount = Math.max(targetCaseConns.length - 1, 0); | ||
this.elseCount = targetElseConn ? 1 : 0; | ||
}, | ||
/** | ||
* Collects all of the target blocks attached to case inputs. If neither the | ||
* if nor the due input in a case has an attached block, that input is | ||
* skipped. If only one of them has an attached block, the other value in | ||
* the pair is undefined. | ||
* @returns A list of target connections attached to case inputs. | ||
*/ | ||
collectTargetCaseConns(this: DynamicIfBlock): CaseConnectionPair[] { | ||
const targetConns = []; | ||
for (let i = 0; i < this.inputList.length - 1; i += 2) { | ||
const ifTarget = | ||
this.inputList[i].connection?.targetConnection; | ||
const doTarget = | ||
this.inputList[i + 1].connection?.targetConnection; | ||
if (!ifTarget && !doTarget) continue; | ||
targetConns.push({ifTarget, doTarget}); | ||
} | ||
return targetConns; | ||
}, | ||
// Remove the If input if it is empty and there is at least one Else If | ||
if (this.inputList.length > 2) { | ||
const ifInput = this.inputList[0]; | ||
const doInput = this.inputList[1]; | ||
const nextInput = this.inputList[2]; | ||
if (nextInput.name.includes('IF') && | ||
!ifInput.connection?.targetConnection && | ||
!doInput.connection?.targetConnection) { | ||
this.removeInput(ifInput.name); | ||
this.removeInput(doInput.name); | ||
nextInput.removeField('elseif'); | ||
nextInput.appendField(Blockly.Msg['CONTROLS_IF_MSG_IF'], 'if'); | ||
/** Deletes all inputs on the block so it can be rebuilt. */ | ||
tearDownBlock(this: DynamicIfBlock): void { | ||
for (let i = this.inputList.length - 1; i >= 0; i--) { | ||
this.removeInput(this.inputList[i].name); | ||
} | ||
}, | ||
/** | ||
* Adds inputs for all of the given target connection pairs (if the input | ||
* doesn't already exist), and connects the target connections to them. | ||
* | ||
* This is essentially rebuilding all of the cases with strictly ascending | ||
* case numbers. | ||
* @param targetConns The list of target connections to attach to this block. | ||
*/ | ||
addCaseInputs(this: DynamicIfBlock, targetConns: CaseConnectionPair[]): void { | ||
for (let i = 0; i < targetConns.length; i++) { | ||
let ifInput = this.getInput(`IF${i}`); | ||
let doInput = this.getInput(`DO${i}`); | ||
if (!ifInput || !doInput) { | ||
({ifInput, doInput} = this.insertElseIf(i * 2, i)); | ||
} | ||
const {ifTarget, doTarget} = targetConns[i]; | ||
if (ifTarget) ifInput.connection?.connect(ifTarget); | ||
if (doTarget) doInput.connection?.connect(doTarget); | ||
} | ||
}, | ||
/** | ||
* Adds an else input to this block. | ||
* @returns The appended input. | ||
*/ | ||
addElseInput(this: DynamicIfBlock): Blockly.Input { | ||
return this.appendStatementInput('ELSE') | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_ELSE']); | ||
}, | ||
/** | ||
* Adds the first 'IF' and 'DO' inputs and their associated labels to this | ||
* block. | ||
*/ | ||
addFirstCase(this: DynamicIfBlock): void { | ||
this.appendValueInput('IF0') | ||
.setCheck('Boolean') | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_IF'], 'if'); | ||
this.appendStatementInput('DO0') | ||
.appendField(Blockly.Msg['CONTROLS_IF_MSG_THEN']); | ||
}, | ||
}; | ||
Blockly.Blocks['dynamic_if'] = DYNAMIC_IF_MIXIN; |
@@ -25,15 +25,18 @@ /** | ||
/* eslint-enable @typescript-eslint/naming-convention */ | ||
/** Counter for the next input to add to this block. */ | ||
inputCounter: 2, | ||
/** Minimum number of inputs for this block. */ | ||
minInputs: 2, | ||
/** Count of item inputs. */ | ||
itemCount: 0, | ||
/** Block for concatenating any number of strings. */ | ||
init(this: DynamicListCreateBlock): void { | ||
this.itemCount = this.minInputs; | ||
this.setHelpUrl(Blockly.Msg['LISTS_CREATE_WITH_HELPURL']); | ||
this.setStyle('list_blocks'); | ||
this.appendValueInput('ADD0') | ||
.appendField(Blockly.Msg['LISTS_CREATE_WITH_INPUT_WITH']); | ||
this.appendValueInput('ADD1'); | ||
this.addFirstInput(); | ||
for (let i = 1; i < this.minInputs; i++) { | ||
this.appendValueInput(`ADD${i}`); | ||
} | ||
this.setOutput(true, 'Array'); | ||
@@ -48,7 +51,11 @@ this.setTooltip(Blockly.Msg['LISTS_CREATE_WITH_TOOLTIP']); | ||
mutationToDom(this: DynamicListCreateBlock): Element { | ||
// If we call finalizeConnections here without disabling events, we get into | ||
// an event loop. | ||
Blockly.Events.disable(); | ||
this.finalizeConnections(); | ||
if (this instanceof Blockly.BlockSvg) this.initSvg(); | ||
Blockly.Events.enable(); | ||
const container = Blockly.utils.xml.createElement('mutation'); | ||
const inputNames = | ||
this.inputList.map((input: Blockly.Input) => input.name).join(','); | ||
container.setAttribute('inputs', inputNames); | ||
container.setAttribute('next', String(this.inputCounter)); | ||
container.setAttribute('items', `${this.itemCount}`); | ||
return container; | ||
@@ -82,4 +89,2 @@ }, | ||
} | ||
const next = parseInt(xmlElement.getAttribute('next') ?? '0', 10) || 0; | ||
this.inputCounter = next; | ||
}, | ||
@@ -92,12 +97,46 @@ | ||
deserializeCounts(this: DynamicListCreateBlock, xmlElement: Element): void { | ||
const itemCount = Math.max( | ||
this.itemCount = Math.max( | ||
parseInt(xmlElement.getAttribute('items') ?? '0', 10), this.minInputs); | ||
// Two inputs are added automatically. | ||
for (let i = this.minInputs; i < itemCount; i++) { | ||
// minInputs are added automatically. | ||
for (let i = this.minInputs; i < this.itemCount; i++) { | ||
this.appendValueInput('ADD' + i); | ||
} | ||
this.inputCounter = itemCount; | ||
}, | ||
/** | ||
* Returns the state of this block as a JSON serializable object. | ||
* @returns The state of this block, ie the item count. | ||
*/ | ||
saveExtraState: function(this: DynamicListCreateBlock): {itemCount: number} { | ||
// If we call finalizeConnections here without disabling events, we get into | ||
// an event loop. | ||
Blockly.Events.disable(); | ||
this.finalizeConnections(); | ||
if (this instanceof Blockly.BlockSvg) this.initSvg(); | ||
Blockly.Events.enable(); | ||
return { | ||
'itemCount': this.itemCount, | ||
}; | ||
}, | ||
/** | ||
* Applies the given state to this block. | ||
* @param state The state to apply to this block, ie the item count. | ||
*/ | ||
loadExtraState: function( | ||
this: DynamicListCreateBlock, state: ({[x: string]: any} | string)) { | ||
if (typeof state === 'string') { | ||
this.domToMutation(Blockly.utils.xml.textToDom(state)); | ||
return; | ||
} | ||
this.itemCount = state['itemCount']; | ||
// minInputs are added automatically. | ||
for (let i = this.minInputs; i < this.itemCount; i++) { | ||
this.appendValueInput('ADD' + i); | ||
} | ||
}, | ||
/** | ||
* Check whether a new input should be added and determine where it should go. | ||
@@ -108,3 +147,3 @@ * @param connection The connection that has a pending connection. | ||
*/ | ||
getIndexForNewInput( | ||
findInputIndexForConnection( | ||
this: DynamicListCreateBlock, | ||
@@ -149,7 +188,7 @@ connection: Blockly.Connection): number | null { | ||
this: DynamicListCreateBlock, connection: Blockly.Connection): void { | ||
const insertIndex = this.getIndexForNewInput(connection); | ||
const insertIndex = this.findInputIndexForConnection(connection); | ||
if (insertIndex == null) { | ||
return; | ||
} | ||
this.appendValueInput('ADD' + (this.inputCounter++)); | ||
this.appendValueInput(`ADD${Blockly.utils.idGenerator.genUid()}`); | ||
this.moveNumberedInputBefore(this.inputList.length - 1, insertIndex); | ||
@@ -163,25 +202,70 @@ }, | ||
finalizeConnections(this: DynamicListCreateBlock): void { | ||
if (this.inputList.length > this.minInputs) { | ||
let toRemove: string[] = []; | ||
this.inputList.forEach((input: Blockly.Input) => { | ||
if (!input.connection?.targetConnection) { | ||
toRemove.push(input.name); | ||
} | ||
}); | ||
const targetConns = | ||
this.removeUnnecessaryEmptyConns( | ||
this.inputList.map((i) => i.connection?.targetConnection)); | ||
this.tearDownBlock(); | ||
this.addItemInputs(targetConns); | ||
this.itemCount = targetConns.length; | ||
}, | ||
if (this.inputList.length - toRemove.length < this.minInputs) { | ||
// Always show at least two inputs | ||
toRemove = toRemove.slice(this.minInputs); | ||
/** Deletes all inputs on the block so it can be rebuilt. */ | ||
tearDownBlock(this: DynamicListCreateBlock): void { | ||
for (let i = this.inputList.length - 1; i >= 0; i--) { | ||
this.removeInput(this.inputList[i].name); | ||
} | ||
}, | ||
/** | ||
* Filters the given target connections so that empty connections are removed, | ||
* unless we need those to reach the minimum input count. Empty connections | ||
* are removed starting at the end of the array. | ||
* @param targetConns The list of connections associated with inputs. | ||
* @returns A filtered list of connections (or null/undefined) which should | ||
* be attached to inputs. | ||
*/ | ||
removeUnnecessaryEmptyConns( | ||
targetConns: Array<Blockly.Connection | undefined | null> | ||
): Array<Blockly.Connection | undefined | null> { | ||
const filteredConns = [...targetConns]; | ||
for (let i = filteredConns.length - 1; i >= 0; i--) { | ||
if (!filteredConns[i] && filteredConns.length > this.minInputs) { | ||
filteredConns.splice(i, 1); | ||
} | ||
toRemove.forEach((inputName) => this.removeInput(inputName)); | ||
// The first input should have the block text. If we removed the | ||
// first input, add the block text to the new first input. | ||
if (this.inputList[0].fieldRow.length == 0) { | ||
this.inputList[0] | ||
.appendField(Blockly.Msg['LISTS_CREATE_WITH_INPUT_WITH']); | ||
} | ||
} | ||
return filteredConns; | ||
}, | ||
/** | ||
* Adds inputs based on the given array of target cons. An input is added for | ||
* every entry in the array (if it does not already exist). If the entry is | ||
* a connection and not null/undefined the connection will be connected to | ||
* the input. | ||
* @param targetConns The connections defining the inputs to add. | ||
*/ | ||
addItemInputs( | ||
this: DynamicListCreateBlock, | ||
targetConns: Array<Blockly.Connection | undefined | null>, | ||
): void { | ||
const input = this.addFirstInput(); | ||
const firstConn = targetConns[0]; | ||
if (firstConn) input.connection?.connect(firstConn); | ||
for (let i = 1; i < targetConns.length; i++) { | ||
const input = this.appendValueInput(`ADD${i}`); | ||
const targetConn = targetConns[i]; | ||
if (targetConn) input.connection?.connect(targetConn); | ||
} | ||
}, | ||
/** | ||
* Adds the top input with the label to this block. | ||
* @returns The added input. | ||
*/ | ||
addFirstInput(this: DynamicListCreateBlock): Blockly.Input { | ||
return this.appendValueInput('ADD0') | ||
.appendField(Blockly.Msg['LISTS_CREATE_WITH_INPUT_WITH']); | ||
}, | ||
}; | ||
Blockly.Blocks['dynamic_list_create'] = DYNAMIC_LIST_CREATE_MIXIN; |
@@ -25,15 +25,16 @@ /** | ||
/* eslint-enable @typescript-eslint/naming-convention */ | ||
/** Counter for the next input to add to this block. */ | ||
inputCounter: 2, | ||
/** Minimum number of inputs for this block. */ | ||
minInputs: 2, | ||
/** Count of the item inputs. */ | ||
itemCount: 0, | ||
/** Block for concatenating any number of strings. */ | ||
init(this: DynamicTextJoinBlock): void { | ||
this.itemCount = this.minInputs; | ||
this.setHelpUrl(Blockly.Msg['TEXT_JOIN_HELPURL']); | ||
this.setStyle('text_blocks'); | ||
this.appendValueInput('ADD0') | ||
.appendField(Blockly.Msg['TEXT_JOIN_TITLE_CREATEWITH']); | ||
this.appendValueInput('ADD1'); | ||
this.addFirstInput(); | ||
for (let i = 1; i < this.minInputs; i++) this.appendValueInput(`ADD${i}`); | ||
this.setOutput(true, 'String'); | ||
@@ -48,7 +49,11 @@ this.setTooltip(Blockly.Msg['TEXT_JOIN_TOOLTIP']); | ||
mutationToDom(this: DynamicTextJoinBlock): Element { | ||
// If we call finalizeConnections here without disabling events, we get into | ||
// an event loop. | ||
Blockly.Events.disable(); | ||
this.finalizeConnections(); | ||
if (this instanceof Blockly.BlockSvg) this.initSvg(); | ||
Blockly.Events.enable(); | ||
const container = Blockly.utils.xml.createElement('mutation'); | ||
const inputNames = | ||
this.inputList.map((input: Blockly.Input) => input.name).join(','); | ||
container.setAttribute('inputs', inputNames); | ||
container.setAttribute('next', String(this.inputCounter)); | ||
container.setAttribute('items', `${this.itemCount}`); | ||
return container; | ||
@@ -82,4 +87,2 @@ }, | ||
} | ||
const next = parseInt(xmlElement.getAttribute('next') ?? '0', 10) || 0; | ||
this.inputCounter = next; | ||
}, | ||
@@ -92,12 +95,46 @@ | ||
deserializeCounts(this: DynamicTextJoinBlock, xmlElement: Element): void { | ||
const itemCount = Math.max( | ||
this.itemCount = Math.max( | ||
parseInt(xmlElement.getAttribute('items') ?? '0', 10), this.minInputs); | ||
// Two inputs are added automatically. | ||
for (let i = this.minInputs; i < itemCount; i++) { | ||
// minInputs are added automatically. | ||
for (let i = this.minInputs; i < this.itemCount; i++) { | ||
this.appendValueInput('ADD' + i); | ||
} | ||
this.inputCounter = itemCount; | ||
}, | ||
/** | ||
* Returns the state of this block as a JSON serializable object. | ||
* @returns The state of this block, ie the item count. | ||
*/ | ||
saveExtraState: function(this: DynamicTextJoinBlock): {itemCount: number} { | ||
// If we call finalizeConnections here without disabling events, we get into | ||
// an event loop. | ||
Blockly.Events.disable(); | ||
this.finalizeConnections(); | ||
if (this instanceof Blockly.BlockSvg) this.initSvg(); | ||
Blockly.Events.enable(); | ||
return { | ||
'itemCount': this.itemCount, | ||
}; | ||
}, | ||
/** | ||
* Applies the given state to this block. | ||
* @param state The state to apply to this block, ie the item count. | ||
*/ | ||
loadExtraState: function( | ||
this: DynamicTextJoinBlock, state: ({[x: string]: any} | string)) { | ||
if (typeof state === 'string') { | ||
this.domToMutation(Blockly.utils.xml.textToDom(state)); | ||
return; | ||
} | ||
this.itemCount = state['itemCount']; | ||
// minInputs are added automatically. | ||
for (let i = this.minInputs; i < this.itemCount; i++) { | ||
this.appendValueInput('ADD' + i); | ||
} | ||
}, | ||
/** | ||
* Check whether a new input should be added and determine where it should go. | ||
@@ -108,3 +145,3 @@ * @param connection The connection that has a pending connection. | ||
*/ | ||
getIndexForNewInput( | ||
findInputIndexForConnection( | ||
this: DynamicTextJoinBlock, | ||
@@ -150,7 +187,7 @@ connection: Blockly.Connection): number | null { | ||
this: DynamicTextJoinBlock, connection: Blockly.Connection): void { | ||
const insertIndex = this.getIndexForNewInput(connection); | ||
const insertIndex = this.findInputIndexForConnection(connection); | ||
if (insertIndex == null) { | ||
return; | ||
} | ||
this.appendValueInput('ADD' + (this.inputCounter++)); | ||
this.appendValueInput(`ADD${Blockly.utils.idGenerator.genUid()}`); | ||
this.moveNumberedInputBefore(this.inputList.length - 1, insertIndex); | ||
@@ -164,25 +201,71 @@ }, | ||
finalizeConnections(this: DynamicTextJoinBlock): void { | ||
if (this.inputList.length > this.minInputs) { | ||
let toRemove: string[] = []; | ||
this.inputList.forEach((input: Blockly.Input) => { | ||
if (!input.connection?.targetConnection) { | ||
toRemove.push(input.name); | ||
} | ||
}); | ||
const targetConns = | ||
this.removeUnnecessaryEmptyConns( | ||
this.inputList.map((i) => i.connection?.targetConnection)); | ||
this.tearDownBlock(); | ||
this.addItemInputs(targetConns); | ||
this.itemCount = targetConns.length; | ||
}, | ||
if (this.inputList.length - toRemove.length < this.minInputs) { | ||
// Always show at least two inputs | ||
toRemove = toRemove.slice(this.minInputs); | ||
/** Deletes all inputs on this block so it can be rebuilt. */ | ||
tearDownBlock(this: DynamicTextJoinBlock): void { | ||
for (let i = this.inputList.length - 1; i >= 0; i--) { | ||
this.removeInput(this.inputList[i].name); | ||
} | ||
}, | ||
/** | ||
* Filters the given target connections so that empty connections are removed, | ||
* unless we need those to reach the minimum input count. Empty connections | ||
* are removed starting at the end of the array. | ||
* @param targetConns The list of connections associated with inputs. | ||
* @returns A filtered list of connections (or null/undefined) which should | ||
* be attached to inputs. | ||
*/ | ||
removeUnnecessaryEmptyConns( | ||
this: DynamicTextJoinBlock, | ||
targetConns: Array<Blockly.Connection | undefined | null> | ||
): Array<Blockly.Connection | undefined | null> { | ||
const filteredConns = [...targetConns]; | ||
for (let i = filteredConns.length - 1; i >= 0; i--) { | ||
if (!filteredConns[i] && filteredConns.length > this.minInputs) { | ||
filteredConns.splice(i, 1); | ||
} | ||
toRemove.forEach((inputName) => this.removeInput(inputName)); | ||
// The first input should have the block text. If we removed the | ||
// first input, add the block text to the new first input. | ||
if (this.inputList[0].fieldRow.length == 0) { | ||
this.inputList[0] | ||
.appendField(Blockly.Msg['TEXT_JOIN_TITLE_CREATEWITH']); | ||
} | ||
} | ||
return filteredConns; | ||
}, | ||
/** | ||
* Adds inputs based on the given array of target conns. An input is added for | ||
* every entry in the array (if it does not already exist). If the entry is | ||
* a connection and not null/undefined the connection will be connected to | ||
* the input. | ||
* @param targetConns The connections defining the inputs to add. | ||
*/ | ||
addItemInputs( | ||
this: DynamicTextJoinBlock, | ||
targetConns: Array<Blockly.Connection | undefined | null>, | ||
): void { | ||
const input = this.addFirstInput(); | ||
const firstConn = targetConns[0]; | ||
if (firstConn) input.connection?.connect(firstConn); | ||
for (let i = 1; i < targetConns.length; i++) { | ||
const input = this.appendValueInput(`ADD${i}`); | ||
const targetConn = targetConns[i]; | ||
if (targetConn) input.connection?.connect(targetConn); | ||
} | ||
}, | ||
/** | ||
* Adds the top input with the label to this block. | ||
* @returns The added input. | ||
*/ | ||
addFirstInput(this: DynamicTextJoinBlock): Blockly.Input { | ||
return this.appendValueInput('ADD0') | ||
.appendField(Blockly.Msg['TEXT_JOIN_TITLE_CREATEWITH']); | ||
}, | ||
}; | ||
Blockly.Blocks['dynamic_text_join'] = DYNAMIC_TEXT_JOIN_MIXIN; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
122249
1010
32