$('.blpn-nodeEditor-tab-click').click( function(event) { event.preventDefault(); $('.blpn-nodeEditor-left').css('width','100%'); $('.blpn-nodeEditor-right').animate({width:'toggle'}); } ); $(`.blpn-panel-area-vertical-btn`).click(function() { if ($(this).hasClass(`blpn-arrow-down`)) { $(this).removeClass(`blpn-arrow-down`); $(this).addClass(`blpn-arrow-up`); $(this).parent().parent().removeClass(`blpn-minimize`); } else { $(this).removeClass(`blpn-arrow-up`); $(this).addClass(`blpn-arrow-down`); $(this).parent().parent().addClass(`blpn-minimize`); } }); // MOUSE SETUP // ============= var mouse = { currentLink: null, createPath: function(a, b) { var diff = { x: b.x - a.x, y: b.y - a.y }; var pathStr = 'M' + a.x + ',' + a.y + ' '; pathStr += 'C'; pathStr += a.x + diff.x / 3 * 2 + ',' + a.y + ' '; pathStr += a.x + diff.x / 3 + ',' + b.y + ' '; pathStr += b.x + ',' + b.y; return pathStr; } }; // CLEAN UP AND ACTUAL CODE [WIP] // ================================ var getFullOffset = function(element) { var offset = { top: element.offsetTop, left: element.offsetLeft, }; if (element.offsetParent) { var po = getFullOffset(element.offsetParent); offset.top += po.top; offset.left += po.left; return offset; } else { return offset; } } var svg = document.getElementById('svg'); svg.ns = svg.namespaceURI; window.onmousemove = function(event) { if (mouse.currentLink) { var p = mouse.currentLink.path; var iP = mouse.currentLink.getAttachPoint(); var oP = { x: event.pageX , y: event.pageY }; var s = mouse.createPath(iP, oP); p.setAttributeNS(null, 'd', s); } }; window.onclick = function(e) { if (mouse.currentLink) { mouse.currentLink.path.removeAttribute('d'); if (mouse.currentLink.nextNode) { mouse.currentLink.nextNode.detachLink(mouse.currentLink); } mouse.currentLink = null; } }; // commonApi var getUUID = function() { return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); } // stateApi /** findStateValue 함수 * state를 while루프로 돌면서 돌면서 keyName과 일치하는 state의 value값을 찾아 리턴한다 * 없으면 null을 리턴한다. * @param {object} state * @param {string} keyName * @returns {any | null} returnValueOrNull */ var findStateValue = function(state, keyName) { var result = []; var stack = [{ context: result , key: 0 , value: state }]; var currContext; var returnValueOrNull = null; while (currContext = stack.pop()) { var { context, key, value } = currContext; if (!value || typeof value != 'object') { if (key === keyName) { returnValueOrNull = value; break; } context[key] = value; } else if (Array.isArray(value)) { if (key === keyName) { returnValueOrNull = value; break; } } else { if (key === keyName) { returnValueOrNull = value; break; } context = context[key] = Object.create(null); Object.entries(value).forEach(([ key,value ]) => { stack.push({ context, key, value }); }); } }; return returnValueOrNull; }; /** changeOldToNewState 함수 * oldState(이전 state 데이터)와 newState(새로운 state 데이터)를 비교해서 newState로 들어온 새로운 값을 oldState에 덮어 씌운다. * @param {Object} oldState * @param {Object} newState * @returns {Object} */ var changeOldToNewState = function(oldState, newState) { var result = []; var stack = [{ context: result , key: 0 , value: oldState }]; var currContext; while (currContext = stack.pop()) { var { context, key, value } = currContext; if (!value || typeof value != 'object') { var newValue = findStateValue(newState, key); if ( newValue === "") { context[key] = ""; } else if (newValue === false) { context[key] = false; } else { context[key] = newValue || value; } } else if (Array.isArray(value)) { var newValue = findStateValue(newState, key); context[key] = newValue || value; } else { context = context[key] = Object.create(null); Object.entries(value).forEach(([ key, value ]) => { stack.push({context, key, value}); }); } }; return result[0]; }; /** updateOneArrayIndexValueAndGetNewArray * 배열의 특정 인덱스 값을 업데이트하고 업데이트된 새로운 배열을 리턴한다 * @param {Array} array * @param {number} index * @param {number | string} newValue * @returns {Array} New array */ var updateOneArrayIndexValueAndGetNewArray = function(array, index, newValue) { return [ ...array.slice(0, index), newValue, ...array.slice(index+1, array.length) ] } /** deleteOneArrayIndexValueAndGetNewArray * 배열의 특정 인덱스 값을 삭제하고 삭제된 새로운 배열을 리턴한다 * @param {Array} array * @param {number} index * @returns {Array} New array */ var deleteOneArrayIndexValueAndGetNewArray = function(array, index) { return [ ...array.slice(0, index), ...array.slice(index+1, array.length) ] } /** updateTwoArrayIndexValueAndGetNewArray * 2차원 배열의 특정 인덱스 값을 업데이트하고 업데이트된 새로운 배열을 리턴한다 * @param {Array} array * @param {number} row * @param {number} col * @param {number | string} newValue * @returns {Array} New array */ var updateTwoArrayIndexValueAndGetNewArray = function(twoarray, row, col, newValue) { var newArray = [...twoarray[row].slice(0, col),newValue, ...twoarray[row].slice(col + 1, twoarray[row].length)] return [ ...twoarray.slice(0, row), newArray, ...twoarray.slice(row+1, twoarray.length) ] } /** deleteTwoArrayIndexValueAndGetNewArray * 2차원 배열의 특정 인덱스 값을 삭제하고 삭제된 새로운 배열을 리턴한다 * @param {Array} array * @param {number} row * @param {number} col * @returns {Array} New array */ var deleteTwoArrayIndexValueAndGetNewArray = function(twoarray, row, col) { var newArray = [...twoarray[row].slice(0, col), ...twoarray[row].slice(col + 1, twoarray[row].length)] return [ ...twoarray.slice(0, row), newArray, ...twoarray.slice(row+1, twoarray.length) ] } const BLPN_NODE_EDITOR_LEFT = `.blpn-nodeEditor-left`; const NODE_BLOCK_BTN_ENUM = { CLASS: 1 , DEF: 2 , IF: 3 , FOR: 4 , WHILE: 5 , IMPORT: 6 , API: 7 , TRY: 8 , CODE: 9 } const NODE_BLOCK_ENUM = { CLASS: 1 , DEF: 2 , IF: 3 , FOR: 4 , WHILE: 5 , IMPORT: 6 , API: 7 , TRY: 8 , CODE: 9 } const NODE_OPERATOR_ENUM = { PLUS: 1 , MINUS: 2 , MULTIPLY: 3 , DIVIDE: 4 , ASSIGN: 5 , NOT_SAME: 6 , SAME:7 , LESS_THAN: 8 , LESS_THAN_OR_SAME: 9 , MORE_THAN: 10 , MORE_THAN_OR_SMAE: 11 , PLUS_ASSIGN: 12 , MINUS_ASSIGN: 13 , IN: 14 } const NODE_ELEMENT_ENUM = { CLASS: 1 , DEF: 2 , IF: 3 , FOR: 4 , WHILE: 5 , IMPORT: 6 , API: 7 , TRY: 8 , CODE: 9 , ELIF: 10 , ELSE: 11 } var NodeCodeLine = function( nodeElementThis ) { this.rootDomElement; this.uuid = getUUID(); this.nodeElementThis = nodeElementThis; this.codeTokenArray = [ ]; this.render(); } NodeCodeLine.prototype.render = function() { var rootDomElement = $(`
Drop Here
`); this.setRootDomElement(rootDomElement); } NodeCodeLine.prototype.setRootDomElement = function(element) { this.rootDomElement = element; } NodeCodeLine.prototype.getRootDomElement = function() { return this.rootDomElement; } var NodeLink = function( nodeElementThis ) { this.rootDomElement; this.uuid = getUUID(); this.nodeElementThis = nodeElementThis; this.nextNode = null; this.path; this.render(); } NodeLink.prototype.render = function() { var nodeLinkDomElementContainer = $(``); var nodeNext = $(`
Next
`); var nodeLinkDomElement = document.createElement('span'); nodeLinkDomElement.classList.add('blpn-node-link'); nodeNext.append(nodeLinkDomElement); nodeLinkDomElementContainer.append(nodeNext); this.setRootDomElement(nodeLinkDomElementContainer); this.setNodeLinkDomElement(nodeLinkDomElement); // SVG Connector this.path = document.createElementNS(svg.ns, 'path'); this.path.setAttributeNS(null, 'stroke', '#545454'); this.path.setAttributeNS(null, 'stroke-width', '2'); this.path.setAttributeNS(null, 'fill', 'none'); svg.appendChild(this.path); this.bindClickNodeLinkEventFunction(); } NodeLink.prototype.getNodeThis = function() { var nodeElementThis = this.getNodeElementThis(); var nodeThis = nodeElementThis.getNodeThis(); return nodeThis; } NodeLink.prototype.getNodeElementThis = function() { return this.nodeElementThis; } NodeLink.prototype.setRootDomElement = function(element) { this.rootDomElement = element; } NodeLink.prototype.getRootDomElement = function() { return this.rootDomElement; } NodeLink.prototype.setNodeLinkDomElement = function(element) { this.nodeLinkDomElement = element; } NodeLink.prototype.getNodeLinkDomElement = function() { return this.nodeLinkDomElement; } NodeLink.prototype.getNextNode = function() { return this.nextNode; } NodeLink.prototype.setNextNode = function(nextNode) { this.nextNode = nextNode; } NodeLink.prototype.getAttachPoint = function() { var offset = this.getNodeLinkDomElement().getBoundingClientRect(); return { x: offset.left , y: offset.top }; }; NodeLink.prototype.bindClickNodeLinkEventFunction = function() { // DOM Event handlers var that = this; var nodeLinkDomElement = this.getNodeLinkDomElement(); nodeLinkDomElement.onclick = function(event) { if (mouse.currentLink) { if (mouse.currentLink.path.hasAttribute('d')) mouse.currentLink.path.removeAttribute('d'); if (mouse.currentLink.nextNode) { mouse.currentLink.nextNode.detachLink(mouse.currentLink); mouse.currentLink.nextNode = null; } } mouse.currentLink = that; if (that.nextNode) { that.nextNode.detachLink(that); $(this).removeClass('filled'); $(this).addClass('empty'); } event.stopPropagation(); }; } /** option * isCodeLine * isNodeLink */ var NodeElement = function(nodeThis, subType, elementNum, option ) { this.rootDomElement; this.nodeLinkDomElement; this.nodeCodeLineDomElement; this.deleteButtonElement; this.uuid = getUUID(); this.subType = subType; this.nodeThis = nodeThis; /** subtype이 class (1) 타입이면 코드라인을 생성하지 않는다 */ if (subType === 1) { this.nodeCodeLine = null; } else { this.nodeCodeLine = new NodeCodeLine(this); } if (option && option.isNodeLink === false ) { this.nodeLink = null; } else { this.nodeLink = new NodeLink(this); } var newNodeCodeLineDomElement = $(`
Drop Here
`); this.setNodeCodeLineDomElement(newNodeCodeLineDomElement); // if (subType === 1) { // nodeThis.addClassState('init'); // } //FIXME: this.elementNum = elementNum; } NodeElement.prototype.getElementNum = function() { return this.elementNum; } NodeElement.prototype.setElementNum = function(elementNum) { this.elementNum = elementNum; } NodeElement.prototype.render = function(elementNum) { var _rootDomElement = this.getRootDomElement(); $(_rootDomElement).empty(); $(_rootDomElement).remove(); this.setElementNum(elementNum); var nodeThis = this.getNodeThis(); var subType = this.getSubType(); // var rootDomNodeElement = $(`
//
`); var rootDomNodeElement = document.createElement('div'); rootDomNodeElement.classList.add('blpn-node-element-container'); var nodeElementHeader; switch (subType) { // class case 1: { this.setRootDomElement(rootDomNodeElement); this.renderClassState(elementNum); break; } // def case 2: { var nodeElementRow = $(`
`); var nodeCodeLineRootDom = this.getNodeCodeLineDomElement(); var nodeLinkRootDom = this.nodeLink.getRootDomElement(); nodeElementRow.append(nodeCodeLineRootDom); nodeElementRow.append(nodeLinkRootDom); $(rootDomNodeElement).append(nodeElementRow); this.setRootDomElement(rootDomNodeElement); this.setNodeCodeLineDomElement(nodeCodeLineRootDom); this.setNodeLinkDomElement(nodeLinkRootDom); break; } // if case 3: { this.setRootDomElement(rootDomNodeElement); this.renderIfState(elementNum); break; } // for case 4: { var nodeElementRow = $(`
`); var nodeCodeLineRootDom = this.getNodeCodeLineDomElement(); var nodeLinkRootDom = this.nodeLink.getRootDomElement(); nodeElementRow.append(nodeCodeLineRootDom); nodeElementRow.append(nodeLinkRootDom); $(rootDomNodeElement).append(nodeElementRow); this.setRootDomElement(rootDomNodeElement); this.setNodeCodeLineDomElement(nodeCodeLineRootDom); this.setNodeLinkDomElement(nodeLinkRootDom); break; } // while case 5: { var nodeElementRow = $(`
`); var nodeCodeLineRootDom = this.getNodeCodeLineDomElement(); var nodeLinkRootDom = this.nodeLink.getRootDomElement(); nodeElementRow.append(nodeCodeLineRootDom); nodeElementRow.append(nodeLinkRootDom); $(rootDomNodeElement).append(nodeElementRow); this.setRootDomElement(rootDomNodeElement); this.setNodeCodeLineDomElement(nodeCodeLineRootDom); this.setNodeLinkDomElement(nodeLinkRootDom); break; } // code case 9: { this.setRootDomElement(rootDomNodeElement); this.renderCodeState(elementNum); break; } // elif case 10: { this.setRootDomElement(rootDomNodeElement); this.renderIfState(elementNum); break; } // else case 11: { this.setRootDomElement(rootDomNodeElement); this.renderIfState(elementNum); break; } default: { break; } } var nodeThis = this.getNodeThis(); var nodeRootDomElement = nodeThis.getRootDomElement(); $(nodeRootDomElement).append(rootDomNodeElement); } NodeElement.prototype.getSubType = function() { return this.subType; } NodeElement.prototype.getNodeThis = function() { return this.nodeThis; } NodeElement.prototype.getNodeCodeLine = function() { return this.nodeCodeLine; } NodeElement.prototype.getNodeLink = function() { return this.nodeLink; } NodeElement.prototype.setRootDomElement = function(element) { this.rootDomElement = element; } NodeElement.prototype.getRootDomElement = function() { return this.rootDomElement; } NodeElement.prototype.makeNodeCodeLineDomElement = function(operatorSubType) { var nodeThis = this.getNodeThis(); var elementNum = this.getElementNum(); var nodeElementSubType = this.getSubType(); var reNewData = function(data) { // console.log('elementNum', elementNum); // console.log('operatorSubType', operatorSubType); // console.log('nodeElementSubType', nodeElementSubType); if ( nodeElementSubType === 3 || nodeElementSubType === 10 || nodeElementSubType === 11) { nodeThis.getState('ifCodeLineList')[elementNum].codeTokenList.push(data); // console.log('ifCodeLineList', nodeThis.getState('ifCodeLineList')); } else if (nodeElementSubType === 9) { nodeThis.getState('codeBlockLineList')[elementNum].codeTokenList.push(data); // console.log('codeBlockLineList', nodeThis.getState('codeBlockLineList')); } } var operatorName = ``; switch (operatorSubType) { case 1: { var codeToken = { type: "CALCULATION_OPERATOR", data:"+" } reNewData(codeToken); operatorName = `+`; break; } case 2: { var codeToken = { type: "CALCULATION_OPERATOR", data:"-" } reNewData(codeToken); operatorName = `-`; break; } case 3: { var codeToken = { type: "CALCULATION_OPERATOR", data:"*" } reNewData(codeToken); operatorName = `x`; break; } case 4: { var codeToken = { type: "CALCULATION_OPERATOR", data:"/" } reNewData(codeToken); operatorName = `÷`; break; } case 5: { var codeToken = { type: "ASSIGN_OPERATOR", data:"=" } reNewData(codeToken); operatorName = `=`; break; } case 6: { var codeToken = { type: "CONDITION_OPERATOR", data:"!=" } reNewData(codeToken); operatorName = `≠≠`; break; } case 7: { var codeToken = { type: "CONDITION_OPERATOR", data:"==" } reNewData(codeToken); operatorName = `==`; break; } case 8: { var codeToken = { type: "CONDITION_OPERATOR", data:"<" } reNewData(codeToken); operatorName = `<`; break; } case 9: { var codeToken = { type: "CONDITION_OPERATOR", data:"<=" } reNewData(codeToken); operatorName = `≤`; break; } case 10: { var codeToken = { type: "CONDITION_OPERATOR", data:">" } reNewData(codeToken); operatorName = `>`; break; } case 11: { var codeToken = { type: "CONDITION_OPERATOR", data:">=" } reNewData(codeToken); operatorName = `≥`; break; } case 12: { var codeToken = { type: "CALCULATION_OPERATOR", data:"+=" } reNewData(codeToken); operatorName = `+=`; break; } case 13: { var codeToken = { type: "CALCULATION_OPERATOR", data:"-=" } reNewData(codeToken); operatorName = `-=`; break; } case 14: { var codeToken = { type: "CONDITION_OPERATOR", data:"in" } reNewData(codeToken); operatorName = `in`; break; } default :{ break; } } var newNodeCodeLineDomElement = $(`
Drop Here ${operatorName} Drop Here
`); this.setNodeCodeLineDomElement(newNodeCodeLineDomElement); // this.render(); var nodeThis = this.getNodeThis(); nodeThis.renderNodeElementList(); } NodeElement.prototype.setNodeCodeLineDomElement = function(element) { this.nodeCodeLineDomElement = element; } NodeElement.prototype.getNodeCodeLineDomElement = function() { return this.nodeCodeLineDomElement; } NodeElement.prototype.setNodeLinkDomElement = function(element) { this.nodeLinkDomElement = element; } NodeElement.prototype.getNodeLinkDomElement = function() { return this.nodeLinkDomElement; } NodeElement.prototype.setDeleteButtonElement = function(element) { this.deleteButtonElement = element; } NodeElement.prototype.getDeleteButtonElement = function() { return this.deleteButtonElement; } NodeElement.prototype.getUUID = function() { return this.uuid; } NodeElement.prototype.setUUID = function(uuid) { this.uuid = uuid; } NodeElement.prototype.getCodeLineDomPoint = function() { var rootDomElement = this.getRootDomElement(); var offset = rootDomElement.getElementsByClassName("blpn-node-codeline")[0].getBoundingClientRect(); return { x: offset.left , y: offset.top , width: offset.width , height: offset.height , dom: rootDomElement.getElementsByClassName("blpn-node-codeline")[0] , nodeElementThis: this , nodeThis : this.getNodeThis() }; }; /** type에 따른 렌더링 */ NodeElement.prototype.renderClassState = function(index) { var nodeThis = this.getNodeThis(); var rootDomNodeElement = this.getRootDomElement(); var methodName = nodeThis.getState(`methodList`)[index].name; var nodeElementHeader = $(`
`); if( methodName !== '_init_') { var deleteButtonElement = $(``); nodeElementHeader.append(deleteButtonElement); this.setDeleteButtonElement(deleteButtonElement); this.bindDeleteNodeElementEventFunction(); var flexRow = $(`
`); var methodNameElement = $(`
Method:
`); var methodNameInput = $(``); flexRow.append(methodNameElement); flexRow.append(methodNameInput); $(methodNameInput).on("change keyup paste", function() { nodeThis.getState('methodList')[index]['name'] = $(this).val() }); $(rootDomNodeElement).append(flexRow); } else { var initName = $(`${ methodName || ''}`); nodeElementHeader.append(initName); } var nodeElementRow = $(`
`); var nodeEmptyLineDom = $(`
`); var inParamDomeElement = $(`
In Param:
`); nodeThis.getState(`methodList`)[index]['inParamList'].forEach( (inParam, paramIndex) => { var inParamNode = $(`
${paramIndex}
`); var input = $(``); var deleteButton = $(``); $(input).on("change keyup paste", function() { var newData = { name: $(this).val() } nodeThis.getState('methodList')[index]['inParamList'][paramIndex] = newData; }); $(deleteButton).on('click', function() { nodeThis.getState('methodList')[index]['inParamList'].splice(paramIndex,1); nodeThis.render(); }); inParamNode.append(input); inParamNode.append(deleteButton); inParamDomeElement.append(inParamNode); }); var inParamPlusButton = $(``); $(inParamPlusButton).click(function() { var newData = { name: '' } nodeThis.getState('methodList')[index]['inParamList'].push(newData); nodeThis.render(); }); nodeEmptyLineDom.append(inParamDomeElement); nodeEmptyLineDom.append(inParamPlusButton); var nodeLinkRootDom = this.nodeLink.getRootDomElement(); nodeElementRow.append(nodeEmptyLineDom); nodeElementRow.append(nodeLinkRootDom); $(rootDomNodeElement).append(nodeElementHeader); $(rootDomNodeElement).append(nodeElementRow); } NodeElement.prototype.renderIfState = function(index) { var nodeThis = this.getNodeThis(); var rootDomNodeElement = this.getRootDomElement(); var {name} = nodeThis.getState('ifCodeLineList')[index]; var nodeElementHeader = $(`
${name}
`); if ( name !== 'IF') { var deleteButtonElement = $(``); nodeElementHeader.append(deleteButtonElement); this.setDeleteButtonElement(deleteButtonElement); this.bindDeleteNodeElementEventFunction(); $(rootDomNodeElement).append(nodeElementHeader); } var nodeElementRow = $(`
`); // var nodeCodeLineRootDom = this.nodeCodeLine.getRootDomElement(); var nodeCodeLineRootDom = this.getNodeCodeLineDomElement(); var nodeLinkRootDom = this.nodeLink.getRootDomElement(); nodeElementRow.append(nodeCodeLineRootDom); nodeElementRow.append(nodeLinkRootDom); $(rootDomNodeElement).append(nodeElementRow); this.setNodeCodeLineDomElement(nodeCodeLineRootDom); this.setNodeLinkDomElement(nodeLinkRootDom); } NodeElement.prototype.renderCodeState = function(index) { var nodeThis = this.getNodeThis(); var rootDomNodeElement = this.getRootDomElement(); // console.log(nodeThis.getState('codeBlockLineList'), index); var { codeTokenList } = nodeThis.getState('codeBlockLineList')[index]; var nodeElementHeader = $(`
`); var deleteButtonElement = $(``); nodeElementHeader.append(deleteButtonElement); this.setDeleteButtonElement(deleteButtonElement); this.bindDeleteNodeElementEventFunction(); $(rootDomNodeElement).append(nodeElementHeader); var nodeElementRow = $(`
`); // var nodeCodeLineRootDom = this.nodeCodeLine.getRootDomElement(); var nodeCodeLineRootDom = this.getNodeCodeLineDomElement(); var nodeLinkRootDom = this.nodeLink.getRootDomElement(); nodeElementRow.append(nodeCodeLineRootDom); nodeElementRow.append(nodeLinkRootDom); $(rootDomNodeElement).append(nodeElementRow); this.setNodeCodeLineDomElement(nodeCodeLineRootDom); this.setNodeLinkDomElement(nodeLinkRootDom); } /** 이벤트 함수 바인딩 */ NodeElement.prototype.bindDeleteNodeElementEventFunction = function() { var that = this; var deleteButtonElement = this.getDeleteButtonElement(); deleteButtonElement.click( function() { var subType = that.getSubType(); var elementNum = that.getElementNum(); // console.log('삭제 subType, elementNum',subType, elementNum); var nodeThis = that.getNodeThis(); /** node의 특정 elementNum의 class state 삭제*/ if ( subType === 1) { nodeThis.deleteOneArrayIndexValue("methodList", elementNum); } /** node의 특정 elementNum의 if state 삭제*/ if ( subType === 10 || subType === 11) { nodeThis.deleteOneArrayIndexValue("ifCodeLineList", elementNum); } /** node의 특정 elementNum의 codeBlock state 삭제*/ if ( subType === 9) { nodeThis.deleteOneArrayIndexValue("codeBlockLineList", elementNum); } var rootDomElement = that.getRootDomElement(); var uuid = that.getUUID(); nodeThis.deleteNodeElement(uuid); $(rootDomElement).empty(); $(rootDomElement).remove(); nodeThis.renderNodeElementList(); }); } var Node = function(nodeContainerThis, subType, point) { this.type = `NODE`; this.subType = subType; this.pointX = point.x; this.pointY = point.y; this.scrollNum = 1; this.isConnected = false; this.uuid = getUUID(); this.nodeContainerThis = nodeContainerThis; // nodeContainer에 push 될 때 할당 this.rootDomElement; // render 시점에 할당 this.deleteBtnDomElement; // render 시점에 할당 // this.nodeCodeLineList = []; // this.nodeLinkList = []; this.nodeElementList = []; this.attachedLinkList = []; /** * subType에 따라 node의 state는 달라짐 */ this.state = { class: { methodButton: null , selfVariableList: [] , methodList: [ // { // name:'_init_' // , inParamList: [] // } ] , inParamList: [] } , def: { defName: '' , defInParamList: [] , defOutParamList: [] } , if: { elifButton: null , elseButton: null , ifCodeLineList: [] } , for: { forCodeLine: '' } , while: { whileCodeLine: '' } , code: { codeBlockLineList: [] , lineButton: null } } if (this.subType === 1) { this.addNodeElement(NODE_ELEMENT_ENUM.CLASS); this.addClassState('init'); } if (this.subType === 3) { this.addNodeElement(NODE_ELEMENT_ENUM.IF); this.addIfState('IF'); } if (this.subType === 9) { this.addNodeElement(NODE_ELEMENT_ENUM.CODE); this.addCodeBlockState(); } this.render(); } Node.prototype.getSubType = function() { return this.subType; } Node.prototype.getUUID = function() { return this.uuid; } Node.prototype.setUUID = function(uuid) { this.uuid = uuid; } Node.prototype.getNodeContainerThis = function() { return this.nodeContainerThis; } Node.prototype.setNodeContainerThis = function(nodeContainerThis) { this.nodeContainerThis = nodeContainerThis; } Node.prototype.getPointX = function() { return this.pointX; } Node.prototype.setPointX = function(pointX) { this.pointX = pointX; } Node.prototype.setPointY = function(pointY) { this.pointY = pointY; } Node.prototype.getPointY = function() { return this.pointY; } Node.prototype.getScrollNum = function() { return this.scrollNum; } Node.prototype.setScrollNum = function(scrollNum) { this.scrollNum = scrollNum; } Node.prototype.getIsConnected = function() { return this.isConnected; } Node.prototype.setIsConnectedToFalse = function() { this.isConnected = false; } Node.prototype.setIsConnectedToTrue = function() { this.isConnected = true; } /** DOM 조작 관련 메소드 들 */ Node.prototype.setRootDomElement = function(element) { this.rootDomElement = element; } Node.prototype.getRootDomElement = function() { return this.rootDomElement; } Node.prototype.setDeleteBtnDomElement = function(element) { this.deleteBtnDomElement = element; } Node.prototype.getDeleteBtnDomElement = function() { return this.deleteBtnDomElement; } Node.prototype.setHeaderLinkDomElement = function(element) { this.headerLinkDomElement = element; } Node.prototype.getHeaderLinkDomElement = function() { return this.headerLinkDomElement; } // Node.prototype.getNodeCodeLineList = function() { // return this.nodeCodeLineList; // } // Node.prototype.addNodeCodeLine = function(nodeCodeLine) { // this.nodeCodeLineList.push(nodeCodeLine); // } // Node.prototype.deleteCodeLine = function() { // } // Node.prototype.getNodeLinkList = function() { // return this.nodeLinkList; // } // Node.prototype.addNodeLink = function(nodeLink) { // this.nodeLinkList.push(nodeLink); // } // Node.prototype.deleteNodeLink = function() { // } Node.prototype._renderHeaderLink = function(headerName) { var rootDomElement = this.getRootDomElement(); var header = $(`
${headerName}
`); // headerLinkDomElement = $(``); var headerLinkDomElement = document.createElement('span'); headerLinkDomElement.classList.add('blpn-node-headlink'); headerLinkDomElement.innerHTML = ' '; $(header).append(headerLinkDomElement); $(rootDomElement).append(header); var that = this; headerLinkDomElement.onclick = function(event) { if (mouse.currentLink && !that.ownsLink(mouse.currentLink)) { var tmp = mouse.currentLink; mouse.currentLink = null; that.connectTo(tmp); } event.stopPropagation(); }; this.setHeaderLinkDomElement(headerLinkDomElement); return header; } Node.prototype.render = function() { var that = this; /** 기존 렌더링 삭제*/ var _rootDomElement = this.getRootDomElement(); $(_rootDomElement).remove(); $(_rootDomElement).empty(); /** 새로 렌더링 */ var subType = this.getSubType(); var rootDomElement = document.createElement('div'); this.setRootDomElement(rootDomElement); rootDomElement.classList.add('blpn-node'); var headerName = ``; switch (subType) { /** class */ case 1: { headerName = `CLASS`; var headerDomElement = this._renderHeaderLink(headerName); var buttonContainer = $(`
`); var methodButton = $(``); this.setState({ methodButton: methodButton }); buttonContainer.append(methodButton); headerDomElement.append(buttonContainer); $(methodButton).click(function() { that.addNodeElement(NODE_ELEMENT_ENUM.CLASS); that.addClassState(); var nodeElementList = that.getNodeElementList(); nodeElementList.forEach(( nodeElement, index) => { nodeElement.render(index); }); }); /** class node self variable */ var selfVariableDomeElement = $(`
Self Variable :
`); that.getState(`selfVariableList`).forEach( (selfVar, index) => { var selfVarNode = $(`
${index}
`); var input = $(``); var deleteButton = $(``); $(input).on("change keyup paste", function() { var newData = { name: $(this).val() } that.updateOneArrayIndexValue("selfVariableList", index, newData); }); $(deleteButton).on('click', function() { that.deleteOneArrayIndexValue("selfVariableList", index); that.render(); }); selfVarNode.append(input); selfVarNode.append(deleteButton); selfVariableDomeElement.append(selfVarNode); }); var selfVariablePlusButton = $(``); $(rootDomElement).append(selfVariableDomeElement); $(rootDomElement).append(selfVariablePlusButton); $(selfVariablePlusButton).click(function() { var newData = { name: '' } that.setState({ selfVariableList: [...that.getState(`selfVariableList`), newData] }); that.render(); }); this.renderNodeElementList(); break; } /** def */ case 2: { headerName = `DEF`; this._renderHeaderLink(headerName); this.addNodeElement(NODE_ELEMENT_ENUM.DEF); this.renderNodeElementList(); break; } /** if */ case 3: { headerName = `IF`; var headerDomElement = this._renderHeaderLink(headerName); var buttonContainer = $(`
`); var elifButton = $(``); var elseButton = $(``); this.setState({ elifButton , elseButton }); buttonContainer.append(elifButton); buttonContainer.append(elseButton); headerDomElement.append(buttonContainer); // this.addNodeElement(NODE_ELEMENT_ENUM.IF); this.renderNodeElementList(); this.bindClickElifBtnEvent(); this.bindClickElseBtnEvent(); break; } /** for */ case 4: { headerName = `FOR`; this._renderHeaderLink(headerName); this.addNodeElement(NODE_ELEMENT_ENUM.FOR); this.renderNodeElementList(); break; } /** while */ case 5: { headerName = `WHILE`; this._renderHeaderLink(headerName); this.addNodeElement(NODE_ELEMENT_ENUM.WHILE); this.renderNodeElementList(); break; } /** code block */ case 9: { headerName = `CODE BLOCK`; var headerDomElement = this._renderHeaderLink(headerName); var buttonContainer = $(`
`); var lineButton = $(``); // this.addNodeElement(NODE_ELEMENT_ENUM.CODE); this.setState({ lineButton }); buttonContainer.append(lineButton); headerDomElement.append(buttonContainer); this.renderNodeElementList(); this.bindClickLineBtnEvent(); break; } default: { break; } } /** 공통 dom 렌더링 */ /* top: -25px; */ var btnContainer = $(`
`); var deleteBtn = $(``); var updownToggleBtn = $(` `); btnContainer.append(deleteBtn); btnContainer.append(updownToggleBtn); $(rootDomElement).append(btnContainer); this.setDeleteBtnDomElement(deleteBtn); rootDomElement.style.top = `${this.getPointY()}` + 'px'; rootDomElement.style.left = `${this.getPointX()}` + 'px'; $(`.blpn-nodeEditor-left`).append(rootDomElement); // 이벤트 함수 바인딩 this.bindDragEvent(); this.bindClickNodeEvent(); this.bindMouseWheelEvent(); this.bindDeleteNodeEvent(); } Node.prototype.getNodeElementList = function() { return this.nodeElementList; } Node.prototype.addNodeElement = function(nodeElementSubType) { var nodeElementSubType = nodeElementSubType; var elementNum = this.getNodeElementList().length; var nodeElement = new NodeElement(this, nodeElementSubType, elementNum); this.nodeElementList.push(nodeElement); return nodeElement; } Node.prototype.deleteNodeElement = function(nodeElementUUID) { var nodeElementList = this.getNodeElementList(); var selectedIndex = -1; var is = this.nodeElementList.some((nodeElement, index) => { if (nodeElement.getUUID() === nodeElementUUID) { selectedIndex = index; return true; } else { return false; } }); if (is) { this.nodeElementList.splice(selectedIndex,1); } } Node.prototype.renderNodeElementList = function() { var nodeElementList = this.getNodeElementList(); nodeElementList.forEach(( nodeElement, index) => { nodeElement.render(index); }); } // ** link 연결하는 메소드 들*/ Node.prototype.getOutputPoint = function() { var rootDomElement = this.getRootDomElement(); var offset = rootDomElement.getElementsByClassName("blpn-node-headlink")[0].getBoundingClientRect(); return { x: offset.left, y: offset.top }; }; Node.prototype.getCurrPosition = function() { var rootDomElement = this.getRootDomElement(); var tmp = rootDomElement.firstElementChild; var offset = getFullOffset(tmp); return { x: offset.left, y: offset.top }; }; Node.prototype.createPath = function(a, b) { var diff = { x: b.x - a.x, y: b.y - a.y }; var pathStr = 'M' + a.x + ',' + a.y + ' '; pathStr += 'C'; pathStr += a.x + diff.x / 3 * 2 + ',' + a.y + ' '; pathStr += a.x + diff.x / 3 + ',' + b.y + ' '; pathStr += b.x + ',' + b.y; return pathStr; }; Node.prototype.ownsLink = function(link) { var nodeLinkList = this.getNodeLinkList(); for (var i = 0; i < nodeLinkList.length; i++) { if (nodeLinkList[i] == link) { return true; } } return false; }; /** FIXME: */ Node.prototype.addLink = function(name, nodeLinkSubType) { var rootDomElement = this.getRootDomElement(); // var link = new NodeLink(this, name, nodeLinkSubType); // this.nodeLinkList.push(link); // if ( name === "elif" && this.subType === 6) { // if (this.domElement.children.length < 5 ) { // this.domElement.appendChild(link.domElement); // } else { // var elseDomElement = this.domElement.children[this.domElement.children.length - 1]; // this.domElement.insertBefore(link.domElement, elseDomElement); // } // } else { // this.domElement.appendChild(link.domElement); // } return link; }; Node.prototype.getAttachedLinkList = function() { return this.attachedLinkList; } Node.prototype.getNodeLinkList = function() { var nodeElementList = this.getNodeElementList(); var nodeLinkList = []; nodeElementList.forEach(nodeElement => { var nodeLink = nodeElement.getNodeLink(); if (nodeLink) { nodeLinkList.push(nodeLink); } }); return nodeLinkList; } Node.prototype.getAttachingLinkList = function() { var attachingLinkList = []; var nodeLinkList = this.getNodeLinkList(); nodeLinkList.forEach(nodeLink => { if (nodeLink.getNextNode()) { attachingLinkList.push(nodeLink); } }); return attachingLinkList; } Node.prototype.detachLink = function(nodeLink) { var rootDomElement = this.getRootDomElement(); var index = -1; var attachedLinkList = this.getAttachedLinkList(); for ( var i = 0; i < attachedLinkList.length; i++) { if ( attachedLinkList[i] == nodeLink) { index = i; } }; if (index >= 0) { attachedLinkList[index].path.removeAttribute('d'); attachedLinkList[index].setNextNode(null); attachedLinkList.splice(index, 1); } if (attachedLinkList.length <= 0) { this.removeConnectedCssClass(); this.setIsConnectedToFalse(); } }; Node.prototype.detachAttachedLink = function(nodeLink) { var rootDomElement = this.getRootDomElement(); var index = -1; var attachedLinkList = this.getAttachedLinkList(); for ( var i = 0; i < attachedLinkList.length; i++) { if ( attachedLinkList[i] == nodeLink) { index = i; } }; if (index >= 0) { attachedLinkList[index].path.removeAttribute('d'); attachedLinkList[index].setNextNode(null); attachedLinkList.splice(index, 1); } if (attachedLinkList.length <= 0) { this.removeConnectedCssClass(); this.setIsConnectedToFalse(); } } /** * @param {object} link */ Node.prototype.detachAttachingLink = function(nodeLink) { var attachingLinkList = this.getAttachingLinkList(); var index = -1; for ( var i = 0; i < attachingLinkList.length; i++) { if ( attachingLinkList[i] == nodeLink) { index = i; } }; if (index >= 0) { attachingLinkList[index].path.removeAttribute('d'); attachingLinkList[index].nextNode = null; attachingLinkList.splice(index, 1); var nodeLinkRootDomElement = nodeLink.getRootDomElement(); $(nodeLinkRootDomElement).find(`.blpn-node-link`).removeClass('filled'); $(nodeLinkRootDomElement).find(`.blpn-node-link`).addClass('empty'); } } Node.prototype.updatePosition = function() { var outPoint = this.getOutputPoint(); var attachedLinkList = this.getAttachedLinkList(); for (var i = 0; i < attachedLinkList.length; i++) { var iPoint = attachedLinkList[i].getAttachPoint(); var pathStr = this.createPath(iPoint, outPoint); attachedLinkList[i].path.setAttributeNS(null, 'd', pathStr); } var attachingLinkList = this.getAttachingLinkList(); for (var i = 0; i < attachingLinkList.length; i++) { var iPoint = attachingLinkList[i].getAttachPoint(); var outPoint = attachingLinkList[i].getNextNode().getOutputPoint(); var pathStr = this.createPath(iPoint, outPoint); attachingLinkList[i].path.setAttributeNS(null, 'd', pathStr); } var nodeLinkList = this.getNodeLinkList(); for (var j = 0; j < nodeLinkList.length; j++) { if (nodeLinkList[j].getNextNode() != null) { var iP = nodeLinkList[j].getAttachPoint(); var oP = nodeLinkList[j].getNextNode().getOutputPoint(); var pStr = this.createPath(iP, oP); nodeLinkList[j].path.setAttributeNS(null, 'd', pStr); } } }; Node.prototype.connectTo = function(nodeLink) { nodeLink.setNextNode(this); this.setIsConnectedToTrue(); this.addConnectedCssClass(); var nodeLinkRootDomElement = nodeLink.getRootDomElement(); $(nodeLinkRootDomElement).find(`.blpn-node-link`).removeClass('empty'); $(nodeLinkRootDomElement).find(`.blpn-node-link`).addClass('filled'); this.attachedLinkList.push(nodeLink); var iPoint = nodeLink.getAttachPoint(); var oPoint = this.getOutputPoint(); var pathStr = this.createPath(iPoint, oPoint); nodeLink.path.setAttributeNS(null, 'd',pathStr); }; Node.prototype.moveTo = function(point) { var rootDomElement = this.getRootDomElement(); rootDomElement.style.top = point.y + 'px'; rootDomElement.style.left = point.x + 'px'; this.setPointX(point.x); this.setPointY(point.y); this.updatePosition(); }; Node.prototype.checkIsConnectedAndRender = function() { if( this.getAttachedLinkList().length !== 0 ) { this.setIsConnectedToTrue(); this.addConnectedCssClass(); } else { this.setIsConnectedToFalse(); this.removeConnectedCssClass(); } } Node.prototype.addConnectedCssClass = function() { var rootDomElement = this.getRootDomElement(); rootDomElement.classList.add('connected'); } Node.prototype.removeConnectedCssClass = function() { var rootDomElement = this.getRootDomElement(); rootDomElement.classList.remove('connected'); } Node.prototype.deleteNode = function() { var rootDomElement = this.getRootDomElement(); $(rootDomElement).remove(); $(rootDomElement).empty(); var attachedLinkList = this.getAttachedLinkList(); var attachingLinkList = this.getAttachingLinkList(); attachedLinkList.forEach( ( nodeLink, index ) => { var node = nodeLink.getNodeThis(); node.detachAttachingLink(nodeLink); }); attachingLinkList.forEach( ( nodeLink, index ) => { var node = nodeLink.getNextNode(); node.detachAttachedLink(nodeLink); }); var nodeUuid = this.getUUID(); var nodeContainerThis = this.getNodeContainerThis(); nodeContainerThis.deleteNode(nodeUuid); } // ** node state 관련 메소드들 */ Node.prototype.setState = function(newState) { this.state = changeOldToNewState(this.state, newState); this.consoleState(); } /** 모든 state 값을 가져오는 함수 */ Node.prototype.getStateAll = function() { return this.state; } /** 특정 state Name 값을 가져오는 함수 @param {string} stateKeyName */ Node.prototype.getState = function(stateKeyName) { return findStateValue(this.state, stateKeyName); } Node.prototype.consoleState = function() { // console.log(this.state); } Node.prototype.updateOneArrayIndexValue = function(stateParamName, index, updatedIndexValue) { var updatedParamOneArray = updateOneArrayIndexValueAndGetNewArray(this.getState(stateParamName), index, updatedIndexValue); this.setState({ [`${stateParamName}`]: updatedParamOneArray }); } Node.prototype.deleteOneArrayIndexValue = function(stateParamName, index) { var deletedParamOneArray = deleteOneArrayIndexValueAndGetNewArray(this.getState(stateParamName), index); this.setState({ [`${stateParamName}`]: deletedParamOneArray }); } /** type에 따른 state 생성 */ Node.prototype.addClassState = function(methodNameType) { var name = ''; if (methodNameType === 'init') { name = '_init_'; } var nodeThis = this; var newData = { name , inParamList: [] } nodeThis.setState({ methodList: [...nodeThis.getState('methodList'), newData] }); } Node.prototype.addIfState = function(methodNameType) { var nodeThis = this; var newData = { name: methodNameType , codeTokenList: [] } nodeThis.setState({ ifCodeLineList: [...nodeThis.getState('ifCodeLineList'), newData] }); } Node.prototype.addCodeBlockState = function(methodNameType) { var nodeThis = this; var newData = { codeTokenList: [] } nodeThis.setState({ codeBlockLineList: [...nodeThis.getState('codeBlockLineList'), newData ] }); } // ** node 이벤트 메소드 들*/ Node.prototype.bindDragEvent = function() { var that = this; var rootDomElement = this.getRootDomElement(); /** 드래그 범뮈 지정 */ // $(rootDomElement).draggable({ // cancel: '.blpn-node-input' // ,containment: '.blpn-nodeEditor-left', // }); var pos1 = 0; var pos2 = 0; var pos3 = 0; var pos4 = 0; var dragMouseDown = function (event) { event = event || window.event; // event.preventDefault(); // 시작지점 마우스좌표 얻기 pos3 = event.clientX; pos4 = event.clientY; document.onmouseup = closeDragElement; // 이동지점 마우스좌표 얻기 document.onmousemove = elementDrag; event.stopPropagation(); } var elementDrag = function(event) { event = event || window.event; // event.preventDefault(); // 이동지점 커서좌표 계산 pos1 = pos3 - event.clientX; pos2 = pos4 - event.clientY; pos3 = event.clientX; pos4 = event.clientY; // 요소의 새 위치 설정 var y = rootDomElement.offsetTop - pos2; var x = rootDomElement.offsetLeft - pos1; that.setPointX(x); that.setPointY(y); rootDomElement.style.top = `${y}` + 'px'; rootDomElement.style.left = `${x}` + 'px'; that.updatePosition(); event.stopPropagation(); } var closeDragElement = function() { /* 마우스버튼 풀렸을 때, 이동 멈춤 */ document.onmouseup = null; document.onmousemove = null; } // 이동 목적지 rootDomElement.onmousedown = dragMouseDown; } Node.prototype.bindMouseWheelEvent = function() { var that = this; var rootDomElement = this.getRootDomElement(); $(rootDomElement).bind('mousewheel', function (event) { var scrollNum = that.getScrollNum(); if ( scrollNum < 0.5) { that.setScrollNum(0.5); return; } if (event.originalEvent.wheelDelta / 120 > 0) { scrollNum += 0.05; that.setScrollNum(scrollNum); $(this).css('transform', 'scale(' + scrollNum + ')'); } else { scrollNum -= 0.05; that.setScrollNum(scrollNum); $(this).css('transform', 'scale(' + scrollNum + ')'); } that.updatePosition(); }); } Node.prototype.bindClickNodeEvent = function() { var rootDomElement = this.getRootDomElement(); $(rootDomElement).click(function() { }); } Node.prototype.bindDeleteNodeEvent = function() { var that = this; var nodeContainerThis = this.getNodeContainerThis(); var uuid = this.getUUID(); var rootDomElement = this.getRootDomElement(); this.deleteBtnDomElement.click(function() { that.deleteNode(); // nodeContainerThis.deleteNode(uuid); // $(rootDomElement).remove(); // $(rootDomElement).empty(); }); } /** NODE SUBTYPE : IF */ Node.prototype.bindClickElifBtnEvent = function() { var that = this; var elifButton = this.getState('elifButton'); elifButton.click( function() { that.addNodeElement(NODE_ELEMENT_ENUM.ELIF); that.addIfState('ELIF'); that.renderNodeElementList(); }); } /** NODE SUBTYPE : IF */ Node.prototype.bindClickElseBtnEvent = function() { var that = this; var elseButton = this.getState('elseButton'); elseButton.click( function() { var nodeElementList = that.getNodeElementList(); var is = nodeElementList.some(( nodeElement, index ) => { var nodeElementSubType = nodeElement.getSubType(); if (nodeElementSubType === NODE_ELEMENT_ENUM.ELSE) { return true; } else { return false; } }); if (is === true) { return; } else { that.addNodeElement(NODE_ELEMENT_ENUM.ELSE); that.addIfState('ELSE'); that.renderNodeElementList(); } }); } Node.prototype.bindClickLineBtnEvent = function() { var that = this; var lineButton = this.getState('lineButton'); lineButton.click( function() { that.addNodeElement(NODE_ELEMENT_ENUM.CODE); that.addCodeBlockState(); that.renderNodeElementList(); }); } var NodeContainer = function() { this.nodeList = []; } NodeContainer.prototype.pushNode = function(node) { node.setNodeContainerThis(this); this.nodeList.push(node); } NodeContainer.prototype.popNode = function() { this.nodeList.pop(); } NodeContainer.prototype.getNodeList = function() { return this.nodeList; } NodeContainer.prototype.makeUUID = function() { return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) ); } NodeContainer.prototype.deleteNode = function(nodeUUID) { var selectedIndex = -1; var is = this.nodeList.some((node, index) => { if (node.getUUID() === nodeUUID) { selectedIndex = index; return true; } else { return false; } }); if (is) { this.nodeList.splice(selectedIndex,1); // this.traverseNodeList(); } } NodeContainer.prototype.getCodeLineDomPoint = function() { var nodeList = this.getNodeList(); var nodeCodeLineDomPointList = []; nodeList.forEach(node => { var nodeElementList = node.getNodeElementList(); nodeElementList.forEach(nodeElement => { var nodeCodeLineDomElement = nodeElement.getNodeCodeLineDomElement(); if( nodeCodeLineDomElement ) { var nodeCodeLinePoint = nodeElement.getCodeLineDomPoint(); nodeCodeLineDomPointList.push(nodeCodeLinePoint); } }); }); return nodeCodeLineDomPointList; } NodeContainer.prototype.getNodeCodeLineDomElementList = function() { var nodeList = this.getNodeList(); var nodeCodeLineDomElementList = []; nodeList.forEach(node => { var nodeElementList = node.getNodeElementList(); nodeElementList.forEach(nodeElement => { var nodeCodeLineDomElement = nodeElement.getNodeCodeLineDomElement(); if( nodeCodeLineDomElement ) { nodeCodeLineDomElementList.push(nodeCodeLineDomElement); } }); }); return nodeCodeLineDomElementList; } NodeContainer.prototype.traverseNodeList = function() { var stack = []; this.nodeList.forEach((node, index) => { if ( node.getIsConnected() === false && node.getAttachingLinkList().length !== 0) { stack.push(node); } }); var current; var currType = ""; var iterationCount = 0; while (stack.length !== 0) { if ( iterationCount > 100 ) { console.log('NODE 무한 루프!!!'); break; } current = stack.pop(); if ( Array.isArray(current) ) { var j = current.length; while (j--) { var node = current[j].getNextNode(); if (node !== null) { stack.push(node); } } } else { console.log("NODE",current); var attachingLinkList = current.getAttachingLinkList(); if (attachingLinkList.length === 0) { continue; } stack.push(attachingLinkList); } iterationCount++; } } var CreateBlockNodeBtn = function(nodeContainerThis, subType) { this.nodeContainerThis = nodeContainerThis; this.mapSubTypeToName(subType); this.type = 'CREATE_NODE_BTN'; this.subType = subType; this.isStartDrag = false; this.rootDomElement; this.render(); this.bindDragEvent(); } CreateBlockNodeBtn.prototype.mapSubTypeToName = function(subType) { switch (subType) { case 1: { this.name = 'Class'; break; } case 2: { this.name = 'Def'; break; } case 3: { this.name = 'If'; break; } case 4: { this.name = 'For'; break; } case 5: { this.name = 'While'; break; } case 6: { this.name = 'Import'; break; } case 7: { this.name = 'Api'; break; } case 8: { this.name = 'Try'; break; } case 9: { this.name = 'Code'; break; } default: { break; } } } CreateBlockNodeBtn.prototype.getSubType = function() { return this.subType; } CreateBlockNodeBtn.prototype.getNodeContainerThis = function() { return this.nodeContainerThis; } CreateBlockNodeBtn.prototype.setNodeContainerThis = function(nodeContainerThis) { this.nodeContainerThis = nodeContainerThis; } CreateBlockNodeBtn.prototype.getRootDomElement = function() { return this.rootDomElement; } CreateBlockNodeBtn.prototype.setRootDomElement = function(rootDomElement) { this.rootDomElement = rootDomElement; } CreateBlockNodeBtn.prototype.getName = function() { return this.name; } CreateBlockNodeBtn.prototype.setName = function(name) { this.name = name; } CreateBlockNodeBtn.prototype.render = function() { var blockContainer = $(`.blpn-nodeEditor-tab-navigation-node-block-body`); var rootDomElement = $(`
${this.getName()}
`); this.setRootDomElement(rootDomElement); blockContainer.append(this.rootDomElement); } CreateBlockNodeBtn.prototype.bindDragEvent = function() { var nodeContainerThis = this.getNodeContainerThis(); var subType = this.getSubType(); this.getRootDomElement().draggable({ revert: 'invalid', revertDuration: 200, appendTo: '.blpn-nodeEditor-left', // containment: 'window', cursor: 'move', helper: 'clone', // scroll: false, cursorAt: { top: 17, left: 80 }, start: (event, ui) => { }, drag: (event, ui) => { $('.blpn-nodeEditor-left').droppable({ activeClass: 'ui-hover', hoverClass: 'ui-active', drop: ( _, __ ) => { if( this.type === 'CREATE_NODE_BTN') { var buttonX = event.clientX; var buttonY = event.clientY; var node = new Node(nodeContainerThis, subType, {x: buttonX, y: buttonY} ); nodeContainerThis.pushNode(node); } $('.blpn-nodeEditor-left').off(); } }); }, stop: () => { $('.blpn-nodeEditor-left').off(); } }); } var CreateOperatorNodeBtn = function(nodeContainerThis, subType) { this.nodeContainerThis = nodeContainerThis; this.mapSubTypeToName(subType); this.type = 'CREATE_NODE_OPERATOR_BTN'; this.subType = subType; this.isStartDrag = false; this.rootDomElement; this.render(); this.bindDragEvent(); } CreateOperatorNodeBtn.prototype.getSubType = function() { return this.subType; } CreateOperatorNodeBtn.prototype.getNodeContainerThis = function() { return this.nodeContainerThis; } CreateOperatorNodeBtn.prototype.setNodeContainerThis = function(nodeContainerThis) { this.nodeContainerThis = nodeContainerThis; } CreateOperatorNodeBtn.prototype.getRootDomElement = function() { return this.rootDomElement; } CreateOperatorNodeBtn.prototype.setRootDomElement = function(rootDomElement) { this.rootDomElement = rootDomElement; } CreateOperatorNodeBtn.prototype.getName = function() { return this.name; } CreateOperatorNodeBtn.prototype.setName = function(name) { this.name = name; } CreateOperatorNodeBtn.prototype.mapSubTypeToName = function(subType) { switch (subType) { case 1: { this.name = '+'; break; } case 2: { this.name = '-'; break; } case 3: { this.name = 'x'; break; } case 4: { this.name = '÷'; break; } case 5: { this.name = '='; break; } case 6: { this.name = '≠≠'; break; } case 7: { this.name = '=='; break; } case 8: { this.name = '<'; break; } case 9: { this.name = '≤'; break; } case 10: { this.name = '>'; break; } case 11: { this.name = '≥'; break; } case 12: { this.name = '+='; break; } case 13: { this.name = '-='; break; } case 14: { this.name = 'in'; break; } default: { this.name = ''; break; } } } CreateOperatorNodeBtn.prototype.render = function() { var blockContainer = $(`.blpn-nodeEditor-tab-navigation-node-operator-body`); var rootDomElement = $(`
${this.getName()}
`); this.setRootDomElement(rootDomElement); blockContainer.append(this.rootDomElement); } CreateOperatorNodeBtn.prototype.bindDragEvent = function() { var nodeContainerThis = this.getNodeContainerThis(); var subType = this.getSubType(); this.getRootDomElement().draggable({ revert: 'invalid', revertDuration: 200, appendTo: '.blpn-nodeEditor-left', // containment: 'window', cursor: 'move', helper: 'clone', // scroll: false, cursorAt: { top: 17, left: 80 }, start: (event, ui) => { }, drag: (event, ui) => { var nodeCodeLineDomElementList = nodeContainerThis.getCodeLineDomPoint(); nodeCodeLineDomElementList.forEach(nodeCodeLineDomElement => { var nodeCodeLineDomPointX = nodeCodeLineDomElement.x; var nodeCodeLineDomPointY = nodeCodeLineDomElement.y; var nodeCodeLineDomPointWidth = nodeCodeLineDomElement.width; var nodeCodeLineDomPointHeight = nodeCodeLineDomElement.height; var nodeCodeLineDom = nodeCodeLineDomElement.dom; var nodeElementThis = nodeCodeLineDomElement.nodeElementThis; /** 물체 충돌 로직 */ if(nodeCodeLineDomPointX < event.clientX && event.clientX < (nodeCodeLineDomPointX + nodeCodeLineDomPointWidth) && nodeCodeLineDomPointY < event.clientY && event.clientY < (nodeCodeLineDomPointY + nodeCodeLineDomPointHeight) ) { $(nodeCodeLineDom).addClass('blpn-nodeCodeLine-selected'); // $(nodeCodeLineDom).find('.blpn-node-codeline-span').addClass('blpn-node-codeline-selected-span'); } else { $(nodeCodeLineDom).removeClass('blpn-nodeCodeLine-selected'); // $(nodeCodeLineDom).find('.blpn-node-codeline-span').removeClass('blpn-node-codeline-selected-span'); } $('.blpn-nodeEditor-left').droppable({ activeClass: 'ui-hover', hoverClass: 'ui-active', drop: ( _, __ ) => { } }); $(nodeCodeLineDom).droppable({ drop: ( event, ui ) => { $(nodeCodeLineDom).removeClass("blpn-nodeCodeLine-selected"); // $(nodeCodeLineDom).find('.blpn-node-codeline-span').removeClass('blpn-node-codeline-selected-span'); nodeElementThis.makeNodeCodeLineDomElement(subType); // nodeCodeLine.setSubType( this.getSubType() ); // /** 헤드 코드 라인 */ // if ( nodeCodeLine.getType() === "HEAD_NODE_CODELINE" ) { // nodeCodeLine.render(); // return; // } // /** 일반 코드 라인 */ // var nodeLink = nodeCodeLine.getNodeLink(); // nodeLink.renderNodeCodeLineList(); } }); }); }, stop: () => { } }); } var nodeContainer = new NodeContainer(); var createBlockNodeBtnArray = Object.values(NODE_BLOCK_BTN_ENUM); createBlockNodeBtnArray.forEach(enumData => { new CreateBlockNodeBtn(nodeContainer, enumData); }); var operatorNodeBtnList = Object.values(NODE_OPERATOR_ENUM); operatorNodeBtnList.forEach(enumData => { new CreateOperatorNodeBtn(nodeContainer, enumData); }); var node1 = new Node(nodeContainer, NODE_BLOCK_ENUM.IF, {x:100,y:300}); nodeContainer.pushNode(node1);