From 00e0c8ff0ee67d425eac6f616f13f11ec6a91e6f Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Tue, 11 Apr 2017 16:55:51 -0600 Subject: [PATCH 01/48] rough beginnings of reworked block code --- index.html | 8 +- resources/js/blockFilter.js | 63 ++--- resources/js/blocks.js | 461 +++++++++++++++++++++++------------- 3 files changed, 332 insertions(+), 200 deletions(-) diff --git a/index.html b/index.html index 68459f0..52e2157 100644 --- a/index.html +++ b/index.html @@ -192,14 +192,8 @@
-
diff --git a/resources/js/blockFilter.js b/resources/js/blockFilter.js index b9daef4..505530d 100644 --- a/resources/js/blockFilter.js +++ b/resources/js/blockFilter.js @@ -34,49 +34,50 @@ var filter = { blockArea.innerHTML = ''; for(x = 0; x < blocksToDisplay.length; x++) { var block = filter.blocks[blocksToDisplay[x]]; - var blockString; + var newBlock; if (block.type == 'wrapper') { if (!block.ftype || block.ftype == 'html') { - blockString = [ - '' - ].join(''); + newBlock = new Block(block.type, block.name, { + hasAttrs: true, + hasQuickText: true, + scriptInputContent: null, + inPalette: true + }); } else { - blockString = [ - '' - ].join(''); + newBlock = new Block(block.type, block.name, { + hasAttrs: false, + hasQuickText: false, + scriptInputContent: ' ', + inPalette: true + }); } } else { if (block.name != 'text') { if (!block.ftype || block.ftype == 'html') { - blockString = [ - '
  • ', - block.name, - "", - '
  • ' - ].join(''); + newBlock = new Block(block.type, block.name, { + hasAttrs: true, + hasQuickText: false, + scriptInputContent: null, + inPalette: true + }); } else { - blockString = [ - '
  • ', - block.name, - ' : ', - '
  • ' - ].join(''); + newBlock = new Block(block.type, block.name, { + hasAttrs: true, + hasQuickText: false, + scriptInputContent: '', + inPalette: true + });; } } else { - blockString = '
  • ' + DEFAULT_TEXT + '
  • '; + newBlock = new Block('stack', 'text', { + hasAttrs: false, + hasQuickText: false, + scriptInputContent: DEFAULT_TEXT, + inPalette: true + }); } } - blockArea.innerHTML += blockString; + blockArea.appendChild(newBlock.elem); } } else { blockArea.innerHTML = "No blocks were found."; diff --git a/resources/js/blocks.js b/resources/js/blocks.js index fbdc7d1..d00ce06 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -2,6 +2,230 @@ var selected = null, // Object of the element to be moved x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer x_elem = 0, y_elem = 0, // Stores top, left values (edge) of the element DEFAULT_TEXT = 'breadfish'; +var blocksDatabase = {}; // all blocks by ID. Not an array in case we decide to use md5's or something later +var allBlocks = []; +var blocksCount = 0; // not a real bumber of blocks. This value should never be + // decrememnted because it's used to generate a blocks' unique ID + +// a more generic abstraction of a block +// it can have children, so it can be a script +function Draggy() { + this.x = 0; + this.y = 0; + this.type = 'draggy'; + this.id = blocksCount++; + blocksDatabase[this.id] = this; + allBlocks.push(this); + this.parent = null; + this.children = []; + this.inPalette = false; + + this.elem = document.createElement('ul'); + this.elem.classList.add('draggy'); + this.content = this.elem; + + var block = this; + this.getIndex = function() { + if(block.parent) { + return block.parent.children.indexOf(block); + } else { + return null; + } + }; + this.insertChild = function(child, index) { + if(index == -1 || index > block.children.length - 1) { + block.children.push(child); + block.content.appendChild(child.elem); + } else { + block.content.insertBefore(child.elem, block.children[index].elem); + } + child.parent = block; + }; + this.removeFromParent = function() { + if(!block.parent) return; + block.parent.children.splice(block.parent.children.indexOf(block), 1); + block.parent = null; + }; + this.deleteDraggy = function() { + block.removeFromParent(); + block.elem.parentElement.removeChild(block.elem); + blocksDatabase[block.id] = null; + allBlocks[allBlocks.indexOf(block)] = null; + }; + this.getClosestBlock = function() { + var el = null, + elOffset, + x = getOffset(block.elem).left, + y = getOffset(block.elem).top, + distance, + dx, dy, + minDistance; + blocks: for(let oblock of allBlocks) { + + if (!oblock + || oblock.type == 'draggy' + || oblock.unmoveable) continue blocks; + + // check for descendancy + let pblock = block; + while(pblock) { + if (pblock == oblock + || pblock.children.indexOf(oblock) != -1) continue blocks; + pblock = pblock.parent; + } + pblock = oblock; + while(pblock) { + if (pblock == block + || pblock.children.indexOf(block) != -1) continue blocks; + pblock = pblock.parent; + } + + elOffset = getOffset(oblock.elem); + // move point inside c-blocks to the right; + if(oblock.type == 'nullWrapperContent') elOffset.left += oblock.content.style.paddingLeft; + + //let's only test the bottom-left corner + dx = elOffset.left - x; + dy = elOffset.bottom - y; + distance = Math.sqrt((dx*dx) + (dy*dy)); //dist to each corner + if (distance <= MIN_DISTANCE && (minDistance === undefined || distance < minDistance)) { + minDistance = distance; + el = oblock; + } + } + return el; + }; +} +/* +opts = { + bool hasAttrs, + bool hasQuickText, + string|null scriptInputContent, + bool inPalette = true, + bool unmoveable +} +*/ +function Block(type, name, opts) { + if(!opts) opts = {}; + Draggy.apply(this); + this.type = type; + this.name = name; + this.inPalette = (opts.inPalette !== undefined) ? opts.inPalette : true; + this.unmoveable = opts.unmoveable || false; + var block = this; + if(type == 'wrapper') { + this.elem = document.createElement('ul'); + this.elem.classList.add('c-wrapper'); + + var header = document.createElement('li'); + header.classList.add('c-header'); + this.elem.appendChild(header); + + // add a blank draggy inside wrapper + var nullWrapperContent = new Draggy(); + nullWrapperContent.type = 'nullWrapperContent'; + this.insertChild(nullWrapperContent, -1); + nullWrapperContent.elem = nullWrapperContent.content = header; + + this.content = document.createElement('ul'); + this.content.classList.add('c-content'); + this.elem.appendChild(this.content); + + var footer = document.createElement('ul'); + footer.classList.add('c-footer'); + this.elem.appendChild(footer); + + if(opts.hasQuickText) { + this.quickText = document.createElement('li'); + this.quickText.classList.add('c-quicktext'); + this.quickText.appendChild(document.createTextNode('Aa')) + footer.appendChild(this.quickText); + + this.quickText.addEventListener('click', function(ev) { + var newBlock = new Block('stack', 'text', { + hasAttrs: false, + hasQuickText: false, + scriptInputContent: DEFAULT_TEXT, + inPalette: false + }); + block.insertChild(newBlock, -1); + setFrameContent(); + }); + } + } else if(type == 'stack') { + this.elem = document.createElement('li'); + this.elem.classList.add('stack'); + var header = this.elem; + } + this.elem.classList.add('e-' + name); + this.elem.setAttribute('data-id', this.id); + + header.appendChild(document.createTextNode(name + ' ')); + + if(opts.hasAttrs) { + header.innerHTML += ``; + } + + if(opts.scriptInputContent !== null) { + this.scriptInput = document.createElement('span'); + this.scriptInput.classList.add('script-input'); + this.scriptInput.setAttribute('contenteditable', 'true') + this.scriptInput.appendChild(document.createTextNode(opts.scriptInputContent)); + header.appendChild(this.scriptInput); + } + + this.clone = function(_inPalette) { + return new Block(type, name, { + hasAttrs: opts.hasAttrs, + hasQuickText: opts.hasQuickText, + scriptInputContent: opts.scriptInputContent, + inPalette: _inPalette + }); + }; + if(!opts.unmoveable) { + let testBlockContents = function(elem) { + var BLOCK_CONTENTS = [ + 'script-input', + 'c-quicktext', + 'attr-controls', + 'attr-holder' + ]; + var loops = 4; + while(elem && loops--) { + for(let content of BLOCK_CONTENTS) { + if(elem.classList.contains(content)) return true; + } + elem = elem.parentNode; + } + return false; + } + + this.elem.addEventListener('mousedown', function(ev) { + if (ev.which == 3 + || testBlockContents(ev.target)) return; + ev.stopPropagation(); + if(block.inPalette) { + _palette_drag_init(block, ev); + } else { + _drag_init(block, ev); + trashCan = document.getElementById('trashCan'); + trashCan.classList.add('showing'); + } + setZebra(); + setFrameContent(); + SCRIPT_MENU.style.display = 'none'; + RIGHT_CLICKED_SCRIPT = undefined; + }); + + this.elem.addEventListener('mouseup', function(ev) { + trashCan = document.getElementById('trashCan'); + trashCan.classList.remove('showing'); + }); + } + +} +Block.prototype = Object.create(Draggy.prototype); +Block.prototype.constructor = Block.constructor; function isDescendant(parent, child) { var node = child.parentNode; @@ -14,28 +238,11 @@ function isDescendant(parent, child) { return false; } -function closestElem(elem, offset, initial) { //elem is nodelist, offset is own offset - var el = null, - elOffset, - x = offset.x, //x is my own offset - y = offset.y, //y is my own offset - distance, - dx, dy, - minDistance; - elem.each( function(item) { - if(item == selected) {return false;} // I added this -NN - elOffset = getOffset(item); //returns object with offsets - - //let's only test the bottom-left corner - dx = elOffset.left - x; - dy = elOffset.bottom - y; - distance = Math.sqrt((dx*dx) + (dy*dy)); //dist to each corner - if (distance <= MIN_DISTANCE && initial != item && !isDescendant(initial, item) && (minDistance === undefined || distance < minDistance)) { - minDistance = distance; - el = item; - } - }); - return el; +function removeDropArea() { + let dropArea; + while(dropArea = document.querySelector('.drop-area')) { + dropArea.classList.remove('drop-area'); + }; } function getOffset( elem ) { @@ -88,47 +295,55 @@ function parentHasClass(element, className) { } // Will be called when user starts dragging an element -function _drag_init(elem, ev) { +function _drag_init(block, ev) { + var elem = block.elem; var relativeX = ev.pageX - getOffset(elem).left; var relativeY = ev.pageY - getOffset(elem).top; // Store the object of the element which needs to be moved - var wrapper = document.createElement("ul"); - wrapper.classList.add('draggy'); - SCRIPTING_AREA.insertBefore(wrapper, SCRIPTING_AREA.firstChild); - selected = elem; + var draggy = new Draggy() + SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); var curX = ev.pageX - getOffset(SCRIPTING_AREA).left, curY = ev.pageY - getOffset(SCRIPTING_AREA).top; - var childs = Array.prototype.slice.call(elem.parentElement.children); - for(var i = childs.indexOf(elem); i < childs.length; i++) { - childs[i].removeAttribute('style'); - wrapper.appendChild(childs[i]); + var parent = block.parent; + var kids = parent.children.slice(); + for(let i = block.getIndex(), child; child = kids[i]; i++) { + child.removeFromParent(); + draggy.insertChild(child, -1); + child.elem.removeAttribute('style'); } - wrapper.style.left = curX - relativeX + 'px'; - wrapper.style.top = curY - relativeY + 'px'; - selected = wrapper; - x_elem = x_pos - selected.offsetLeft; - y_elem = y_pos - selected.offsetTop; + if(parent.children.length == 0 && parent.type == 'draggy') parent.deleteDraggy(); + draggy.x = curX - relativeX; + draggy.y = curY - relativeY; + draggy.elem.style.left = draggy.x + 'px'; + draggy.elem.style.top = draggy.y + 'px'; + selected = draggy; + x_elem = x_pos - selected.elem.offsetLeft; + y_elem = y_pos - selected.elem.offsetTop; } -function _palette_drag_init(elem, ev) { +function _palette_drag_init(block, ev) { + var elem = block.elem; var relativeX = ev.clientY - getOffset(elem).left - SCRIPTING_AREA.scrollLeft; var relativeY = ev.clientY - getOffset(elem).top + BLOCK_PALETTE.scrollTop - SCRIPTING_AREA.scrollTop; // Clone element - var newElem = elem.cloneNode(true); + var newBlock = block.clone(false); + var newElem = newBlock.elem; newElem.classList.remove('paletteBlock'); // Store the object of the element which needs to be moved - var wrapper = document.createElement("ul"); - wrapper.classList.add('draggy'); - SCRIPTING_AREA.insertBefore(wrapper, SCRIPTING_AREA.firstChild); + var draggy = new Draggy(); + SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); selected = newElem; + selectedBlock = newBlock; var curX = ev.clientY - getOffset(SCRIPTING_AREA).left, curY = ev.clientY - getOffset(SCRIPTING_AREA).top; - wrapper.appendChild(newElem); - wrapper.style.left = curX - relativeX + 'px'; - wrapper.style.top = curY - relativeY + 'px'; - selected = wrapper; - x_elem = x_pos - selected.offsetLeft; - y_elem = y_pos - selected.offsetTop; + draggy.insertChild(selectedBlock, -1); + draggy.x = curX - relativeX; + draggy.y = curY - relativeY; + draggy.elem.style.left = draggy.x + 'px'; + draggy.elem.style.top = draggy.y + 'px'; + selected = draggy; + x_elem = x_pos - selected.elem.offsetLeft; + y_elem = y_pos - selected.elem.offsetTop; } // Will be called when user dragging an element @@ -137,74 +352,42 @@ function _move_elem(e) { x_pos = document.all ? window.event.clientX : e.pageX + SCRIPTING_AREA.scrollLeft; y_pos = document.all ? window.event.clientY : e.pageY + SCRIPTING_AREA.scrollTop; var SNAP_CLASSES = currentFile.split('.').pop() == 'css' ? CSS_SNAP_CLASSES : HTML_SNAP_CLASSES; + removeDropArea(); if (selected !== null) { - $(SNAP_CLASSES).each(function(item) { - if (item.classList.contains('drop-area')) { - item.classList.remove('drop-area'); - } - }); - var el = closestElem( - $(SNAP_CLASSES), - { - y: getOffset(selected).top, - x: getOffset(selected).left - }, - selected - ) - if ((el !== null && !el.classList.contains('paletteBlock') && !parentHasClass(el, 'paletteBlock') && !parentHasClass(el, 'blockArea'))) { - el.classList.add('drop-area'); + var el = selected.getClosestBlock(); + if (el !== null && !el.inPalette && (!el.parent || (el.parent && !el.parent.inPalette))) { + el.elem.classList.add('drop-area'); } - selected.style.left = (x_pos - x_elem) + 'px'; - selected.style.top = (y_pos - y_elem) + 'px'; + selected.elem.style.left = (x_pos - x_elem) + 'px'; + selected.elem.style.top = (y_pos - y_elem) + 'px'; } } // Destroy the object when we are done function _destroy(ev) { - var SNAP_CLASSES = currentFile.split('.').pop() == 'css' ? CSS_SNAP_CLASSES : HTML_SNAP_CLASSES; - $(SNAP_CLASSES).each(function(item) { - if (item.classList.contains('drop-area')) { - item.classList.remove('drop-area'); - } - }); - var topEl = null; - if (selected !== null) { - topEl = closestElem( - $(SNAP_CLASSES), - { - y: getOffset(selected).top, - x: getOffset(selected).left - }, - selected - ); - } - if (topEl !== null && !topEl.classList.contains('paletteBlock') && !parentHasClass(topEl, 'paletteBlock') && !parentHasClass(topEl, 'blockArea')) { - for(var i = selected.children.length - 1; i >= 0; i--) { - // for one reason for/in desn't work here; - var elem = selected.children[i]; - if (topEl.classList.contains('stack')) { - elem.removeAttribute('style'); - topEl.parentNode.insertBefore(elem, topEl.nextElementSibling); - } else if (topEl.classList.contains('c-header')) { - elem.removeAttribute('style'); - topEl.nextElementSibling.insertBefore(elem, topEl.nextElementSibling.firstElementChild); - } else if (topEl.classList.contains('c-footer')) { - elem.removeAttribute('style'); - topEl.parentNode.parentNode.insertBefore(elem, topEl.parentNode.nextElementSibling); - } else if (topEl.classList.contains('hat') && currentFile.split('.').pop() == 'css') { - elem.removeAttribute('style'); - topEl.parentNode.insertBefore(elem, topEl.nextElementSibling); + removeDropArea(); + + if (selected == null) return; + var topEl = selected.getClosestBlock(); + if (topEl !== null && !topEl.inPalette && !parentHasClass(topEl.elem, 'blockArea')) { + var kids = selected.children.slice(); + for(let child of kids) { + child.removeFromParent(); + child.elem.removeAttribute('style'); + if(topEl.type == 'nullWrapperContent') { + topEl.parent.insertChild(child, -1); + } else if(topEl.type == 'stack' + || topEl.type == 'wrapper') { + topEl.parent.insertChild(child, topEl.getIndex() + 1); } } - selected.parentNode.removeChild(selected); + } else { - if (selected !== null) { - if (getOffset(selected).top - getOffset(SCRIPTING_AREA).top < 0) { - selected.style.top = 0; - } - if (getOffset(selected).left - getOffset(SCRIPTING_AREA).left < 0) { - selected.style.left = 0; - } + if (getOffset(selected.elem).top - getOffset(SCRIPTING_AREA).top < 0) { + selected.elem.style.top = 0; + } + if (getOffset(selected.elem).left - getOffset(SCRIPTING_AREA).left < 0) { + selected.elem.style.left = 0; } } selected = null; @@ -218,7 +401,7 @@ function _delete(ev) { } }); if (selected) { // TODO: make this not ugly - selected.parentNode.removeChild(selected); + selected.elem.parentNode.removeChild(selected.elem); } selected = null; } @@ -268,56 +451,17 @@ var C_PALETTE_ELEMENTS = ([ return '.blockArea ' + item; }).join(', '); -BLOCK_PALETTE.addEventListener('mousedown', function(ev) { - if (ev.target.className =='script-input') { - ev.stopPropagation(); - return; - } - if (ev.target.matches(DRAGGABLE_PALETTE_ELEMENTS)) { - _palette_drag_init(ev.target, ev); - ev.stopPropagation(); - setZebra(); - } else if (ev.target.matches(C_PALETTE_ELEMENTS)) { - _palette_drag_init(ev.target.parentElement, ev); - ev.stopPropagation(); - setZebra(); - } - setFrameContent(); -}); - -SCRIPTING_AREA.addEventListener('mousedown', function(ev) { - if (ev.which != 3) { // shouldn't do anything on right click - if (ev.target.className =='script-input') { - ev.stopPropagation(); - return; - } - if (ev.target.matches(DRAGGABLE_ELEMENTS)) { - _drag_init(ev.target, ev); - ev.stopPropagation(); - setZebra(); - } else if (ev.target.matches(C_ELEMENTS)) { - if (!ev.target.parentNode.classList.contains('e-body')) { - _drag_init(ev.target.parentElement, ev); - ev.stopPropagation(); - setZebra(); - } - } - if (ev.target.matches(C_ELEMENTS) || ev.target.matches(DRAGGABLE_ELEMENTS)) { - trashCan = document.getElementById('trashCan'); - trashCan.classList.add('showing'); - } - setFrameContent(); - SCRIPT_MENU.style.display = 'none'; - RIGHT_CLICKED_SCRIPT = undefined; - } -}); -SCRIPTING_AREA.addEventListener('mouseup', function(ev) { - if (ev.target.matches(C_ELEMENTS) || ev.target.matches(DRAGGABLE_ELEMENTS)) { - trashCan = document.getElementById('trashCan'); - trashCan.classList.remove('showing'); - } -}); +var bodyScript = new Draggy(); +bodyScript.elem = bodyScript.content = document.querySelector('#bodyScript'); +var body = newBlock = new Block('wrapper', 'body', { + hasAttrs: true, + hasQuickText: true, + scriptInputContent: null, + inPalette: false, + unmoveable: true + }); +bodyScript.insertChild(body, -1); SCRIPTING_AREA.addEventListener('contextmenu', function(ev) { if (ev.target.matches(DRAGGABLE_ELEMENTS) || ev.target.parentNode.matches(DRAGGABLE_ELEMENTS)) { @@ -358,13 +502,6 @@ SCRIPTING_AREA.addEventListener('input', function(ev) { } }); -SCRIPTING_AREA.addEventListener('click', function(ev) { - if (ev.target.matches('.c-quicktext')) { - ev.target.parentNode.parentNode.querySelector('.c-content').innerHTML = '
  • ' + DEFAULT_TEXT + '
  • '; - setFrameContent(); - } -}); - var SCRIPT_MENU = document.querySelector('.context-menu.scripts'); var RIGHT_CLICKED_SCRIPT = undefined; From b97017c2a2808865610833c5609e74f15fa6d1c0 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 00:00:15 -0600 Subject: [PATCH 02/48] add Attr constructor; transition from getOffset() to block.left() (etc.); rewrite json2html --- index.html | 2 +- resources/js/block2json.js | 65 ++++++----------- resources/js/blockAttributes.js | 125 ++++++++++++++++++++------------ resources/js/blockFilter.js | 2 +- resources/js/blocks.js | 97 ++++++++++++++++++------- resources/js/fileManagement.js | 4 +- 6 files changed, 175 insertions(+), 120 deletions(-) diff --git a/index.html b/index.html index 52e2157..52ae5da 100644 --- a/index.html +++ b/index.html @@ -201,8 +201,8 @@ - + diff --git a/resources/js/block2json.js b/resources/js/block2json.js index f9b97d8..b357455 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -171,6 +171,24 @@ function getCSSAttributes(children) { return attributes; } +function blockTreeToHTML(block) { + if(block.type !== 'stack' && block.type !== 'wrapper') { + return null; + } else if(block.name == 'text') { + return document.createTextNode(block.scriptInput.textContent); + } else { + var element = document.createElement(block.name); + for(let attr of block.attrs) { + element.setAttribute(attr.getName(), attr.getValue()); + } + for(let child of block.children) { + let parsedChild = blockTreeToHTML(child); + if(parsedChild) element.appendChild(parsedChild); + } + return element; + } +} + function setFrameContent(ext) { ext = ext || currentFile.split('.').pop(); var script = document.getElementsByClassName('script')[0].cloneNode(true); //should only be one... @@ -194,51 +212,12 @@ function setFrameContent(ext) { } fileData[currentFile] = jsonFormat; } else if (ext == 'html') { - - var jsonFormat = { - tag: 'body', - attr: {}, - child: [], - }; - var blocks = []; - - for (var i = 0; i < directChildren.length; i++) { - if (includesArrItem(directChildren[i].className, stackElements)) { //things like imgs - var elType = getElType(directChildren[i]); - if (elType == 'text') { - elType = ''; - } - if (elType == 'CSS') { - console.log(getSingleAttrs(directChildren[i])); - } else { - blocks.push({ - tag: elType, - attr: elType ? getSingleAttrs(directChildren[i]) : {}, - text: encodeEntities(getInlineText(directChildren[i])) - }); - } - } else if (includesArrItem(directChildren[i].className, wrapperElements)) { // things that can nest things - ie most elements - var elType = getElType(directChildren[i]); - blocks.push({ - tag: elType, - child: traverseTree(directChildren[i]), - }); - } - } - - if (blocks[0]) { - jsonFormat = blocks[0]; - } - - fileData[currentFile] = jsonFormat; - - var parsedHtml = json2html(jsonFormat); + var parsedHtml = blockTreeToHTML(BODY); var previewWindow = previewElement; previewWindow = (previewWindow.contentWindow) ? previewWindow.contentWindow : (previewWindow.contentDocument.document) ? previewWindow.contentDocument.document : previewWindow.contentDocument; - previewWindow.document.open(); - previewWindow.document.write(parsedHtml); - previewWindow.document.close(); + while(previewWindow.document.firstChild) previewWindow.document.removeChild(previewWindow.document.firstChild); + previewWindow.document.appendChild(parsedHtml); } else { throw 'this should never be thrown though'; } @@ -277,4 +256,4 @@ setFrameContent(); // value: 'execute' // } // }] -// }; \ No newline at end of file +// }; diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index aeee239..6d5775a 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -4,52 +4,85 @@ var ATTRIBUTE_RESULTS = document.getElementById('attributeResults'); var CLICKED_ATTR; -SCRIPTING_AREA.addEventListener('click', function(ev) { - var el = ev.target; - - // Check if click was on rightward arrow - if (ev.target.classList.contains('add-attr')) { - - // If so, add an attribute block - var newAttrString = [ - '', - ' ', - '=', - '', - '' - ].join(''); - var newAttr = stringToHtml(newAttrString); - el.parentNode.parentNode.insertBefore(newAttr, el.parentNode); - - // Check if click was on the leftward arrow - } else if (ev.target.classList.contains('remove-attr')) { - - // If so, remove the last attribute block - var prev = el.parentNode.previousElementSibling; - if (prev) { - prev.parentNode.removeChild(prev); - } - } - - // Check if click was on the first input of an attribute block - if (ev.target.classList.contains('attr-dropdown')) { - - // If so, display the searchable dropdown used for attributes +// both optional +function Attr(attrName, value) { + this.elem = document.createElement('span'); + this.elem.classList.add('attr-holder'); + + if(attrName === undefined) attrName = '\u00A0'; + this.dropdown = document.createElement('span'); + this.dropdown.classList.add('attr-dropdown') + this.dropdown.appendChild(document.createTextNode(attrName)); + this.elem.appendChild(this.dropdown); + + this.elem.appendChild(document.createTextNode('=')); + + if(value === undefined) value = ''; + this.input = document.createElement('span'); + this.input.classList.add('attr-dropdown') + this.input.setAttribute('contenteditable', 'true'); + this.input.appendChild(document.createTextNode(value)); + this.elem.appendChild(this.input); + + var attr = this; + this.dropdown.addEventListener('click', function(e) { ATTRIBUTE_MENU.classList.remove('hidden'); - - // Position dropdown based on input location - ATTRIBUTE_MENU.style.top = getOffset(el).top + el.offsetHeight + 'px'; - ATTRIBUTE_MENU.style.left = getOffset(el).left + 'px'; - CLICKED_ATTR = ev.target; - - ATTRIBUTE_SEARCH.focus(); // Give focus to search input so user can type without clicking - } else { - - // If click was not in one of the previously specified places, hide the dropdown (won't do anything if it was already hidden) - ATTRIBUTE_MENU.classList.add('hidden'); - CLICKED_ATTR = null; + ATTRIBUTE_MENU.style.top = attr.top() + attr.elem.offsetHeight + 'px'; + ATTRIBUTE_MENU.style.left = attr.left() + 'px'; + CLICKED_ATTR = attr; + + ATTRIBUTE_SEARCH.focus(); + setTimeout(function() { + document.body.addEventListener('click', function dropdown_blur(e2) { + ATTRIBUTE_MENU.classList.add('hidden'); + CLICKED_ATTR = null; + document.body.removeEventListener('click', dropdown_blur); + }); + }, 0); + }); + + this.getName = function() { + return attr.dropdown.textContent; } -}); + + this.getValue = function() { + return attr.input.textContent; + } + + this.left = function() { + var elem = attr.elem; + var offsetLeft = 0; + do { + if ( !isNaN( elem.offsetLeft ) ) + { + offsetLeft += elem.offsetLeft; + } + } while( elem = elem.offsetParent ); + return offsetLeft; + } + + this.top = function() { + var elem = attr.elem; + var offsetTop = 0; + do { + if ( !isNaN( elem.offsetTop ) ) + { + offsetTop += elem.offsetTop; + } + } while( elem = elem.offsetParent ); + return offsetTop; + } +} + +function add_attr(block) { + var attr = new Attr(); + block.header.insertBefore(attr.elem, block.attrControls); + block.attrs.push(attr); +} +function remove_attr(block) { + var attrs = block.attr.pop(); + block.header.removeChild(attr.elem); +} // uses array called attrNames... @@ -72,7 +105,7 @@ ATTRIBUTE_SEARCH.addEventListener('paste', attrSearch); ATTRIBUTE_RESULTS.addEventListener('click', function(ev) { var attr = ev.target.textContent; - CLICKED_ATTR.textContent = attr; + CLICKED_ATTR.dropdown.textContent = attr; }); // initialize the stuff in the menu @@ -80,4 +113,4 @@ var attrString = ''; for (var i = 0; i < attrNames.length; i++) { attrString += '
  • ' + attrNames[i] + '
  • '; } -ATTRIBUTE_RESULTS.innerHTML = attrString; \ No newline at end of file +ATTRIBUTE_RESULTS.innerHTML = attrString; diff --git a/resources/js/blockFilter.js b/resources/js/blockFilter.js index 505530d..aa475db 100644 --- a/resources/js/blockFilter.js +++ b/resources/js/blockFilter.js @@ -47,7 +47,7 @@ var filter = { newBlock = new Block(block.type, block.name, { hasAttrs: false, hasQuickText: false, - scriptInputContent: ' ', + scriptInputContent: '\u00A0', inPalette: true }); } diff --git a/resources/js/blocks.js b/resources/js/blocks.js index d00ce06..0ce6eb9 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -10,14 +10,13 @@ var blocksCount = 0; // not a real bumber of blocks. This value should never be // a more generic abstraction of a block // it can have children, so it can be a script function Draggy() { - this.x = 0; - this.y = 0; this.type = 'draggy'; this.id = blocksCount++; blocksDatabase[this.id] = this; allBlocks.push(this); this.parent = null; this.children = []; + this.attrs = []; this.inPalette = false; this.elem = document.createElement('ul'); @@ -54,9 +53,6 @@ function Draggy() { }; this.getClosestBlock = function() { var el = null, - elOffset, - x = getOffset(block.elem).left, - y = getOffset(block.elem).top, distance, dx, dy, minDistance; @@ -80,13 +76,15 @@ function Draggy() { pblock = pblock.parent; } - elOffset = getOffset(oblock.elem); - // move point inside c-blocks to the right; - if(oblock.type == 'nullWrapperContent') elOffset.left += oblock.content.style.paddingLeft; - //let's only test the bottom-left corner - dx = elOffset.left - x; - dy = elOffset.bottom - y; + dx = oblock.left() - block.left(); + dy = oblock.bottom() - block.top(); + + // move point inside c-blocks to the right + if(oblock.type == 'nullWrapperContent') { + dx += oblock.content.style.paddingLeft; + } + distance = Math.sqrt((dx*dx) + (dy*dy)); //dist to each corner if (distance <= MIN_DISTANCE && (minDistance === undefined || distance < minDistance)) { minDistance = distance; @@ -95,6 +93,38 @@ function Draggy() { } return el; }; + + this.left = function() { + var elem = block.elem; + var offsetLeft = 0; + do { + if ( !isNaN( elem.offsetLeft ) ) + { + offsetLeft += elem.offsetLeft; + } + } while( elem = elem.offsetParent ); + return offsetLeft; + } + + this.top = function() { + var elem = block.elem; + var offsetTop = 0; + do { + if ( !isNaN( elem.offsetTop ) ) + { + offsetTop += elem.offsetTop; + } + } while( elem = elem.offsetParent ); + return offsetTop; + } + + this.right = function() { + return block.left() + block.elem.offsetWidth; + } + + this.bottom = function() { + return block.top() + block.elem.offsetHeight; + } } /* opts = { @@ -117,15 +147,15 @@ function Block(type, name, opts) { this.elem = document.createElement('ul'); this.elem.classList.add('c-wrapper'); - var header = document.createElement('li'); - header.classList.add('c-header'); - this.elem.appendChild(header); + this.header = document.createElement('li'); + this.header.classList.add('c-header'); + this.elem.appendChild(this.header); // add a blank draggy inside wrapper var nullWrapperContent = new Draggy(); nullWrapperContent.type = 'nullWrapperContent'; this.insertChild(nullWrapperContent, -1); - nullWrapperContent.elem = nullWrapperContent.content = header; + nullWrapperContent.elem = nullWrapperContent.content = this.header; this.content = document.createElement('ul'); this.content.classList.add('c-content'); @@ -155,15 +185,28 @@ function Block(type, name, opts) { } else if(type == 'stack') { this.elem = document.createElement('li'); this.elem.classList.add('stack'); - var header = this.elem; + this.header = this.elem; } this.elem.classList.add('e-' + name); this.elem.setAttribute('data-id', this.id); - header.appendChild(document.createTextNode(name + ' ')); + this.header.appendChild(document.createTextNode(name + ' ')); if(opts.hasAttrs) { - header.innerHTML += ``; + this.attrControls = document.createElement('span'); + this.attrControls.classList.add('attr-controls'); + + let removeAttr = document.createElement('span'); + removeAttr.classList.add('remove-attr'); + this.attrControls.appendChild(removeAttr); + removeAttr.addEventListener('click', function(e) {remove_attr(block)}); + + let addAttr = document.createElement('span'); + addAttr.classList.add('add-attr'); + this.attrControls.appendChild(addAttr); + addAttr.addEventListener('click', function(e) {add_attr(block)}); + + this.header.appendChild(this.attrControls); } if(opts.scriptInputContent !== null) { @@ -171,7 +214,7 @@ function Block(type, name, opts) { this.scriptInput.classList.add('script-input'); this.scriptInput.setAttribute('contenteditable', 'true') this.scriptInput.appendChild(document.createTextNode(opts.scriptInputContent)); - header.appendChild(this.scriptInput); + this.header.appendChild(this.scriptInput); } this.clone = function(_inPalette) { @@ -297,8 +340,8 @@ function parentHasClass(element, className) { // Will be called when user starts dragging an element function _drag_init(block, ev) { var elem = block.elem; - var relativeX = ev.pageX - getOffset(elem).left; - var relativeY = ev.pageY - getOffset(elem).top; + var relativeX = ev.pageX - block.left(); + var relativeY = ev.pageY - block.top(); // Store the object of the element which needs to be moved var draggy = new Draggy() SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); @@ -323,8 +366,8 @@ function _drag_init(block, ev) { function _palette_drag_init(block, ev) { var elem = block.elem; - var relativeX = ev.clientY - getOffset(elem).left - SCRIPTING_AREA.scrollLeft; - var relativeY = ev.clientY - getOffset(elem).top + BLOCK_PALETTE.scrollTop - SCRIPTING_AREA.scrollTop; + var relativeX = ev.clientY - block.left() - SCRIPTING_AREA.scrollLeft; + var relativeY = ev.clientY - block.top() + BLOCK_PALETTE.scrollTop - SCRIPTING_AREA.scrollTop; // Clone element var newBlock = block.clone(false); var newElem = newBlock.elem; @@ -383,10 +426,10 @@ function _destroy(ev) { } } else { - if (getOffset(selected.elem).top - getOffset(SCRIPTING_AREA).top < 0) { + if (selected.top() - getOffset(SCRIPTING_AREA).top < 0) { selected.elem.style.top = 0; } - if (getOffset(selected.elem).left - getOffset(SCRIPTING_AREA).left < 0) { + if (selected.left() - getOffset(SCRIPTING_AREA).left < 0) { selected.elem.style.left = 0; } } @@ -454,14 +497,14 @@ var C_PALETTE_ELEMENTS = ([ var bodyScript = new Draggy(); bodyScript.elem = bodyScript.content = document.querySelector('#bodyScript'); -var body = newBlock = new Block('wrapper', 'body', { +var BODY = newBlock = new Block('wrapper', 'body', { hasAttrs: true, hasQuickText: true, scriptInputContent: null, inPalette: false, unmoveable: true }); -bodyScript.insertChild(body, -1); +bodyScript.insertChild(BODY, -1); SCRIPTING_AREA.addEventListener('contextmenu', function(ev) { if (ev.target.matches(DRAGGABLE_ELEMENTS) || ev.target.parentNode.matches(DRAGGABLE_ELEMENTS)) { diff --git a/resources/js/fileManagement.js b/resources/js/fileManagement.js index af16eb5..a26fee6 100644 --- a/resources/js/fileManagement.js +++ b/resources/js/fileManagement.js @@ -3,7 +3,7 @@ document.getElementById('downloadButton').addEventListener('click', function() { var jsonFiles = zip.folder('.elem'); for (fileName in fileData) { - zip.file(fileName, json2html(fileData[fileName])); + zip.file(fileName, blockTreeToHTML(fileData[fileName]).outerHTML); // jsonFiles.file(fileName.split('.')[0] + '.json', JSON.stringify(fileData[fileName])); } @@ -50,4 +50,4 @@ document.getElementById('projectOpen').addEventListener('change', function() { reader.readAsArrayBuffer(this.files[0]); document.getElementById('projectOpen').value = null; // clear value -}); \ No newline at end of file +}); From 83a3cb6fe95a1cd180efef120a357710ef1c04a6 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 00:20:00 -0600 Subject: [PATCH 03/48] =?UTF-8?q?fix=20bug=20where=20sometimes=20blocks=20?= =?UTF-8?q?didn=E2=80=99t=20symbolically=20attach=20to=20parent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- resources/js/blocks.js | 31 +++++++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index 52ae5da..64272f9 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ - + diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 0ce6eb9..e53cc1a 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -37,6 +37,7 @@ function Draggy() { block.content.appendChild(child.elem); } else { block.content.insertBefore(child.elem, block.children[index].elem); + block.children.splice(index, 0, child); } child.parent = block; }; @@ -225,6 +226,24 @@ function Block(type, name, opts) { inPalette: _inPalette }); }; + + block.elem.addEventListener('contextmenu', function(ev) { + SCRIPT_MENU.style.display = 'block'; + SCRIPT_MENU.style.top = ev.pageY + 'px'; + SCRIPT_MENU.style.left = ev.pageX + 'px'; + RIGHT_CLICKED_SCRIPT = ev.target; + ev.preventDefault(); + + setTimeout(function() { + document.body.addEventListener('click', function context_blur(e2) { + SCRIPT_MENU.style.display = 'none'; + RIGHT_CLICKED_SCRIPT = undefined; + document.body.removeEventListener('click', context_blur); + }); + }, 0); + + }); + if(!opts.unmoveable) { let testBlockContents = function(elem) { var BLOCK_CONTENTS = [ @@ -256,8 +275,6 @@ function Block(type, name, opts) { } setZebra(); setFrameContent(); - SCRIPT_MENU.style.display = 'none'; - RIGHT_CLICKED_SCRIPT = undefined; }); this.elem.addEventListener('mouseup', function(ev) { @@ -506,16 +523,6 @@ var BODY = newBlock = new Block('wrapper', 'body', { }); bodyScript.insertChild(BODY, -1); -SCRIPTING_AREA.addEventListener('contextmenu', function(ev) { - if (ev.target.matches(DRAGGABLE_ELEMENTS) || ev.target.parentNode.matches(DRAGGABLE_ELEMENTS)) { - SCRIPT_MENU.style.display = 'block'; - SCRIPT_MENU.style.top = ev.pageY + 'px'; - SCRIPT_MENU.style.left = ev.pageX + 'px'; - RIGHT_CLICKED_SCRIPT = ev.target; - ev.preventDefault(); - } -}); - SCRIPTING_AREA.addEventListener('input', function(ev) { if (ev.target.getAttribute('contenteditable')) { if(ev.target.innerHTML != ev.target.textContent) { From 0bfd3facc701897b9227ab44663206fad5b46eb8 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 00:25:04 -0600 Subject: [PATCH 04/48] bugfix: now you can add block to beginning of c-stack --- resources/js/blocks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/blocks.js b/resources/js/blocks.js index e53cc1a..5cdc2b2 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -435,7 +435,7 @@ function _destroy(ev) { child.removeFromParent(); child.elem.removeAttribute('style'); if(topEl.type == 'nullWrapperContent') { - topEl.parent.insertChild(child, -1); + topEl.parent.insertChild(child, 1); // 0 is the null Draggy } else if(topEl.type == 'stack' || topEl.type == 'wrapper') { topEl.parent.insertChild(child, topEl.getIndex() + 1); From 60aefcf769f1ba37a49e41a123a72c860ecb76d8 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 00:38:04 -0600 Subject: [PATCH 05/48] move some event listeners around, resolve #242 in the process --- resources/js/blockAttributes.js | 1 + resources/js/blocks.js | 59 +++++++++++++++++---------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index 6d5775a..787b049 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -23,6 +23,7 @@ function Attr(attrName, value) { this.input.setAttribute('contenteditable', 'true'); this.input.appendChild(document.createTextNode(value)); this.elem.appendChild(this.input); + this.input.addEventListener('input', cleanse_contenteditable); var attr = this; this.dropdown.addEventListener('click', function(e) { diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 5cdc2b2..0dab87b 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -215,6 +215,7 @@ function Block(type, name, opts) { this.scriptInput.classList.add('script-input'); this.scriptInput.setAttribute('contenteditable', 'true') this.scriptInput.appendChild(document.createTextNode(opts.scriptInputContent)); + this.scriptInput.addEventListener('input', cleanse_contenteditable); this.header.appendChild(this.scriptInput); } @@ -523,34 +524,34 @@ var BODY = newBlock = new Block('wrapper', 'body', { }); bodyScript.insertChild(BODY, -1); -SCRIPTING_AREA.addEventListener('input', function(ev) { - if (ev.target.getAttribute('contenteditable')) { - if(ev.target.innerHTML != ev.target.textContent) { - var caretPos = 0, - sel, range; - sel = window.getSelection(); - if (sel.rangeCount) { - range = sel.getRangeAt(0); - var children = ev.target.childNodes; - var keepLooping = true; - for(let i = 0; keepLooping; i++) { - if(children[i] == range.commonAncestorContainer || children[i] == range.commonAncestorContainer.parentNode) { - caretPos += range.endOffset; - keepLooping = false; - } else { - caretPos += children[i].textContent.length; - } +function cleanse_contenteditable (ev) { + if(ev.target.innerHTML != ev.target.textContent) { + var caretPos = 0, + sel, range; + sel = window.getSelection(); + if (sel.rangeCount) { + range = sel.getRangeAt(0); + var children = ev.target.childNodes; + var keepLooping = true; + for(let i = 0; keepLooping; i++) { + if(children[i] == range.commonAncestorContainer || children[i] == range.commonAncestorContainer.parentNode) { + caretPos += range.endOffset; + keepLooping = false; + } else if(!children[i]) { + keepLooping = false; + } else { + caretPos += children[i].textContent.length; } - ev.target.innerHTML = ev.target.textContent; - range = document.createRange(); - range.setStart(ev.target.childNodes[0], caretPos); - range.collapse(true); - sel.removeAllRanges(); - sel.addRange(range); } + ev.target.innerHTML = ev.target.textContent; + range = document.createRange(); + range.setStart(ev.target.childNodes[0], caretPos); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); } } -}); +} var SCRIPT_MENU = document.querySelector('.context-menu.scripts'); var RIGHT_CLICKED_SCRIPT = undefined; @@ -561,11 +562,11 @@ $('body').on('mousemove', _move_elem) trashCan = document.getElementById('trashCan'); trashCan.classList.remove('showing'); _delete(ev); - } else { - if (ev.target == BLOCK_PALETTE) { - trashCan = document.getElementById('trashCan'); - trashCan.classList.remove('showing'); - } + } else { + if (ev.target == BLOCK_PALETTE) { + trashCan = document.getElementById('trashCan'); + trashCan.classList.remove('showing'); + } _destroy(ev); } if (!(ev.target.classList.contains('file') || parentHasClass(ev.target, 'file'))) { From 60ca20a42d821bc80576e0f25ce94dd9b1934e2d Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 00:58:41 -0600 Subject: [PATCH 06/48] fix duplicate functionality --- resources/js/blocks.js | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 0dab87b..8323a99 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -232,7 +232,7 @@ function Block(type, name, opts) { SCRIPT_MENU.style.display = 'block'; SCRIPT_MENU.style.top = ev.pageY + 'px'; SCRIPT_MENU.style.left = ev.pageX + 'px'; - RIGHT_CLICKED_SCRIPT = ev.target; + RIGHT_CLICKED_SCRIPT = block; ev.preventDefault(); setTimeout(function() { @@ -581,28 +581,21 @@ $('.context-menu.scripts .menu-item').on('click', function(ev) { if (RIGHT_CLICKED_SCRIPT) { switch (this.dataset.action) { case 'duplicate-script': - var target = RIGHT_CLICKED_SCRIPT; - // context menu stuff here... - if (target.matches(C_ELEMENTS)) { - target = target.parentNode; - } // do stuff with node... and get stuff beneath it too! - var wrapper = document.createElement('ul'); - wrapper.className = 'draggy'; - var childs = toArr(target.parentElement.children); - for (var i = childs.indexOf(target); i < childs.length; i++) { - var child = childs[i].cloneNode(true); - child.removeAttribute('style'); - wrapper.appendChild(child); + var target = RIGHT_CLICKED_SCRIPT; + var draggy = new Draggy(); + SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); + for(let i = target.getIndex(); i < target.parent.children.length; i++) { + let child = target.parent.children[i]; + draggy.insertChild(child.clone(false), -1); } - var relativeX = ev.pageX - getOffset(target).left; - var relativeY = ev.pageY - getOffset(target).top; + var relativeX = ev.pageX - target.left(); + var relativeY = ev.pageY - target.top(); var curX = ev.pageX - getOffset(SCRIPTING_AREA).left, curY = ev.pageY - getOffset(SCRIPTING_AREA).top; - wrapper.style.left = curX - relativeX + 25 + 'px'; - wrapper.style.top = curY - relativeY + 25 + 'px'; - SCRIPTING_AREA.insertBefore(wrapper, SCRIPTING_AREA.firstChild); + draggy.elem.style.left = curX - relativeX + 25 + 'px'; + draggy.elem.style.top = curY - relativeY + 25 + 'px'; setZebra(); RIGHT_CLICKED_SCRIPT = undefined; From 6d1abd33cba970d8cd0aec82b147defda4ac4f59 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 01:02:06 -0600 Subject: [PATCH 07/48] =?UTF-8?q?disable=20context=20menu=20on=20=E2=80=9C?= =?UTF-8?q?body=E2=80=9D=20element?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/blocks.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 8323a99..5eb732a 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -229,11 +229,14 @@ function Block(type, name, opts) { }; block.elem.addEventListener('contextmenu', function(ev) { + ev.preventDefault(); + + if(opts.unmoveable) return; + SCRIPT_MENU.style.display = 'block'; SCRIPT_MENU.style.top = ev.pageY + 'px'; SCRIPT_MENU.style.left = ev.pageX + 'px'; RIGHT_CLICKED_SCRIPT = block; - ev.preventDefault(); setTimeout(function() { document.body.addEventListener('click', function context_blur(e2) { From a119253e8076893386c3fc8531b6780ed55527fe Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 15:41:51 -0600 Subject: [PATCH 08/48] resolve error when rendering blank attributes --- resources/js/block2json.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index b357455..c41c49e 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -179,7 +179,7 @@ function blockTreeToHTML(block) { } else { var element = document.createElement(block.name); for(let attr of block.attrs) { - element.setAttribute(attr.getName(), attr.getValue()); + if(attr.getName().trim() && attr.getValue().trim()) element.setAttribute(attr.getName(), attr.getValue()); } for(let child of block.children) { let parsedChild = blockTreeToHTML(child); From 6a18aa1f4c35adc06145732c40d8ea7f63bc0f29 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 17:44:57 -0600 Subject: [PATCH 09/48] start on file import/export --- resources/js/block2json.js | 8 +-- resources/js/blockAttributes.js | 38 +++++----- resources/js/blocks.js | 40 +++++++++-- resources/js/files.js | 121 +++++++++++++++++++------------- resources/js/tutorials/2.js | 2 +- 5 files changed, 133 insertions(+), 76 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index c41c49e..c13b0f6 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -179,7 +179,7 @@ function blockTreeToHTML(block) { } else { var element = document.createElement(block.name); for(let attr of block.attrs) { - if(attr.getName().trim() && attr.getValue().trim()) element.setAttribute(attr.getName(), attr.getValue()); + if(attr.value.trim() && attr.value.trim()) element.setAttribute(attr.value, attr.value); } for(let child of block.children) { let parsedChild = blockTreeToHTML(child); @@ -191,11 +191,11 @@ function blockTreeToHTML(block) { function setFrameContent(ext) { ext = ext || currentFile.split('.').pop(); - var script = document.getElementsByClassName('script')[0].cloneNode(true); //should only be one... + //var script = document.getElementsByClassName('script')[0].cloneNode(true); //should only be one... var previewElement = document.getElementsByClassName('previewBody')[0]; - var directChildren = toArr(script.children); - directChildren.shift(); + //var directChildren = toArr(script.children); + //directChildren.shift(); if (ext == 'css') { var jsonFormat = {}; diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index 787b049..77de8f3 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -5,27 +5,31 @@ var ATTRIBUTE_RESULTS = document.getElementById('attributeResults'); var CLICKED_ATTR; // both optional -function Attr(attrName, value) { +function Attr(name, value) { this.elem = document.createElement('span'); this.elem.classList.add('attr-holder'); - if(attrName === undefined) attrName = '\u00A0'; + this.name = (name === undefined) ? '\u00A0' : attrName; this.dropdown = document.createElement('span'); this.dropdown.classList.add('attr-dropdown') - this.dropdown.appendChild(document.createTextNode(attrName)); + this.dropdown.appendChild(document.createTextNode(this.name)); this.elem.appendChild(this.dropdown); this.elem.appendChild(document.createTextNode('=')); - if(value === undefined) value = ''; + this.value = (value === undefined) ? '' : value; this.input = document.createElement('span'); this.input.classList.add('attr-dropdown') this.input.setAttribute('contenteditable', 'true'); - this.input.appendChild(document.createTextNode(value)); + this.input.appendChild(document.createTextNode(this.value)); this.elem.appendChild(this.input); this.input.addEventListener('input', cleanse_contenteditable); var attr = this; + this.input.addEventListener('input', function(e) { + attr.value = attr.input.textContent; + }); + this.dropdown.addEventListener('click', function(e) { ATTRIBUTE_MENU.classList.remove('hidden'); ATTRIBUTE_MENU.style.top = attr.top() + attr.elem.offsetHeight + 'px'; @@ -38,18 +42,11 @@ function Attr(attrName, value) { ATTRIBUTE_MENU.classList.add('hidden'); CLICKED_ATTR = null; document.body.removeEventListener('click', dropdown_blur); + attr.name = attr.dropdown.textContent; }); }, 0); }); - this.getName = function() { - return attr.dropdown.textContent; - } - - this.getValue = function() { - return attr.input.textContent; - } - this.left = function() { var elem = attr.elem; var offsetLeft = 0; @@ -60,7 +57,7 @@ function Attr(attrName, value) { } } while( elem = elem.offsetParent ); return offsetLeft; - } + }; this.top = function() { var elem = attr.elem; @@ -72,11 +69,18 @@ function Attr(attrName, value) { } } while( elem = elem.offsetParent ); return offsetTop; - } + }; + + this.toStringable = function() { + return { + name: attr.name, + value: attr.value + }; + } } -function add_attr(block) { - var attr = new Attr(); +function add_attr(block, name, value) { + var attr = new Attr(name, value); block.header.insertBefore(attr.elem, block.attrControls); block.attrs.push(attr); } diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 5eb732a..4e3edf9 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -10,6 +10,8 @@ var blocksCount = 0; // not a real bumber of blocks. This value should never be // a more generic abstraction of a block // it can have children, so it can be a script function Draggy() { + this.x = 0; + this.y = 0; this.type = 'draggy'; this.id = blocksCount++; blocksDatabase[this.id] = this; @@ -105,7 +107,7 @@ function Draggy() { } } while( elem = elem.offsetParent ); return offsetLeft; - } + }; this.top = function() { var elem = block.elem; @@ -117,15 +119,41 @@ function Draggy() { } } while( elem = elem.offsetParent ); return offsetTop; - } + }; this.right = function() { return block.left() + block.elem.offsetWidth; - } + }; this.bottom = function() { return block.top() + block.elem.offsetHeight; - } + }; + + this.toStringable = function() { + var dummyBlock = {}; + var keysToAvoid = [ + 'parent', + 'children', + 'attrs' + ] + for(let key in block) { + if(typeof block[key] != 'function' // I know JSON does this automatically, shhh + && !(block[key] instanceof Element) // seemed like a good idea + && keysToAvoid.indexOf(key) == -1) dummyBlock[key] = block[key]; + } + dummyBlock.attrs = []; + for(let attr of block.attrs) { + dummyBlock.attrs.push(attr.toStringable()); + } + dummyBlock.children = []; + for(let child of block.children) { + dummyBlock.children.push(child.toStringable()); + } + return dummyBlock; + }; + this.toString = function() { + return JSON.stringify(block.toStringable()); + }; } /* opts = { @@ -143,6 +171,7 @@ function Block(type, name, opts) { this.name = name; this.inPalette = (opts.inPalette !== undefined) ? opts.inPalette : true; this.unmoveable = opts.unmoveable || false; + this.scriptInputContent = opts.scriptInputContent; var block = this; if(type == 'wrapper') { this.elem = document.createElement('ul'); @@ -216,6 +245,9 @@ function Block(type, name, opts) { this.scriptInput.setAttribute('contenteditable', 'true') this.scriptInput.appendChild(document.createTextNode(opts.scriptInputContent)); this.scriptInput.addEventListener('input', cleanse_contenteditable); + this.scriptInput.addEventListener('input', function(e) { + block.scriptInputContent = block.scriptInput.textContent; + }); this.header.appendChild(this.scriptInput); } diff --git a/resources/js/files.js b/resources/js/files.js index f7ef785..1624c0d 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -187,31 +187,61 @@ function getCSSAttributesHTML(attributes) { function generateBlocks(jsonData, ext) { if (ext == 'html') { - jsonData = jsonData.child; - var baseHtml = [ - '
      ', - '
    • <!DOCTYPE html>
    • ', - '
        ', - '
      • <body>
      • ', - '
          ', - ]; - - console.log(jsonData); - for (var i = 0; i < jsonData.length; i++) { - var curEl = jsonData[i]; - console.log(curEl.tag); - if (stackElements.indexOf('e-' + curEl.tag) > -1 || curEl.tag === '') { // if it's a stack or plain text - baseHtml.push(getBlockHtml(curEl)); - } - if (unnamedWrapperElements.indexOf(curEl.tag) > -1) { - // repeat down tree... - baseHtml.push(generateWrapperBlocks(curEl)); + function generateBlock(block) { + if(!block.type) return null; + let newBlock; + if(block.type == 'draggy') { + newBlock = new Draggy(); + } else if(block.type == 'nullWrapperContent') { + // no-op since wrappers generate these in their constructor + return null; + } else { + newBlock = new Block(block.type, block.name, { + hasAttrs: block.hasAttrs, + hasQuickText: block.hasQuickText, + scriptInputContent: block.scriptInputContent, + inPalette: false, + unmoveable: block.unmoveable + }); + for(let attr of block.attrs) { + add_attr(newBlock, attr.name, attr.value); } + } + newBlock.x = block.x; + newBlock.y = block.y; + for(let child of block.children) { + let newChild = generateBlock(child); + if(newChild) newBlock.insertChild(newChild, -1); + } + return newBlock; } - - baseHtml.push('
    '); - return baseHtml.join(''); + /* file format: + {fileName: + [ + block, + draggy, + draggy + ] + } + ... but this function is only passed the array. + */ + for(let block of jsonData) { + // what's the metadata around the block data? + let newBlock = generateBlock(block); + if(newBlock) { + if(newBlock.type == 'draggy') { + SCRIPTING_AREA.insertBefore(newBlock.elem, SCRIPTING_AREA.firstChild); + newBlock.elem.style.left = newBlock.x + 'px'; + newBlock.elem.style.top = newBlock.y + 'px'; + } else { + // should only be the body block + BODY.deleteDraggy(); + BODY = newBlock; + bodyScript.insertChild(BODY, -1); + } + } + } } else if (ext == 'css') { var baseHtml = [ '
      ', @@ -255,7 +285,7 @@ function loadFile(filename, el) { // render the HTML somehow from the blocks blockArea = $('.scriptingArea')[0]; console.log(fileData); - blockArea.innerHTML = generateBlocks(fileJson, filename.split('.').pop()); + generateBlocks(fileJson, filename.split('.').pop()); setFrameContent(); setZebra(); } @@ -275,7 +305,7 @@ function manuallyCreateFile() { } } -function generateFile(fileName, ext, initial) { +function generateFile(fileName, ext) { currentFile = fileName; var finalFile = $('.add-file')[0]; @@ -294,31 +324,22 @@ function generateFile(fileName, ext, initial) { ''].join(''); finalFile.parentNode.insertBefore(fileSelector, finalFile); - // set the fileData for it to be basic... - if (initial) { - fileData[fileName] = initial; - } else { - if (ext == 'html') { - fileData[fileName] = { - "tag": "body", - "attr": {}, - "child": [] - }; - } else if (ext == 'css') { - fileData[fileName] = { - 'children': { - '.selector': { // should I initialize this? probably not, maybe? idk post comments on it - 'children': {}, - 'attributes': { - 'background-color': 'red', - } + if (ext == 'html') { + fileData[fileName] = BODY; + } else if (ext == 'css') { + fileData[fileName] = { + 'children': { + '.selector': { // should I initialize this? probably not, maybe? idk post comments on it + 'children': {}, + 'attributes': { + 'background-color': 'red', } - }, - 'attributes': {} - }; - } else { - throw 'File type "' + ext + '" not supported.'; - } + } + }, + 'attributes': {} + }; + } else { + throw 'File type "' + ext + '" not supported.'; } blockArea = $('.scriptingArea')[0]; @@ -328,7 +349,7 @@ function generateFile(fileName, ext, initial) { if (ext == 'css') { blockArea.innerHTML = generateBlocks(fileData[fileName].children, ext); } else { - blockArea.innerHTML = generateBlocks([], ext); + generateBlocks([], ext); } } @@ -422,4 +443,4 @@ $('.context-menu.files .menu-item').on('click', function(ev) { } RIGHT_CLICKED = undefined; FILE_MENU.style.display = 'none'; -}); \ No newline at end of file +}); diff --git a/resources/js/tutorials/2.js b/resources/js/tutorials/2.js index 26fd06b..b1078aa 100644 --- a/resources/js/tutorials/2.js +++ b/resources/js/tutorials/2.js @@ -1,5 +1,5 @@ //hijack the file open script so I don't have to walk user through the basics again -fileData = {"index.html":{"tag":"body","child":[{"tag":"h1","attr":{},"child":[{"tag":"","attr":{},"text":"My Awesome Website"}]},{"tag":"","attr":{},"text":DEFAULT_TEXT}]}}; +fileData = {"index.html":[{"x":0,"y":0,"type":"wrapper","id":1,"inPalette":false,"name":"body","unmoveable":true,"scriptInputContent":null,"attrs":[],"children":[{"x":0,"y":0,"type":"nullWrapperContent","id":2,"inPalette":false,"attrs":[],"children":[]},{"x":0,"y":0,"type":"wrapper","id":53,"inPalette":false,"name":"h1","unmoveable":false,"scriptInputContent":null,"attrs":[],"children":[{"x":0,"y":0,"type":"nullWrapperContent","id":54,"inPalette":false,"attrs":[],"children":[]},{"x":0,"y":0,"type":"stack","id":56,"inPalette":false,"name":"text","unmoveable":false,"scriptInputContent":"My Awesome Website","attrs":[],"children":[]}]},{"x":0,"y":0,"type":"stack","id":52,"inPalette":false,"name":"text","unmoveable":false,"scriptInputContent":"breadfish","attrs":[],"children":[]}]}]}; $('.filePane')[0].innerHTML = '
      index.html
      +
      '; loadFile("index.html"); From 0b41c5674d72e5f7a01378a69da0ccf315e5b04d Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 17:53:17 -0600 Subject: [PATCH 10/48] bug fixes related to file import --- resources/js/block2json.js | 2 +- resources/js/blocks.js | 2 ++ resources/js/tutorials/2.js | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index c13b0f6..0c89312 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -179,7 +179,7 @@ function blockTreeToHTML(block) { } else { var element = document.createElement(block.name); for(let attr of block.attrs) { - if(attr.value.trim() && attr.value.trim()) element.setAttribute(attr.value, attr.value); + if(attr.name.trim() && attr.value.trim()) element.setAttribute(attr.name, attr.value); } for(let child of block.children) { let parsedChild = blockTreeToHTML(child); diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 4e3edf9..a7b3e54 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -169,6 +169,8 @@ function Block(type, name, opts) { Draggy.apply(this); this.type = type; this.name = name; + this.hasAttrs = opts.hasAttrs; + this.hasQuickText = opts.hasQuickText; this.inPalette = (opts.inPalette !== undefined) ? opts.inPalette : true; this.unmoveable = opts.unmoveable || false; this.scriptInputContent = opts.scriptInputContent; diff --git a/resources/js/tutorials/2.js b/resources/js/tutorials/2.js index b1078aa..3444843 100644 --- a/resources/js/tutorials/2.js +++ b/resources/js/tutorials/2.js @@ -1,5 +1,5 @@ //hijack the file open script so I don't have to walk user through the basics again -fileData = {"index.html":[{"x":0,"y":0,"type":"wrapper","id":1,"inPalette":false,"name":"body","unmoveable":true,"scriptInputContent":null,"attrs":[],"children":[{"x":0,"y":0,"type":"nullWrapperContent","id":2,"inPalette":false,"attrs":[],"children":[]},{"x":0,"y":0,"type":"wrapper","id":53,"inPalette":false,"name":"h1","unmoveable":false,"scriptInputContent":null,"attrs":[],"children":[{"x":0,"y":0,"type":"nullWrapperContent","id":54,"inPalette":false,"attrs":[],"children":[]},{"x":0,"y":0,"type":"stack","id":56,"inPalette":false,"name":"text","unmoveable":false,"scriptInputContent":"My Awesome Website","attrs":[],"children":[]}]},{"x":0,"y":0,"type":"stack","id":52,"inPalette":false,"name":"text","unmoveable":false,"scriptInputContent":"breadfish","attrs":[],"children":[]}]}]}; +fileData = {"index.html":[{"x":0,"y":0,"type":"wrapper","id":1,"inPalette":false,"name":"body","hasAttrs":true,"hasQuickText":true,"unmoveable":true,"scriptInputContent":null,"attrs":[],"children":[{"x":0,"y":0,"type":"nullWrapperContent","id":2,"inPalette":false,"attrs":[],"children":[]},{"x":0,"y":0,"type":"wrapper","id":53,"inPalette":false,"name":"h1","hasAttrs":true,"hasQuickText":true,"unmoveable":false,"scriptInputContent":null,"attrs":[],"children":[{"x":0,"y":0,"type":"nullWrapperContent","id":54,"inPalette":false,"attrs":[],"children":[]},{"x":0,"y":0,"type":"stack","id":56,"inPalette":false,"name":"text","hasAttrs":false,"hasQuickText":false,"unmoveable":false,"scriptInputContent":"My Awesome Website","attrs":[],"children":[]}]},{"x":0,"y":0,"type":"stack","id":52,"inPalette":false,"name":"text","hasAttrs":false,"hasQuickText":false,"unmoveable":false,"scriptInputContent":"breadfish","attrs":[],"children":[]}]}]}; $('.filePane')[0].innerHTML = '
      index.html
      +
      '; loadFile("index.html"); From 8ea182847ce0a2eab889c6c72fbe72a9272690df Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 12 Apr 2017 23:44:23 -0600 Subject: [PATCH 11/48] I got single-file export to work :D --- resources/js/block2json.js | 2 +- resources/js/blocks.js | 6 ++ resources/js/fileManagement.js | 16 +++-- resources/js/files.js | 107 ++++++--------------------------- 4 files changed, 37 insertions(+), 94 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 0c89312..e7c64af 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -175,7 +175,7 @@ function blockTreeToHTML(block) { if(block.type !== 'stack' && block.type !== 'wrapper') { return null; } else if(block.name == 'text') { - return document.createTextNode(block.scriptInput.textContent); + return document.createTextNode(block.scriptInputContent); } else { var element = document.createElement(block.name); for(let attr of block.attrs) { diff --git a/resources/js/blocks.js b/resources/js/blocks.js index a7b3e54..8050ae3 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -4,6 +4,7 @@ var selected = null, // Object of the element to be moved DEFAULT_TEXT = 'breadfish'; var blocksDatabase = {}; // all blocks by ID. Not an array in case we decide to use md5's or something later var allBlocks = []; +var topLevelBlocks = []; var blocksCount = 0; // not a real bumber of blocks. This value should never be // decrememnted because it's used to generate a blocks' unique ID @@ -53,6 +54,7 @@ function Draggy() { block.elem.parentElement.removeChild(block.elem); blocksDatabase[block.id] = null; allBlocks[allBlocks.indexOf(block)] = null; + if(topLevelBlocks.indexOf(block) != -1) topLevelBlocks[topLevelBlocks.indexOf(block)] = null; }; this.getClosestBlock = function() { var el = null, @@ -402,6 +404,7 @@ function _drag_init(block, ev) { SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); var curX = ev.pageX - getOffset(SCRIPTING_AREA).left, curY = ev.pageY - getOffset(SCRIPTING_AREA).top; + topLevelBlocks.push(draggy); var parent = block.parent; var kids = parent.children.slice(); for(let i = block.getIndex(), child; child = kids[i]; i++) { @@ -429,6 +432,7 @@ function _palette_drag_init(block, ev) { newElem.classList.remove('paletteBlock'); // Store the object of the element which needs to be moved var draggy = new Draggy(); + topLevelBlocks.push(draggy); SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); selected = newElem; selectedBlock = newBlock; @@ -560,6 +564,7 @@ var BODY = newBlock = new Block('wrapper', 'body', { unmoveable: true }); bodyScript.insertChild(BODY, -1); +topLevelBlocks.push(BODY); function cleanse_contenteditable (ev) { if(ev.target.innerHTML != ev.target.textContent) { @@ -622,6 +627,7 @@ $('.context-menu.scripts .menu-item').on('click', function(ev) { var target = RIGHT_CLICKED_SCRIPT; var draggy = new Draggy(); SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); + topLevelBlocks.push(draggy); for(let i = target.getIndex(); i < target.parent.children.length; i++) { let child = target.parent.children[i]; draggy.insertChild(child.clone(false), -1); diff --git a/resources/js/fileManagement.js b/resources/js/fileManagement.js index a26fee6..a05f374 100644 --- a/resources/js/fileManagement.js +++ b/resources/js/fileManagement.js @@ -1,13 +1,17 @@ document.getElementById('downloadButton').addEventListener('click', function() { var zip = new JSZip(); var jsonFiles = zip.folder('.elem'); - - for (fileName in fileData) { - zip.file(fileName, blockTreeToHTML(fileData[fileName]).outerHTML); - // jsonFiles.file(fileName.split('.')[0] + '.json', JSON.stringify(fileData[fileName])); + // only do this if it's an HTML file?? + blocksToJSON(currentFile); // I guess other files should've been serialized when user navigated away from them? + // I'll figure out multiple files later + for(let fileName in fileData) { + let body = fileData[fileName][0]; // first one should always be body... I think? + /// ^^ that only applies to HTML files + console.log(body, blockTreeToHTML(body).outerHTML) + zip.file(fileName, blockTreeToHTML(body).outerHTML); } - - jsonFiles.file('project.json', JSON.stringify(fileData)); + + jsonFiles.file('project.json', JSON.stringify(fileData, null, 1)); var content = zip.generate({type: 'blob'}); saveAs(content, 'project.zip'); diff --git a/resources/js/files.js b/resources/js/files.js index 1624c0d..6770d6f 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -53,6 +53,7 @@ function arrContainsFromArr(arr1, arr2) { } var fileData = {}; +var fileNames = ['index.html']; // make this work later var currentFile = 'index.html'; var attrNames = [ @@ -93,89 +94,6 @@ var unnamedWrapperElements = wrapperElements.map(function(item) { }); var textInput = 'text'; -function getBlockHtml(el) { - console.log('el: ', el); - var name; - if (el.tag == 'style') { - el.tag = 'CSS'; - } - if (el.tag) { - name = filter.blocks.filter(function(item) { - return item.name == el.tag; - })[0].name; - } else { - name = ''; - } - - var parsedHtml; - - var attrInputs = []; - for (attr in el.attr) { - attrInputs.push([ - '', - '' + attr + '', - '=', - '' + el.attr[attr] + '', - '' - ].join('')); - console.log(attr); - } - attrInputs = attrInputs.join(''); - - if (el.tag === "") { - parsedHtml = [ - '
    • ', - '' + el.text + '', - '
    • ' - ].join(''); - } else { - parsedHtml = [ - '
    • ', - name, - attrInputs, - "", - '
    • ' - ].join(''); - } - - return parsedHtml; -} - -function generateWrapperBlocks(jsonData) { - var attrInputs = []; - for (attr in jsonData.attr) { - attrInputs.push([ - '', - '' + attr + '', - '=', - '' + jsonData.attr[attr] + '', - '' - ].join('')); - } - attrInputs = attrInputs.join(''); - var wrapperHtml = [ - '
        ', - '
      • ' + jsonData.tag + attrInputs + '
      • ', - '
          ', - ]; - for (var i = 0; i < jsonData.child.length; i++) { - var curEl = jsonData.child[i]; - if (stackElements.indexOf('e-' + curEl.tag) > -1 || curEl.tag === '') { // if it's a stack or plain text - wrapperHtml.push(getBlockHtml(curEl)); - } - if (unnamedWrapperElements.indexOf(curEl.tag) > -1) { - // repeat down tree... - wrapperHtml.push(generateWrapperBlocks(curEl)); - } - } - - wrapperHtml.push( - '
      ' - ); - - return wrapperHtml.join(''); -} - function getCSSAttributesHTML(attributes) { var pushedHtml = []; for (attr in attributes) { @@ -293,8 +211,7 @@ function loadFile(filename, el) { function manuallyCreateFile() { //we need something better than this var fileName = prompt('Enter a file name', '.html'); - var ext = fileName.split('.'); - ext = ext[ext.length - 1]; + var ext = getExt(fileName); var allowedExts = ['html', 'css']; if (allowedExts.indexOf(ext) > -1) { if (fileName && !fileData.hasOwnProperty(fileName)) { @@ -305,7 +222,23 @@ function manuallyCreateFile() { } } -function generateFile(fileName, ext) { +function getExt(fileName) { + return fileName.match(/\w+$/)[0]; +} + +function blocksToJSON(fileName) { + var ext = getExt(fileName); + if (ext == 'html') { + var expArray = []; + for(let block of topLevelBlocks) { + if(block) expArray.push(block.toStringable()); + } + fileData[fileName] = expArray; + } else if (ext == 'css') {} +} + +// I don't actually know what this function does but I took it apart anyway +function generateFile_OLD(fileName, ext) { currentFile = fileName; var finalFile = $('.add-file')[0]; @@ -325,7 +258,7 @@ function generateFile(fileName, ext) { finalFile.parentNode.insertBefore(fileSelector, finalFile); if (ext == 'html') { - fileData[fileName] = BODY; + fileData[fileName] = blocksToJSON(); } else if (ext == 'css') { fileData[fileName] = { 'children': { From d1234f59b8fabf5b173be42700aafbfdf013b9e6 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 00:04:44 -0600 Subject: [PATCH 12/48] start fixing multiple html files --- index.html | 5 +---- resources/js/block2json.js | 1 + resources/js/blocks.js | 34 +++++++++++++++++++++++----------- resources/js/fileManagement.js | 3 --- resources/js/files.js | 20 +++++++------------- 5 files changed, 32 insertions(+), 31 deletions(-) diff --git a/index.html b/index.html index 64272f9..2116e78 100644 --- a/index.html +++ b/index.html @@ -191,10 +191,7 @@
      - -
        -
      • DOCTYPE html
      • -
      +
      • DOCTYPE html
      diff --git a/resources/js/block2json.js b/resources/js/block2json.js index e7c64af..5256ae6 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -213,6 +213,7 @@ function setFrameContent(ext) { fileData[currentFile] = jsonFormat; } else if (ext == 'html') { var parsedHtml = blockTreeToHTML(BODY); + blocksToJSON(currentFile); var previewWindow = previewElement; previewWindow = (previewWindow.contentWindow) ? previewWindow.contentWindow : (previewWindow.contentDocument.document) ? previewWindow.contentDocument.document : previewWindow.contentDocument; diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 8050ae3..3a3dee6 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -553,18 +553,30 @@ var C_PALETTE_ELEMENTS = ([ return '.blockArea ' + item; }).join(', '); +function clearBlocks() { + blocksDatabase = {}; + allBlocks = []; + topLevelBlocks = []; + let child; + SCRIPTING_AREA.innerHTML = `
      • DOCTYPE html
      `; + BODY = bodyScript = undefined; +} -var bodyScript = new Draggy(); -bodyScript.elem = bodyScript.content = document.querySelector('#bodyScript'); -var BODY = newBlock = new Block('wrapper', 'body', { - hasAttrs: true, - hasQuickText: true, - scriptInputContent: null, - inPalette: false, - unmoveable: true - }); -bodyScript.insertChild(BODY, -1); -topLevelBlocks.push(BODY); +var BODY, bodyScript; +function newHTMLFile() { + bodyScript = new Draggy(); + bodyScript.elem = bodyScript.content = document.querySelector('#bodyScript'); + BODY = newBlock = new Block('wrapper', 'body', { + hasAttrs: true, + hasQuickText: true, + scriptInputContent: null, + inPalette: false, + unmoveable: true + }); + bodyScript.insertChild(BODY, -1); + topLevelBlocks.push(BODY); +} +newHTMLFile(); function cleanse_contenteditable (ev) { if(ev.target.innerHTML != ev.target.textContent) { diff --git a/resources/js/fileManagement.js b/resources/js/fileManagement.js index a05f374..4a75a15 100644 --- a/resources/js/fileManagement.js +++ b/resources/js/fileManagement.js @@ -1,9 +1,6 @@ document.getElementById('downloadButton').addEventListener('click', function() { var zip = new JSZip(); var jsonFiles = zip.folder('.elem'); - // only do this if it's an HTML file?? - blocksToJSON(currentFile); // I guess other files should've been serialized when user navigated away from them? - // I'll figure out multiple files later for(let fileName in fileData) { let body = fileData[fileName][0]; // first one should always be body... I think? /// ^^ that only applies to HTML files diff --git a/resources/js/files.js b/resources/js/files.js index 6770d6f..efb14c7 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -215,7 +215,9 @@ function manuallyCreateFile() { var allowedExts = ['html', 'css']; if (allowedExts.indexOf(ext) > -1) { if (fileName && !fileData.hasOwnProperty(fileName)) { - generateFile(fileName, ext); + generateFile(fileName); + } else { + alert('A file with that name already exists.') } } else { throw 'File type "' + ext + '" not supported.'; @@ -238,7 +240,8 @@ function blocksToJSON(fileName) { } // I don't actually know what this function does but I took it apart anyway -function generateFile_OLD(fileName, ext) { +function generateFile(fileName) { + var ext = getExt(fileName); currentFile = fileName; var finalFile = $('.add-file')[0]; @@ -258,7 +261,8 @@ function generateFile_OLD(fileName, ext) { finalFile.parentNode.insertBefore(fileSelector, finalFile); if (ext == 'html') { - fileData[fileName] = blocksToJSON(); + clearBlocks(); + newHTMLFile(); } else if (ext == 'css') { fileData[fileName] = { 'children': { @@ -276,16 +280,6 @@ function generateFile_OLD(fileName, ext) { } blockArea = $('.scriptingArea')[0]; - if (initial) { - blockArea.innerHtml = generateBlocks(initial); // add shim later? - } else { - if (ext == 'css') { - blockArea.innerHTML = generateBlocks(fileData[fileName].children, ext); - } else { - generateBlocks([], ext); - } - } - //clear preview window var previewWindow = document.getElementsByClassName('previewBody')[0]; previewWindow = (previewWindow.contentWindow) ? previewWindow.contentWindow : (previewWindow.contentDocument.document) ? previewWindow.contentDocument.document : previewWindow.contentDocument; From 5e9ee30e9ec285be4efb05eeab13fe24986bd1ad Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 00:50:55 -0600 Subject: [PATCH 13/48] fixed bugs in switching between multiple html files --- resources/js/blockAttributes.js | 2 +- resources/js/blocks.js | 32 ++++++++++++++++++-------------- resources/js/files.js | 22 +++++++++++----------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index 77de8f3..b2116f7 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -9,7 +9,7 @@ function Attr(name, value) { this.elem = document.createElement('span'); this.elem.classList.add('attr-holder'); - this.name = (name === undefined) ? '\u00A0' : attrName; + this.name = (name === undefined) ? '\u00A0' : name; this.dropdown = document.createElement('span'); this.dropdown.classList.add('attr-dropdown') this.dropdown.appendChild(document.createTextNode(this.name)); diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 3a3dee6..03deb10 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -53,7 +53,8 @@ function Draggy() { block.removeFromParent(); block.elem.parentElement.removeChild(block.elem); blocksDatabase[block.id] = null; - allBlocks[allBlocks.indexOf(block)] = null; + let index = allBlocks.indexOf(block); + if(index != -1) allBlocks[index] = null; if(topLevelBlocks.indexOf(block) != -1) topLevelBlocks[topLevelBlocks.indexOf(block)] = null; }; this.getClosestBlock = function() { @@ -62,11 +63,9 @@ function Draggy() { dx, dy, minDistance; blocks: for(let oblock of allBlocks) { - if (!oblock || oblock.type == 'draggy' || oblock.unmoveable) continue blocks; - // check for descendancy let pblock = block; while(pblock) { @@ -457,7 +456,7 @@ function _move_elem(e) { removeDropArea(); if (selected !== null) { var el = selected.getClosestBlock(); - if (el !== null && !el.inPalette && (!el.parent || (el.parent && !el.parent.inPalette))) { + if (el !== null && !el.inPalette) { el.elem.classList.add('drop-area'); } selected.elem.style.left = (x_pos - x_elem) + 'px'; @@ -558,25 +557,30 @@ function clearBlocks() { allBlocks = []; topLevelBlocks = []; let child; - SCRIPTING_AREA.innerHTML = `
      • DOCTYPE html
      `; + BODY.deleteDraggy(); BODY = bodyScript = undefined; + SCRIPTING_AREA.innerHTML = `
      • DOCTYPE html
      `; } var BODY, bodyScript; -function newHTMLFile() { +function replaceBody(bodyBlock) { bodyScript = new Draggy(); bodyScript.elem = bodyScript.content = document.querySelector('#bodyScript'); - BODY = newBlock = new Block('wrapper', 'body', { - hasAttrs: true, - hasQuickText: true, - scriptInputContent: null, - inPalette: false, - unmoveable: true - }); + if(bodyBlock) { + BODY = bodyBlock; + } else { + BODY = new Block('wrapper', 'body', { + hasAttrs: true, + hasQuickText: true, + scriptInputContent: null, + inPalette: false, + unmoveable: true + }); + } bodyScript.insertChild(BODY, -1); topLevelBlocks.push(BODY); } -newHTMLFile(); +replaceBody(); function cleanse_contenteditable (ev) { if(ev.target.innerHTML != ev.target.textContent) { diff --git a/resources/js/files.js b/resources/js/files.js index efb14c7..2afb2ad 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -153,10 +153,7 @@ function generateBlocks(jsonData, ext) { newBlock.elem.style.left = newBlock.x + 'px'; newBlock.elem.style.top = newBlock.y + 'px'; } else { - // should only be the body block - BODY.deleteDraggy(); - BODY = newBlock; - bodyScript.insertChild(BODY, -1); + replaceBody(newBlock); } } } @@ -200,10 +197,9 @@ function loadFile(filename, el) { el.parentNode.classList.add('selected'); } - // render the HTML somehow from the blocks blockArea = $('.scriptingArea')[0]; - console.log(fileData); - generateBlocks(fileJson, filename.split('.').pop()); + clearBlocks(); + generateBlocks(fileJson, getExt(filename)); setFrameContent(); setZebra(); } @@ -211,16 +207,20 @@ function loadFile(filename, el) { function manuallyCreateFile() { //we need something better than this var fileName = prompt('Enter a file name', '.html'); + if(!fileName) { + alert('File name required.'); + return; + } var ext = getExt(fileName); var allowedExts = ['html', 'css']; - if (allowedExts.indexOf(ext) > -1) { - if (fileName && !fileData.hasOwnProperty(fileName)) { + if (allowedExts.indexOf(ext) != -1) { + if (!fileData.hasOwnProperty(fileName)) { generateFile(fileName); } else { alert('A file with that name already exists.') } } else { - throw 'File type "' + ext + '" not supported.'; + alert('File type "' + ext + '" not supported.'); } } @@ -262,7 +262,7 @@ function generateFile(fileName) { if (ext == 'html') { clearBlocks(); - newHTMLFile(); + replaceBody(); } else if (ext == 'css') { fileData[fileName] = { 'children': { From 00ce0e0193f93b3c522dc20f42e91e687cda039d Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 02:32:30 -0600 Subject: [PATCH 14/48] add CSS blocks and export --- index.html | 6 +-- resources/js/block2json.js | 96 ++++++++-------------------------- resources/js/blockFilter.js | 33 +++++++----- resources/js/blocks.js | 71 ++++++++++++++++++------- resources/js/fileManagement.js | 13 +++-- resources/js/files.js | 19 +++---- 6 files changed, 113 insertions(+), 125 deletions(-) diff --git a/index.html b/index.html index 2116e78..e02a94e 100644 --- a/index.html +++ b/index.html @@ -4,12 +4,12 @@ UI v0.0.4 | Elemental - + - - + + diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 5256ae6..524c40a 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -112,70 +112,32 @@ function getInlineText(elem) { return text; } -function traverseTree(parentNode) { - parentNode = parentNode.children[1]; - var directChildren = toArr(parentNode.children); - var pushedArr = []; - for (var i = 0; i < directChildren.length; i++) { - if (includesArrItem(directChildren[i].className, stackElements)) { //things like imgs - var elType = getElType(directChildren[i]); - if (elType == 'text') { - elType = ''; - } - if (elType == 'CSS') { - var cssFileName = getSingleAttrs(directChildren[i]).href; - if (fileData.hasOwnProperty(cssFileName)) { - var cssText = CSSJSON.toCSS({ - children: fileData[cssFileName], - attributes: {} - }); - pushedArr.push({ - tag: 'style', - attr: getSingleAttrs(directChildren[i]), - text: cssText - }); - } else { - pushedArr.push({ - tag: 'style', - attr: getSingleAttrs(directChildren[i]), - text: '' - }); - } - } else { - pushedArr.push({ - tag: elType, - attr: elType ? getSingleAttrs(directChildren[i]) : {}, - text: encodeEntities(getInlineText(directChildren[i])) - }); - } - } else if (includesArrItem(directChildren[i].className, wrapperElements)) { // things that can nest things - ie most elements - var elType = getElType(directChildren[i]); - pushedArr.push({ - tag: elType, - attr: getWrapperAttrs(directChildren[i]), - child: traverseTree(directChildren[i]), - }); - } - } - return pushedArr; //recursively get children of blocks -} - -function getCSSAttributes(children) { - var attributes = {}; - for (var i = 0; i < children.length; i++) { - var child = children[i]; - var attrName = encodeEntities(child.children[0].textContent); - var attrValue = encodeEntities(child.children[1].textContent); - attributes[attrName] = attrValue; - } - return attributes; +function blockTreeToCSS() { + function blockToCSS(block) { + if(block.name == 'selector') { + let out = ''; + for(let child of block.children) { + out += blockToCSS(child); + } + return `${block.inputs[0].value} {\n${out}}\n` + } else if(block.name == 'rule') { + return ` ${block.inputs[0].value}: ${block.inputs[1].value};\n` + } else { + return ''; + } + } + var css = ''; + for(let block of bodyScript.children) { + css += blockToCSS(block); + } + return css; } -function blockTreeToHTML(block) { +function blockTreeToHTML(block) { if(block.type !== 'stack' && block.type !== 'wrapper') { return null; } else if(block.name == 'text') { - return document.createTextNode(block.scriptInputContent); + return document.createTextNode(block.inputs[0].value); } else { var element = document.createElement(block.name); for(let attr of block.attrs) { @@ -190,7 +152,7 @@ function blockTreeToHTML(block) { } function setFrameContent(ext) { - ext = ext || currentFile.split('.').pop(); + ext = ext || getExt(currentFile); //var script = document.getElementsByClassName('script')[0].cloneNode(true); //should only be one... var previewElement = document.getElementsByClassName('previewBody')[0]; @@ -198,19 +160,7 @@ function setFrameContent(ext) { //directChildren.shift(); if (ext == 'css') { - var jsonFormat = {}; - for (var i = 0; i < directChildren.length; i++) { - //this should be easier than HTML because it's merely a list of selectors - var child = directChildren[i]; - // check to make sure it's a selector block - if (child.classList.contains('e-selector')) { - var selector = child.children[0].children[0].textContent; - jsonFormat[selector] = {}; - jsonFormat[selector].attributes = getCSSAttributes(child.children[1].children); - // console.log(child.children[1].children); - } - } - fileData[currentFile] = jsonFormat; + blocksToJSON(currentFile); } else if (ext == 'html') { var parsedHtml = blockTreeToHTML(BODY); blocksToJSON(currentFile); diff --git a/resources/js/blockFilter.js b/resources/js/blockFilter.js index aa475db..16eb8ec 100644 --- a/resources/js/blockFilter.js +++ b/resources/js/blockFilter.js @@ -40,40 +40,45 @@ var filter = { newBlock = new Block(block.type, block.name, { hasAttrs: true, hasQuickText: true, - scriptInputContent: null, - inPalette: true + inputs: [], + inPalette: true, + ftype: block.ftype }); - } else { + } else { // selector newBlock = new Block(block.type, block.name, { hasAttrs: false, hasQuickText: false, - scriptInputContent: '\u00A0', - inPalette: true + inputs: [''], // \u00A0 + inPalette: true, + ftype: block.ftype }); } - } else { + } else { // block.type == 'stack' if (block.name != 'text') { if (!block.ftype || block.ftype == 'html') { newBlock = new Block(block.type, block.name, { hasAttrs: true, hasQuickText: false, - scriptInputContent: null, - inPalette: true + inputs: [], + inPalette: true, + ftype: block.ftype }); - } else { + } else { // rule newBlock = new Block(block.type, block.name, { - hasAttrs: true, + hasAttrs: false, hasQuickText: false, - scriptInputContent: '', - inPalette: true + inputs: ['', ''], // \u00A0 + inPalette: true, + ftype: block.ftype });; } } else { newBlock = new Block('stack', 'text', { hasAttrs: false, hasQuickText: false, - scriptInputContent: DEFAULT_TEXT, - inPalette: true + inputs: [DEFAULT_TEXT], + inPalette: true, + ftype: block.ftype }); } } diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 03deb10..ac96bdd 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -20,6 +20,7 @@ function Draggy() { this.parent = null; this.children = []; this.attrs = []; + this.inputs = []; this.inPalette = false; this.elem = document.createElement('ul'); @@ -150,6 +151,10 @@ function Draggy() { for(let child of block.children) { dummyBlock.children.push(child.toStringable()); } + dummyBlock.inputs = []; + for(let input of block.inputs) { + dummyBlock.inputs.push(input.value); + } return dummyBlock; }; this.toString = function() { @@ -162,7 +167,9 @@ opts = { bool hasQuickText, string|null scriptInputContent, bool inPalette = true, - bool unmoveable + bool unmoveable, + string ftype, + array[string] inputs } */ function Block(type, name, opts) { @@ -170,11 +177,11 @@ function Block(type, name, opts) { Draggy.apply(this); this.type = type; this.name = name; + this.ftype = opts.ftype || 'html'; this.hasAttrs = opts.hasAttrs; this.hasQuickText = opts.hasQuickText; this.inPalette = (opts.inPalette !== undefined) ? opts.inPalette : true; this.unmoveable = opts.unmoveable || false; - this.scriptInputContent = opts.scriptInputContent; var block = this; if(type == 'wrapper') { this.elem = document.createElement('ul'); @@ -208,7 +215,7 @@ function Block(type, name, opts) { var newBlock = new Block('stack', 'text', { hasAttrs: false, hasQuickText: false, - scriptInputContent: DEFAULT_TEXT, + inputs: [DEFAULT_TEXT], inPalette: false }); block.insertChild(newBlock, -1); @@ -223,7 +230,7 @@ function Block(type, name, opts) { this.elem.classList.add('e-' + name); this.elem.setAttribute('data-id', this.id); - this.header.appendChild(document.createTextNode(name + ' ')); + if(name != 'text') this.header.appendChild(document.createTextNode(name + ' ')); if(opts.hasAttrs) { this.attrControls = document.createElement('span'); @@ -242,23 +249,21 @@ function Block(type, name, opts) { this.header.appendChild(this.attrControls); } - if(opts.scriptInputContent !== null) { - this.scriptInput = document.createElement('span'); - this.scriptInput.classList.add('script-input'); - this.scriptInput.setAttribute('contenteditable', 'true') - this.scriptInput.appendChild(document.createTextNode(opts.scriptInputContent)); - this.scriptInput.addEventListener('input', cleanse_contenteditable); - this.scriptInput.addEventListener('input', function(e) { - block.scriptInputContent = block.scriptInput.textContent; - }); - this.header.appendChild(this.scriptInput); + if(opts.inputs) { + if (opts.inputs.length == 1) { // text and selector + (new BlockInput(opts.inputs[0])).attachToBlock(block); + } else if (opts.inputs.length == 2) { // rule + (new BlockInput(opts.inputs[0])).attachToBlock(block); + this.header.appendChild(document.createTextNode(':\u00A0')); + (new BlockInput(opts.inputs[1])).attachToBlock(block); + } } this.clone = function(_inPalette) { return new Block(type, name, { hasAttrs: opts.hasAttrs, hasQuickText: opts.hasQuickText, - scriptInputContent: opts.scriptInputContent, + inputs: opts.inputs, inPalette: _inPalette }); }; @@ -326,6 +331,29 @@ function Block(type, name, opts) { Block.prototype = Object.create(Draggy.prototype); Block.prototype.constructor = Block.constructor; +function BlockInput(defaultValue) { + if (defaultValue === undefined || defaultValue === null) { + this.value = ''; // \u00A0 + } else { + this.value = defaultValue; + } + this.elem = document.createElement('span'); + this.elem.classList.add('script-input'); + this.elem.setAttribute('contenteditable', 'true') + this.elem.appendChild(document.createTextNode(this.value)); + this.elem.addEventListener('input', cleanse_contenteditable); + + var input = this; + this.elem.addEventListener('input', function(e) { + input.value = input.elem.textContent; + }); + + this.attachToBlock = function(block) { + block.header.appendChild(input.elem); + block.inputs.push(input); + }; +} + function isDescendant(parent, child) { var node = child.parentNode; while (node != null) { @@ -457,7 +485,11 @@ function _move_elem(e) { if (selected !== null) { var el = selected.getClosestBlock(); if (el !== null && !el.inPalette) { - el.elem.classList.add('drop-area'); + if(el.type == 'CSSNullWrapper') { + document.querySelector('#bodyScript > li.hat').classList.add('drop-area'); + } else { + el.elem.classList.add('drop-area'); + } } selected.elem.style.left = (x_pos - x_elem) + 'px'; selected.elem.style.top = (y_pos - y_elem) + 'px'; @@ -478,7 +510,8 @@ function _destroy(ev) { if(topEl.type == 'nullWrapperContent') { topEl.parent.insertChild(child, 1); // 0 is the null Draggy } else if(topEl.type == 'stack' - || topEl.type == 'wrapper') { + || topEl.type == 'wrapper' + || topEl.type == 'CSSNullWrapper') { topEl.parent.insertChild(child, topEl.getIndex() + 1); } } @@ -552,14 +585,14 @@ var C_PALETTE_ELEMENTS = ([ return '.blockArea ' + item; }).join(', '); -function clearBlocks() { +function clearBlocks(hat) { blocksDatabase = {}; allBlocks = []; topLevelBlocks = []; let child; BODY.deleteDraggy(); BODY = bodyScript = undefined; - SCRIPTING_AREA.innerHTML = `
      • DOCTYPE html
      `; + SCRIPTING_AREA.innerHTML = `
      • ${hat || 'DOCTYPE html'}
      `; } var BODY, bodyScript; diff --git a/resources/js/fileManagement.js b/resources/js/fileManagement.js index 4a75a15..e2cf88f 100644 --- a/resources/js/fileManagement.js +++ b/resources/js/fileManagement.js @@ -2,10 +2,15 @@ document.getElementById('downloadButton').addEventListener('click', function() { var zip = new JSZip(); var jsonFiles = zip.folder('.elem'); for(let fileName in fileData) { - let body = fileData[fileName][0]; // first one should always be body... I think? - /// ^^ that only applies to HTML files - console.log(body, blockTreeToHTML(body).outerHTML) - zip.file(fileName, blockTreeToHTML(body).outerHTML); + let ext = getExt(fileName); + let out = ''; + if(ext == 'html') { + let body = fileData[fileName][0]; // first one should always be body + out = blockTreeToHTML(body).outerHTML; + } else if(ext == 'css') { + out = blockTreeToCSS(); + } + zip.file(fileName, out); } jsonFiles.file('project.json', JSON.stringify(fileData, null, 1)); diff --git a/resources/js/files.js b/resources/js/files.js index 2afb2ad..c50f4c3 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -236,7 +236,9 @@ function blocksToJSON(fileName) { if(block) expArray.push(block.toStringable()); } fileData[fileName] = expArray; - } else if (ext == 'css') {} + } else if (ext == 'css') { + fileData[fileName] = bodyScript.toStringable(); // yeah I know I'm ignoring loose blocks + } } // I don't actually know what this function does but I took it apart anyway @@ -264,17 +266,10 @@ function generateFile(fileName) { clearBlocks(); replaceBody(); } else if (ext == 'css') { - fileData[fileName] = { - 'children': { - '.selector': { // should I initialize this? probably not, maybe? idk post comments on it - 'children': {}, - 'attributes': { - 'background-color': 'red', - } - } - }, - 'attributes': {} - }; + clearBlocks(currentFile); + replaceBody(new Draggy()); + BODY.type = 'CSSNullWrapper' + // add default selecter and prop } else { throw 'File type "' + ext + '" not supported.'; } From d316201f1f19daf6ded38e0e8090cb1df2ad8e7b Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 03:11:25 -0600 Subject: [PATCH 15/48] finish file import --- resources/js/block2json.js | 142 ------------------------------------- resources/js/blocks.js | 1 - resources/js/files.js | 131 +++++++++++++++------------------- 3 files changed, 58 insertions(+), 216 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 524c40a..f34ef47 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -7,111 +7,6 @@ if (!String.prototype.startsWith) { // sweet polyfill }; } -function toArr(nl) { - return Array.prototype.slice.call(nl); -} - -function includesArrItem(str, arr) { - var includes = false; - for (var i = 0; i < arr.length; i++) { - if (str.indexOf(arr[i]) > -1) { - includes = true; - break; - } - } - return includes; -} - -function getChildElem(parent, cName) { - var child = null; - for (var i = 0; i < parent.childNodes.length; i++) { - if (parent.childNodes[i].className == cName) { - child = parent.childNodes[i]; - break; - } - } - return child; -} - -function getElType(node) { - var classList = node.className.split(' '); - var type = null; - for (var i = 0; i < classList.length; i++) { - if (classList[i].startsWith('e-')) { - type = classList[i].substr(2, classList[i].length - 1); - break; - } - } - return type; -} - -function getAttrNames(classes) { - var classList = classes.split(' '); - var names = []; - for (var i = 0; i < classList.length; i++) { - if (attrNames.indexOf(classList[i]) > -1) { - names.push(classList[i]); - } - } - return names; -} - -function getSingleAttrs(element) { - // get attributes from element - var attrs = {}; - var attrElems = toArr(element.children); - for (var i = 0; i < attrElems.length; i++) { - var attrHolder = attrElems[i]; - if (attrHolder.classList && attrHolder.classList.contains('attr-holder')) { - var attrName = attrHolder.children[0].textContent; - var attrValue = attrHolder.children[1].textContent; - attrs[encodeEntities(attrName)] = encodeEntities(attrValue); - } - } - return attrs; -} - -function getWrapperAttrs(element) { - element = element.children[0]; - var attrs = {}; - var attrElems = toArr(element.children); - for (var i = 0; i < attrElems.length; i++) { - var attrHolder = attrElems[i]; - if (attrHolder.classList && attrHolder.classList.contains('attr-holder')) { - var attrName = attrHolder.children[0].textContent; - var attrValue = attrHolder.children[1].textContent; - attrs[encodeEntities(attrName)] = encodeEntities(attrValue); - } - } - return attrs; -} - -function encodeEntities(str) { - return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} - -function getText(elem) { - var text = ''; - var childNodes = toArr(elem.children); - for (var i = 0; i < childNodes.length; i++) { - if (childNodes[i].classList.contains(textInput)) { - text += childNodes[i].children[0].textContent; - } - } - return text; -} - -function getInlineText(elem) { - var text = ''; - var childNodes = toArr(elem.children); - for (var i = 0; i < childNodes.length; i++) { - if (childNodes[i].classList.contains(textInput)) { - text += childNodes[i].textContent; - } - } - return text; -} - function blockTreeToCSS() { function blockToCSS(block) { if(block.name == 'selector') { @@ -153,12 +48,8 @@ function blockTreeToHTML(block) { function setFrameContent(ext) { ext = ext || getExt(currentFile); - //var script = document.getElementsByClassName('script')[0].cloneNode(true); //should only be one... var previewElement = document.getElementsByClassName('previewBody')[0]; - //var directChildren = toArr(script.children); - //directChildren.shift(); - if (ext == 'css') { blocksToJSON(currentFile); } else if (ext == 'html') { @@ -175,36 +66,3 @@ function setFrameContent(ext) { } setFrameContent(); - -// example: -// -// var json = { -// tag: 'body', -// attr: { -// id: '1', -// class: ['foo'] -// }, -// child: [{ -// tag: 'h2', -// text: 'sample text with inline tag' -// },{ -// tag: 'pre', -// attr: { -// id: 'demo', -// class: ['foo', 'bar'] -// } -// },{ -// tag: 'pre', -// attr: { -// id: 'output', -// class: ['goo'] -// } -// },{ -// tag: 'input', -// attr: { -// id: 'execute', -// type: 'button', -// value: 'execute' -// } -// }] -// }; diff --git a/resources/js/blocks.js b/resources/js/blocks.js index ac96bdd..f960610 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -229,7 +229,6 @@ function Block(type, name, opts) { } this.elem.classList.add('e-' + name); this.elem.setAttribute('data-id', this.id); - if(name != 'text') this.header.appendChild(document.createTextNode(name + ' ')); if(opts.hasAttrs) { diff --git a/resources/js/files.js b/resources/js/files.js index c50f4c3..1318c24 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -104,78 +104,65 @@ function getCSSAttributesHTML(attributes) { } function generateBlocks(jsonData, ext) { - if (ext == 'html') { - function generateBlock(block) { - if(!block.type) return null; - let newBlock; - if(block.type == 'draggy') { - newBlock = new Draggy(); - } else if(block.type == 'nullWrapperContent') { - // no-op since wrappers generate these in their constructor - return null; - } else { - newBlock = new Block(block.type, block.name, { - hasAttrs: block.hasAttrs, - hasQuickText: block.hasQuickText, - scriptInputContent: block.scriptInputContent, - inPalette: false, - unmoveable: block.unmoveable - }); - for(let attr of block.attrs) { - add_attr(newBlock, attr.name, attr.value); - } - } - newBlock.x = block.x; - newBlock.y = block.y; - for(let child of block.children) { - let newChild = generateBlock(child); - if(newChild) newBlock.insertChild(newChild, -1); - } - return newBlock; - } - - /* file format: - {fileName: - [ - block, - draggy, - draggy - ] + function generateBlock(block) { + if(!block.type) return null; + let newBlock; + if(block.type == 'draggy') { + newBlock = new Draggy(); + } else if( block.type == 'nullWrapperContent' + || block.type == 'CSSNullWrapper') { + // no-op since wrappers generate these in their constructor + return null; + } else { + newBlock = new Block(block.type, block.name, { + hasAttrs: block.hasAttrs, + hasQuickText: block.hasQuickText, + inputs: block.inputs, + inPalette: false, + unmoveable: block.unmoveable + }); + for(let attr of block.attrs) { + add_attr(newBlock, attr.name, attr.value); } - ... but this function is only passed the array. - */ - for(let block of jsonData) { - // what's the metadata around the block data? - let newBlock = generateBlock(block); - if(newBlock) { - if(newBlock.type == 'draggy') { - SCRIPTING_AREA.insertBefore(newBlock.elem, SCRIPTING_AREA.firstChild); - newBlock.elem.style.left = newBlock.x + 'px'; - newBlock.elem.style.top = newBlock.y + 'px'; - } else { - replaceBody(newBlock); - } + } + newBlock.x = block.x; + newBlock.y = block.y; + for(let child of block.children) { + let newChild = generateBlock(child); + if(newChild) newBlock.insertChild(newChild, -1); + } + return newBlock; + } + + /* file format: + {fileName: + [ + block, + draggy, + draggy + ] + } + ... but this function is only passed the array. + */ + for(let block of jsonData) { + let newBlock = generateBlock(block); + if(newBlock) { + if(ext == 'css') { + clearBlocks(currentFile); + replaceBody(new Draggy()); + BODY.type = 'CSSNullWrapper'; + BODY.insertChild(newBlock, -1) + } else { + if(newBlock.type == 'draggy') { + SCRIPTING_AREA.insertBefore(newBlock.elem, SCRIPTING_AREA.firstChild); + newBlock.elem.style.left = newBlock.x + 'px'; + newBlock.elem.style.top = newBlock.y + 'px'; + } else { + clearBlocks(); + replaceBody(newBlock); } } - } else if (ext == 'css') { - var baseHtml = [ - '
        ', - '
      • ' + currentFile + '
      • ', - ]; - for (curSelector in jsonData) { - var selectorHtml = [ - '
          ', - '
        • selector ' + curSelector + '
        • ', - '
            ' - ]; - selectorHtml.push(getCSSAttributesHTML(jsonData[curSelector].attributes)); - selectorHtml.push('
        '); - baseHtml.push(selectorHtml.join('')); - } - baseHtml.push('
      '); - return baseHtml.join(''); - } else { - throw 'the world is going to be destroyed due to your foolishness, mortal!1111! ' + ext + ''; + } } } @@ -198,7 +185,6 @@ function loadFile(filename, el) { } blockArea = $('.scriptingArea')[0]; - clearBlocks(); generateBlocks(fileJson, getExt(filename)); setFrameContent(); setZebra(); @@ -237,7 +223,7 @@ function blocksToJSON(fileName) { } fileData[fileName] = expArray; } else if (ext == 'css') { - fileData[fileName] = bodyScript.toStringable(); // yeah I know I'm ignoring loose blocks + fileData[fileName] = [bodyScript.toStringable()]; // yeah I know I'm ignoring loose blocks } } @@ -268,8 +254,7 @@ function generateFile(fileName) { } else if (ext == 'css') { clearBlocks(currentFile); replaceBody(new Draggy()); - BODY.type = 'CSSNullWrapper' - // add default selecter and prop + BODY.type = 'CSSNullWrapper'; } else { throw 'File type "' + ext + '" not supported.'; } From b274b7523c9ed334d884ae4a63376114d012dbff Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 08:13:45 -0600 Subject: [PATCH 16/48] make change described by @iamunknown2 (close #252) --- resources/css/blocks.css | 2 +- resources/css/blocks.scss | 2 +- resources/js/tutorials/2.js | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/css/blocks.css b/resources/css/blocks.css index 1e06a28..93d9a4a 100644 --- a/resources/css/blocks.css +++ b/resources/css/blocks.css @@ -172,7 +172,7 @@ body { .attr-holder .attr-input { border-radius: 10px; min-width: 30px; - display: inline-block; + display: inline-flex; margin: 0px 3px; padding: 0px 4px; outline: none; } diff --git a/resources/css/blocks.scss b/resources/css/blocks.scss index ead19a2..7ecb942 100644 --- a/resources/css/blocks.scss +++ b/resources/css/blocks.scss @@ -172,7 +172,7 @@ body { background-color: orange; border-radius: 10px; box-sizing: border-box; - display: inline-block; + display: inline-flex; padding: 3px; margin-right: 6px; .attr-dropdown, diff --git a/resources/js/tutorials/2.js b/resources/js/tutorials/2.js index 3444843..8832992 100644 --- a/resources/js/tutorials/2.js +++ b/resources/js/tutorials/2.js @@ -1,5 +1,6 @@ //hijack the file open script so I don't have to walk user through the basics again -fileData = {"index.html":[{"x":0,"y":0,"type":"wrapper","id":1,"inPalette":false,"name":"body","hasAttrs":true,"hasQuickText":true,"unmoveable":true,"scriptInputContent":null,"attrs":[],"children":[{"x":0,"y":0,"type":"nullWrapperContent","id":2,"inPalette":false,"attrs":[],"children":[]},{"x":0,"y":0,"type":"wrapper","id":53,"inPalette":false,"name":"h1","hasAttrs":true,"hasQuickText":true,"unmoveable":false,"scriptInputContent":null,"attrs":[],"children":[{"x":0,"y":0,"type":"nullWrapperContent","id":54,"inPalette":false,"attrs":[],"children":[]},{"x":0,"y":0,"type":"stack","id":56,"inPalette":false,"name":"text","hasAttrs":false,"hasQuickText":false,"unmoveable":false,"scriptInputContent":"My Awesome Website","attrs":[],"children":[]}]},{"x":0,"y":0,"type":"stack","id":52,"inPalette":false,"name":"text","hasAttrs":false,"hasQuickText":false,"unmoveable":false,"scriptInputContent":"breadfish","attrs":[],"children":[]}]}]}; +fileData = {"index.html": [{"x": 0,"y": 0,"type": "wrapper","id": 1,"inputs": [],"inPalette": false,"name": "body","ftype": "html","hasAttrs": true,"hasQuickText": true,"unmoveable": true,"attrs": [],"children": [{"x": 0,"y": 0,"type": "nullWrapperContent","id": 2,"inputs": [],"inPalette": false,"attrs": [],"children": []},{"x": 0,"y": 0,"type": "wrapper","id": 53,"inputs": [],"inPalette": false,"name": "h1","ftype": "html","hasAttrs": true,"hasQuickText": true,"unmoveable": false,"attrs": [],"children": [{"x": 0,"y": 0,"type": "nullWrapperContent","id": 54,"inputs": [],"inPalette": false,"attrs": [],"children": []},{"x": 0,"y": 0,"type": "stack","id": 56,"inputs": ["My Awesome Website"],"inPalette": false,"name": "text","ftype": "html","hasAttrs": false,"hasQuickText": false,"unmoveable": false,"attrs": [],"children": []}]},{"x": 0,"y": 0,"type": "stack","id": 52,"inputs": ["breadfish"],"inPalette": false,"name": "text","ftype": "html","hasAttrs": false,"hasQuickText": false,"unmoveable": false,"attrs": [],"children": []}]},{"x": 324,"y": -128,"type": "draggy","id": 55,"inputs": [],"inPalette": false,"attrs": [],"children": []}] +} $('.filePane')[0].innerHTML = '
      index.html
      +
      '; loadFile("index.html"); From 3f14fd8b4b8d3acb032dd2a98dfff99b7480ccf0 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 13:36:02 -0600 Subject: [PATCH 17/48] =?UTF-8?q?fix=20bug=20where=20imported=20files=20we?= =?UTF-8?q?ren=E2=80=99t=20editable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/blockFilter.js | 10 ++-- resources/js/blocks.js | 42 ++++++------- resources/js/files.js | 114 +++++++++++++++++++----------------- 3 files changed, 87 insertions(+), 79 deletions(-) diff --git a/resources/js/blockFilter.js b/resources/js/blockFilter.js index 16eb8ec..e32feaa 100644 --- a/resources/js/blockFilter.js +++ b/resources/js/blockFilter.js @@ -42,7 +42,7 @@ var filter = { hasQuickText: true, inputs: [], inPalette: true, - ftype: block.ftype + ftype: 'html' }); } else { // selector newBlock = new Block(block.type, block.name, { @@ -50,7 +50,7 @@ var filter = { hasQuickText: false, inputs: [''], // \u00A0 inPalette: true, - ftype: block.ftype + ftype: 'css' }); } } else { // block.type == 'stack' @@ -61,7 +61,7 @@ var filter = { hasQuickText: false, inputs: [], inPalette: true, - ftype: block.ftype + ftype: 'html' }); } else { // rule newBlock = new Block(block.type, block.name, { @@ -69,7 +69,7 @@ var filter = { hasQuickText: false, inputs: ['', ''], // \u00A0 inPalette: true, - ftype: block.ftype + ftype: 'css' });; } } else { @@ -78,7 +78,7 @@ var filter = { hasQuickText: false, inputs: [DEFAULT_TEXT], inPalette: true, - ftype: block.ftype + ftype: 'html ' }); } } diff --git a/resources/js/blocks.js b/resources/js/blocks.js index f960610..bebce8e 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -1,27 +1,30 @@ var selected = null, // Object of the element to be moved x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer x_elem = 0, y_elem = 0, // Stores top, left values (edge) of the element - DEFAULT_TEXT = 'breadfish'; -var blocksDatabase = {}; // all blocks by ID. Not an array in case we decide to use md5's or something later -var allBlocks = []; -var topLevelBlocks = []; -var blocksCount = 0; // not a real bumber of blocks. This value should never be + DEFAULT_TEXT = 'breadfish', + SCRIPTING_AREA = $('.scriptingArea')[0]; +var blocksDatabase, // all blocks by ID. Not an array in case we decide to use md5's or something later + scriptBlocks, + topLevelBlocks, + blocksCount = 0; // not a real bumber of blocks. This value should never be // decrememnted because it's used to generate a blocks' unique ID +clearBlocks(); +replaceBody(); // a more generic abstraction of a block // it can have children, so it can be a script -function Draggy() { +function Draggy(inPalette) { this.x = 0; this.y = 0; this.type = 'draggy'; this.id = blocksCount++; blocksDatabase[this.id] = this; - allBlocks.push(this); this.parent = null; this.children = []; this.attrs = []; this.inputs = []; - this.inPalette = false; + this.inPalette = inPalette; + if(!this.inPalette) scriptBlocks.push(this); this.elem = document.createElement('ul'); this.elem.classList.add('draggy'); @@ -54,16 +57,17 @@ function Draggy() { block.removeFromParent(); block.elem.parentElement.removeChild(block.elem); blocksDatabase[block.id] = null; - let index = allBlocks.indexOf(block); - if(index != -1) allBlocks[index] = null; - if(topLevelBlocks.indexOf(block) != -1) topLevelBlocks[topLevelBlocks.indexOf(block)] = null; + let index1 = scriptBlocks.indexOf(block); + if(index1 != -1) scriptBlocks[index] = null; + let index2 = topLevelBlocks.indexOf(block); + if(index2 != -1) topLevelBlocks[index2] = null; }; this.getClosestBlock = function() { var el = null, distance, dx, dy, minDistance; - blocks: for(let oblock of allBlocks) { + blocks: for(let oblock of scriptBlocks) { if (!oblock || oblock.type == 'draggy' || oblock.unmoveable) continue blocks; @@ -174,7 +178,7 @@ opts = { */ function Block(type, name, opts) { if(!opts) opts = {}; - Draggy.apply(this); + Draggy.apply(this, [opts.inPalette]); this.type = type; this.name = name; this.ftype = opts.ftype || 'html'; @@ -192,7 +196,7 @@ function Block(type, name, opts) { this.elem.appendChild(this.header); // add a blank draggy inside wrapper - var nullWrapperContent = new Draggy(); + var nullWrapperContent = new Draggy(this.inPalette); nullWrapperContent.type = 'nullWrapperContent'; this.insertChild(nullWrapperContent, -1); nullWrapperContent.elem = nullWrapperContent.content = this.header; @@ -483,7 +487,7 @@ function _move_elem(e) { removeDropArea(); if (selected !== null) { var el = selected.getClosestBlock(); - if (el !== null && !el.inPalette) { + if (el !== null) { if(el.type == 'CSSNullWrapper') { document.querySelector('#bodyScript > li.hat').classList.add('drop-area'); } else { @@ -501,7 +505,7 @@ function _destroy(ev) { if (selected == null) return; var topEl = selected.getClosestBlock(); - if (topEl !== null && !topEl.inPalette && !parentHasClass(topEl.elem, 'blockArea')) { + if (topEl !== null) { var kids = selected.children.slice(); for(let child of kids) { child.removeFromParent(); @@ -551,7 +555,6 @@ var CSS_SNAP_CLASSES = [ ':not(.e-body) > .c-footer' ].join(', '); var MIN_DISTANCE = 50; -var SCRIPTING_AREA = $('.scriptingArea')[0]; var BLOCK_PALETTE = $('.blockArea')[0]; var DRAGGABLE_ELEMENTS = ([ @@ -586,10 +589,10 @@ var C_PALETTE_ELEMENTS = ([ function clearBlocks(hat) { blocksDatabase = {}; - allBlocks = []; + scriptBlocks = []; topLevelBlocks = []; let child; - BODY.deleteDraggy(); + if(BODY) BODY.deleteDraggy(); BODY = bodyScript = undefined; SCRIPTING_AREA.innerHTML = `
      • ${hat || 'DOCTYPE html'}
      `; } @@ -612,7 +615,6 @@ function replaceBody(bodyBlock) { bodyScript.insertChild(BODY, -1); topLevelBlocks.push(BODY); } -replaceBody(); function cleanse_contenteditable (ev) { if(ev.target.innerHTML != ev.target.textContent) { diff --git a/resources/js/files.js b/resources/js/files.js index 1318c24..51e6f67 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -104,66 +104,67 @@ function getCSSAttributesHTML(attributes) { } function generateBlocks(jsonData, ext) { - function generateBlock(block) { - if(!block.type) return null; - let newBlock; - if(block.type == 'draggy') { - newBlock = new Draggy(); - } else if( block.type == 'nullWrapperContent' - || block.type == 'CSSNullWrapper') { - // no-op since wrappers generate these in their constructor - return null; - } else { - newBlock = new Block(block.type, block.name, { - hasAttrs: block.hasAttrs, - hasQuickText: block.hasQuickText, - inputs: block.inputs, - inPalette: false, - unmoveable: block.unmoveable - }); - for(let attr of block.attrs) { - add_attr(newBlock, attr.name, attr.value); - } - } - newBlock.x = block.x; - newBlock.y = block.y; - for(let child of block.children) { - let newChild = generateBlock(child); - if(newChild) newBlock.insertChild(newChild, -1); - } - return newBlock; + function generateBlock(block) { + if(!block.type) return null; + let newBlock; + if(block.type == 'draggy') { + newBlock = new Draggy(); + } else if( block.type == 'stack' + || block.type == 'wrapper') { + newBlock = new Block(block.type, block.name, { + hasAttrs: block.hasAttrs, + hasQuickText: block.hasQuickText, + inputs: block.inputs, + inPalette: false, + unmoveable: block.unmoveable, + ftype: block.ftype + }); + for(let attr of block.attrs) { + add_attr(newBlock, attr.name, attr.value); + } + } else { + return null; // other types of Draggies are generated in block constructors } - - /* file format: - {fileName: - [ - block, - draggy, - draggy - ] + newBlock.x = block.x; + newBlock.y = block.y; + for(let child of block.children) { + let newChild = generateBlock(child); + if(newChild) newBlock.insertChild(newChild, -1); } - ... but this function is only passed the array. - */ + return newBlock; + } + if(ext == 'css') { for(let block of jsonData) { let newBlock = generateBlock(block); if(newBlock) { - if(ext == 'css') { - clearBlocks(currentFile); - replaceBody(new Draggy()); - BODY.type = 'CSSNullWrapper'; - BODY.insertChild(newBlock, -1) - } else { - if(newBlock.type == 'draggy') { - SCRIPTING_AREA.insertBefore(newBlock.elem, SCRIPTING_AREA.firstChild); - newBlock.elem.style.left = newBlock.x + 'px'; - newBlock.elem.style.top = newBlock.y + 'px'; - } else { - clearBlocks(); - replaceBody(newBlock); - } + clearBlocks(currentFile); + replaceBody(new Draggy()); + BODY.type = 'CSSNullWrapper'; + BODY.insertChild(newBlock, -1) + } + } + } else if(ext == 'html') { + let body; + for(let block of jsonData) { + if (block.name == 'body') { + body = block; + break; + } + } + clearBlocks(); + let newBody = generateBlock(body); + replaceBody(newBody); + for(let block of jsonData) { + if(block != body) { + let newBlock = generateBlock(block); + if(newBlock) { + SCRIPTING_AREA.insertBefore(newBlock.elem, SCRIPTING_AREA.firstChild); + newBlock.elem.style.left = newBlock.x + 'px'; + newBlock.elem.style.top = newBlock.y + 'px'; } } } + } } function loadFile(filename, el) { @@ -223,11 +224,16 @@ function blocksToJSON(fileName) { } fileData[fileName] = expArray; } else if (ext == 'css') { - fileData[fileName] = [bodyScript.toStringable()]; // yeah I know I'm ignoring loose blocks + // yeah I know I'm ignoring loose blocks + var expArray = []; + for(let block of bodyScript.children) { + if(block) expArray.push(block.toStringable()); + } + fileData[fileName] = expArray; + // fileData[fileName] = [bodyScript.toStringable()]; } } -// I don't actually know what this function does but I took it apart anyway function generateFile(fileName) { var ext = getExt(fileName); currentFile = fileName; From 60e2d7552635d9c02729b5c4e9d6cbf92c3306a9 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 13:56:47 -0600 Subject: [PATCH 18/48] fix items sometimes reversing in order on drop (thanks @iamunknown2 for reporting) --- resources/js/blocks.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/js/blocks.js b/resources/js/blocks.js index bebce8e..71c9c6e 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -58,7 +58,7 @@ function Draggy(inPalette) { block.elem.parentElement.removeChild(block.elem); blocksDatabase[block.id] = null; let index1 = scriptBlocks.indexOf(block); - if(index1 != -1) scriptBlocks[index] = null; + if(index1 != -1) scriptBlocks[index1] = null; let index2 = topLevelBlocks.indexOf(block); if(index2 != -1) topLevelBlocks[index2] = null; }; @@ -436,8 +436,8 @@ function _drag_init(block, ev) { curY = ev.pageY - getOffset(SCRIPTING_AREA).top; topLevelBlocks.push(draggy); var parent = block.parent; - var kids = parent.children.slice(); - for(let i = block.getIndex(), child; child = kids[i]; i++) { + var kids = parent.children.slice(block.getIndex()); + for(let child of kids) { child.removeFromParent(); draggy.insertChild(child, -1); child.elem.removeAttribute('style'); @@ -506,7 +506,7 @@ function _destroy(ev) { if (selected == null) return; var topEl = selected.getClosestBlock(); if (topEl !== null) { - var kids = selected.children.slice(); + var kids = selected.children.slice().reverse(); for(let child of kids) { child.removeFromParent(); child.elem.removeAttribute('style'); From 45e2cdbfe67cbacd2a1a417c36c8c2c9fbb26c73 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 14:23:15 -0600 Subject: [PATCH 19/48] clean up coords code --- resources/js/blocks.js | 48 ++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 71c9c6e..a865d5b 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -1,6 +1,6 @@ var selected = null, // Object of the element to be moved - x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer - x_elem = 0, y_elem = 0, // Stores top, left values (edge) of the element + mousePos = {x: 0, y: 0}, // Stores x & y coordinates of the mouse pointer + dragOffset = {x: 0, y: 0}, // Stores offset between dragged element and mouse DEFAULT_TEXT = 'breadfish', SCRIPTING_AREA = $('.scriptingArea')[0]; var blocksDatabase, // all blocks by ID. Not an array in case we decide to use md5's or something later @@ -135,6 +135,13 @@ function Draggy(inPalette) { return block.top() + block.elem.offsetHeight; }; + this.setPosition = function(x, y) { + block.x = x; + block.y = y; + block.elem.style.left = block.x + 'px'; + block.elem.style.top = block.y + 'px'; + } + this.toStringable = function() { var dummyBlock = {}; var keysToAvoid = [ @@ -443,13 +450,10 @@ function _drag_init(block, ev) { child.elem.removeAttribute('style'); } if(parent.children.length == 0 && parent.type == 'draggy') parent.deleteDraggy(); - draggy.x = curX - relativeX; - draggy.y = curY - relativeY; - draggy.elem.style.left = draggy.x + 'px'; - draggy.elem.style.top = draggy.y + 'px'; + draggy.setPosition(curX - relativeX, curY - relativeY); selected = draggy; - x_elem = x_pos - selected.elem.offsetLeft; - y_elem = y_pos - selected.elem.offsetTop; + dragOffset.x = mousePos.x - selected.elem.offsetLeft; + dragOffset.y = mousePos.y - selected.elem.offsetTop; } function _palette_drag_init(block, ev) { @@ -469,21 +473,17 @@ function _palette_drag_init(block, ev) { var curX = ev.clientY - getOffset(SCRIPTING_AREA).left, curY = ev.clientY - getOffset(SCRIPTING_AREA).top; draggy.insertChild(selectedBlock, -1); - draggy.x = curX - relativeX; - draggy.y = curY - relativeY; - draggy.elem.style.left = draggy.x + 'px'; - draggy.elem.style.top = draggy.y + 'px'; + draggy.setPosition(curX - relativeX, curY - relativeY); selected = draggy; - x_elem = x_pos - selected.elem.offsetLeft; - y_elem = y_pos - selected.elem.offsetTop; + dragOffset.x = mousePos.x - selected.elem.offsetLeft; + dragOffset.y = mousePos.y - selected.elem.offsetTop; } // Will be called when user dragging an element function _move_elem(e) { e.preventDefault(); // avoid selecting text or other blocks - x_pos = document.all ? window.event.clientX : e.pageX + SCRIPTING_AREA.scrollLeft; - y_pos = document.all ? window.event.clientY : e.pageY + SCRIPTING_AREA.scrollTop; - var SNAP_CLASSES = currentFile.split('.').pop() == 'css' ? CSS_SNAP_CLASSES : HTML_SNAP_CLASSES; + mousePos.x = e.pageX + SCRIPTING_AREA.scrollLeft; + mousePos.y = e.pageY + SCRIPTING_AREA.scrollTop; removeDropArea(); if (selected !== null) { var el = selected.getClosestBlock(); @@ -494,8 +494,7 @@ function _move_elem(e) { el.elem.classList.add('drop-area'); } } - selected.elem.style.left = (x_pos - x_elem) + 'px'; - selected.elem.style.top = (y_pos - y_elem) + 'px'; + selected.setPosition(mousePos.x - dragOffset.x, mousePos.y - dragOffset.y); } } @@ -520,12 +519,15 @@ function _destroy(ev) { } } else { - if (selected.top() - getOffset(SCRIPTING_AREA).top < 0) { - selected.elem.style.top = 0; - } + let newX = selected.x, + newY = selected.y; if (selected.left() - getOffset(SCRIPTING_AREA).left < 0) { - selected.elem.style.left = 0; + newX = 0; + } + if (selected.top() - getOffset(SCRIPTING_AREA).top < 0) { + newY = 0; } + selected.setPosition(newX, newY); } selected = null; } From e9c62e9818b607e98dadd029328e3c6a1e3f3572 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 15:00:07 -0600 Subject: [PATCH 20/48] fix tutorial 2 --- resources/js/tutorials/2.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/resources/js/tutorials/2.js b/resources/js/tutorials/2.js index 8832992..fa3bda2 100644 --- a/resources/js/tutorials/2.js +++ b/resources/js/tutorials/2.js @@ -70,8 +70,11 @@ function Intro3() { ;}); intro3.onafterchange(function(e) { if (e.classList.contains('add-attr')) { - introObserve(document.querySelector('.e-body .e-a .add-attr'), "click", - intro3, document.querySelector('.e-body .e-a'), '.e-body .e-a .add-attr', Intro4); + introObserve(false, "=", + false, document.querySelector('.e-body'), '.e-body .e-a .add-attr', function() { + intro3.exit(); + Intro4() + }); } }); } @@ -113,19 +116,10 @@ function Intro4() { } function Intro5() { //prefill img url, using code stolen from blockAttributes.js - var el = document.querySelector('.e-body .e-img .add-attr') - var newAttrString = [ - '', - 'src', - '=', - 'https://33.media.tumblr.com/tumblr_lm7kcfDP2g1qbkjkd.gif', - '' - ].join(''); - var newAttr = stringToHtml(newAttrString); - el.parentNode.parentNode.insertBefore(newAttr, el.parentNode); - - - + var el = document.querySelector('.e-body .e-img'); + var id = el.getAttribute('data-id'); + var block = blocksDatabase[id]; + add_attr(block, 'src', 'https://33.media.tumblr.com/tumblr_lm7kcfDP2g1qbkjkd.gif'); var intro5 = introJs(); From 1d7225c40f71ee0bd161d94a84fd594f8c8dddcc Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 17:41:36 -0600 Subject: [PATCH 21/48] figured out the issues with CSS files --- resources/js/block2json.js | 16 ++++++++++------ resources/js/fileManagement.js | 2 +- resources/js/files.js | 13 +++++++------ 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index f34ef47..11d6b9f 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -7,22 +7,26 @@ if (!String.prototype.startsWith) { // sweet polyfill }; } -function blockTreeToCSS() { - function blockToCSS(block) { +function blockTreeToCSS(blockList) { + function blockToCSS(block) { if(block.name == 'selector') { let out = ''; for(let child of block.children) { out += blockToCSS(child); } - return `${block.inputs[0].value} {\n${out}}\n` + return `${block.inputs[0]} {\n${out}}\n` } else if(block.name == 'rule') { - return ` ${block.inputs[0].value}: ${block.inputs[1].value};\n` + return ` ${block.inputs[0]}: ${block.inputs[1]};\n` } else { - return ''; + let out = ''; + for(let child of block.children) { + out += blockToCSS(child); + } + return out; } } var css = ''; - for(let block of bodyScript.children) { + for(let block of blockList) { css += blockToCSS(block); } return css; diff --git a/resources/js/fileManagement.js b/resources/js/fileManagement.js index e2cf88f..2be7124 100644 --- a/resources/js/fileManagement.js +++ b/resources/js/fileManagement.js @@ -8,7 +8,7 @@ document.getElementById('downloadButton').addEventListener('click', function() { let body = fileData[fileName][0]; // first one should always be body out = blockTreeToHTML(body).outerHTML; } else if(ext == 'css') { - out = blockTreeToCSS(); + out = blockTreeToCSS(fileData[fileName]); } zip.file(fileName, out); } diff --git a/resources/js/files.js b/resources/js/files.js index 51e6f67..28e6522 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -134,13 +134,13 @@ function generateBlocks(jsonData, ext) { return newBlock; } if(ext == 'css') { + clearBlocks(currentFile); + replaceBody(new Draggy()); + BODY.type = 'CSSNullWrapper'; for(let block of jsonData) { let newBlock = generateBlock(block); if(newBlock) { - clearBlocks(currentFile); - replaceBody(new Draggy()); - BODY.type = 'CSSNullWrapper'; - BODY.insertChild(newBlock, -1) + bodyScript.insertChild(newBlock, -1) } } } else if(ext == 'html') { @@ -173,7 +173,6 @@ function loadFile(filename, el) { } currentFile = filename; - var fileJson = fileData[filename]; if (el) { @@ -227,7 +226,9 @@ function blocksToJSON(fileName) { // yeah I know I'm ignoring loose blocks var expArray = []; for(let block of bodyScript.children) { - if(block) expArray.push(block.toStringable()); + if(block.type != 'CSSNullWrapper') { + expArray.push(block.toStringable()); + } } fileData[fileName] = expArray; // fileData[fileName] = [bodyScript.toStringable()]; From c02f4a4a1f0a9870d78bac0e408615e593beb7db Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 22:20:33 -0600 Subject: [PATCH 22/48] limit context menu to blocks in script area --- resources/js/blocks.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/resources/js/blocks.js b/resources/js/blocks.js index a865d5b..d8ae428 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -280,8 +280,7 @@ function Block(type, name, opts) { block.elem.addEventListener('contextmenu', function(ev) { ev.preventDefault(); - - if(opts.unmoveable) return; + if(block.inPalette || block.unmoveable) return false; SCRIPT_MENU.style.display = 'block'; SCRIPT_MENU.style.top = ev.pageY + 'px'; From d20fb48b0e9002389c2dbbeeda7a8de6edb1e13d Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 22:34:55 -0600 Subject: [PATCH 23/48] =?UTF-8?q?fix=20issues=20with=20loose=20blocks=20no?= =?UTF-8?q?t=20being=20JSON=E2=80=99d=20correctly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/files.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/resources/js/files.js b/resources/js/files.js index 28e6522..1038abd 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -109,6 +109,7 @@ function generateBlocks(jsonData, ext) { let newBlock; if(block.type == 'draggy') { newBlock = new Draggy(); + topLevelBlocks.push(newBlock) } else if( block.type == 'stack' || block.type == 'wrapper') { newBlock = new Block(block.type, block.name, { @@ -125,8 +126,7 @@ function generateBlocks(jsonData, ext) { } else { return null; // other types of Draggies are generated in block constructors } - newBlock.x = block.x; - newBlock.y = block.y; + newBlock.setPosition(block.x, block.y); for(let child of block.children) { let newChild = generateBlock(child); if(newChild) newBlock.insertChild(newChild, -1); @@ -137,12 +137,22 @@ function generateBlocks(jsonData, ext) { clearBlocks(currentFile); replaceBody(new Draggy()); BODY.type = 'CSSNullWrapper'; - for(let block of jsonData) { + + let newBodyScript = jsonData[0]; + for(let block of newBodyScript.children) { let newBlock = generateBlock(block); if(newBlock) { bodyScript.insertChild(newBlock, -1) } } + + for(let i = 1, block; i < jsonData.length; i++) { + block = jsonData[i]; + let newBlock = generateBlock(block); + if(newBlock) { + SCRIPTING_AREA.insertBefore(newBlock.elem, SCRIPTING_AREA.firstChild); + } + } } else if(ext == 'html') { let body; for(let block of jsonData) { @@ -159,8 +169,6 @@ function generateBlocks(jsonData, ext) { let newBlock = generateBlock(block); if(newBlock) { SCRIPTING_AREA.insertBefore(newBlock.elem, SCRIPTING_AREA.firstChild); - newBlock.elem.style.left = newBlock.x + 'px'; - newBlock.elem.style.top = newBlock.y + 'px'; } } } @@ -224,9 +232,9 @@ function blocksToJSON(fileName) { fileData[fileName] = expArray; } else if (ext == 'css') { // yeah I know I'm ignoring loose blocks - var expArray = []; - for(let block of bodyScript.children) { - if(block.type != 'CSSNullWrapper') { + var expArray = [bodyScript.toStringable()]; + for(let block of topLevelBlocks) { + if(block != BODY && block.type != 'CSSNullWrapper') { expArray.push(block.toStringable()); } } From e89a78d007e7c26c5d37b203cc0b61646d5ee1fa Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 22:57:47 -0600 Subject: [PATCH 24/48] rename a whole bunch of things --- index.html | 2 +- resources/js/block2json.js | 18 +++--- resources/js/blockFilter.js | 102 ++++++++++++++++----------------- resources/js/blocks.js | 92 +++++++++++++++-------------- resources/js/fileManagement.js | 11 +++- resources/js/files.js | 24 ++++---- 6 files changed, 126 insertions(+), 123 deletions(-) diff --git a/index.html b/index.html index e02a94e..d99e225 100644 --- a/index.html +++ b/index.html @@ -191,7 +191,7 @@
      -
      • DOCTYPE html
      +
      • DOCTYPE html
      diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 11d6b9f..52ec3f1 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -7,12 +7,12 @@ if (!String.prototype.startsWith) { // sweet polyfill }; } -function blockTreeToCSS(blockList) { - function blockToCSS(block) { +function blockToCSS(blockList) { + function blockToCSS_(block) { if(block.name == 'selector') { let out = ''; for(let child of block.children) { - out += blockToCSS(child); + out += blockToCSS_(child); } return `${block.inputs[0]} {\n${out}}\n` } else if(block.name == 'rule') { @@ -20,20 +20,20 @@ function blockTreeToCSS(blockList) { } else { let out = ''; for(let child of block.children) { - out += blockToCSS(child); + out += blockToCSS_(child); } return out; } } var css = ''; for(let block of blockList) { - css += blockToCSS(block); + css += blockToCSS_(block); } return css; } -function blockTreeToHTML(block) { - if(block.type !== 'stack' && block.type !== 'wrapper') { +function blockToHTML(block) { + if(block.type !== 'stack' && block.type !== 'cblock') { return null; } else if(block.name == 'text') { return document.createTextNode(block.inputs[0].value); @@ -43,7 +43,7 @@ function blockTreeToHTML(block) { if(attr.name.trim() && attr.value.trim()) element.setAttribute(attr.name, attr.value); } for(let child of block.children) { - let parsedChild = blockTreeToHTML(child); + let parsedChild = blockToHTML(child); if(parsedChild) element.appendChild(parsedChild); } return element; @@ -57,7 +57,7 @@ function setFrameContent(ext) { if (ext == 'css') { blocksToJSON(currentFile); } else if (ext == 'html') { - var parsedHtml = blockTreeToHTML(BODY); + var parsedHtml = blockToHTML(BODY); blocksToJSON(currentFile); var previewWindow = previewElement; diff --git a/resources/js/blockFilter.js b/resources/js/blockFilter.js index e32feaa..a75a3be 100644 --- a/resources/js/blockFilter.js +++ b/resources/js/blockFilter.js @@ -35,7 +35,7 @@ var filter = { for(x = 0; x < blocksToDisplay.length; x++) { var block = filter.blocks[blocksToDisplay[x]]; var newBlock; - if (block.type == 'wrapper') { + if (block.type == 'cblock') { if (!block.ftype || block.ftype == 'html') { newBlock = new Block(block.type, block.name, { hasAttrs: true, @@ -107,145 +107,145 @@ var filter = { }, { name: 'h1', - type: 'wrapper', + type: 'cblock', tags: ['heading', 'h1'], palette: 0 }, { name: 'h2', - type: 'wrapper', + type: 'cblock', tags: ['heading', 'h2'], palette: 0 }, { name: 'h3', - type: 'wrapper', + type: 'cblock', tags: ['heading', 'h3'], palette: 0 }, { name: 'p', - type: 'wrapper', + type: 'cblock', tags: ['p', 'paragraph'], palette: 0 }, { name: 'span', - type: 'wrapper', + type: 'cblock', tags: ['span'], palette: 0 }, { name: 'pre', - type: 'wrapper', + type: 'cblock', tags: ['pre', 'code'], palette: 0 }, { name: 'code', - type: 'wrapper', + type: 'cblock', tags: ['code'], palette: 0 }, { name: 'a', - type: 'wrapper', + type: 'cblock', tags: ['link', 'a'], palette: 0 }, { name: 'abbr', - type: 'wrapper', + type: 'cblock', tags: ['abbrevation', 'abbr'], palette: 0 }, { name: 'b', - type: 'wrapper', + type: 'cblock', tags: ['bold', 'b'], palette: 0 }, { name: 'i', - type: 'wrapper', + type: 'cblock', tags: ['italics', 'i'], palette: 0 }, { name: 'strong', - type: 'wrapper', + type: 'cblock', tags: ['strong'], palette: 0 }, { name: 'em', - type: 'wrapper', + type: 'cblock', tags: ['em', 'emphasis'], palette: 0 }, { name: 'mark', - type: 'wrapper', + type: 'cblock', tags: ['marker', 'mark', 'highlighted'], palette: 0 }, { name: 'del', - type: 'wrapper', + type: 'cblock', tags: ['deleted', 'del', 'update', 'edit'], palette: 0 }, { name: 'ins', - type: 'wrapper', + type: 'cblock', tags: ['inserted', 'ins', 'update', 'edit'], palette: 0 }, { name: 'sub', - type: 'wrapper', + type: 'cblock', tags: ['subtext', 'sub'], palette: 0 }, { name: 'sup', - type: 'wrapper', + type: 'cblock', tags: ['supertext', 'sup'], palette: 0 }, { name: 'kbd', - type: 'wrapper', + type: 'cblock', tags: ['keyboard', 'input', 'kbd'], palette: 0 }, { name: 'samp', - type: 'wrapper', + type: 'cblock', tags: ['sample', 'output', 'samp'], palette: 0 }, { name: 'var', - type: 'wrapper', + type: 'cblock', tags: ['variable', 'var'], palette: 0 }, { name: 'ol', - type: 'wrapper', + type: 'cblock', tags: ['lists', 'ordered list', 'ol'], palette: 0 }, { name: 'ul', - type: 'wrapper', + type: 'cblock', tags: ['lists', 'unordered list', 'ul'], palette: 0 }, { name: 'li', - type: 'wrapper', + type: 'cblock', tags: ['lists', 'list item', 'li'], palette: 0 }, @@ -265,19 +265,19 @@ var filter = { }, { name: 'audio', - type: 'wrapper', + type: 'cblock', tags: ['audio'], palette: 1 }, { name: 'video', - type: 'wrapper', + type: 'cblock', tags: ['video'], palette: 1 }, { name: 'object', - type: 'wrapper', + type: 'cblock', tags: ['object', 'flash', 'plugin'], palette: 1 }, @@ -303,25 +303,25 @@ var filter = { /* Blocks for palette 2 - Sections */ { name: 'div', - type: 'wrapper', + type: 'cblock', tags: ['div', 'divider', 'separator'], palette: 2 }, { name: 'navigation', - type: 'wrapper', + type: 'cblock', tags: ['nav', 'navigation'], palette: 2 }, { name: 'footer', - type: 'wrapper', + type: 'cblock', tags: ['footer', 'foot' /* can i addz feet plz?*/], palette: 2 }, { name: 'article', - type: 'wrapper', + type: 'cblock', tags: ['article'], palette: 2 }, @@ -329,61 +329,61 @@ var filter = { /* Blocks for palette 3 - Tables */ { name: 'table', - type: 'wrapper', + type: 'cblock', tags: ['table'], palette: 3 }, { name: 'caption', - type: 'wrapper', + type: 'cblock', tags: ['table', 'caption', 'title'], palette: 3 }, { name: 'tbody', - type: 'wrapper', + type: 'cblock', tags: ['table', 'body', 'tbody'], palette: 3 }, { name: 'thead', - type: 'wrapper', + type: 'cblock', tags: ['table', 'head', 'header', 'thead'], palette: 3 }, { name: 'tfoot', - type: 'wrapper', + type: 'cblock', tags: ['table', 'foot', 'footer', 'tfoot'], palette: 3 }, { name: 'tr', - type: 'wrapper', + type: 'cblock', tags: ['table', 'row', 'tr'], palette: 3 }, { name: 'td', - type: 'wrapper', + type: 'cblock', tags: ['table', 'cell', 'td'], palette: 3 }, { name: 'th', - type: 'wrapper', + type: 'cblock', tags: ['table', 'cell', 'th', 'head', 'header'], palette: 3 }, { name: 'col', - type: 'wrapper', + type: 'cblock', tags: ['table', 'column', 'col'], palette: 3 }, { name: 'colgroup', - type: 'wrapper', + type: 'cblock', tags: ['table', 'column', 'colgroup'], palette: 3 }, @@ -391,7 +391,7 @@ var filter = { /* Blocks for palette 4 - forms */ { name: 'form', - type: 'wrapper', + type: 'cblock', tags: ['forms', 'form'], palette: 4 }, @@ -403,43 +403,43 @@ var filter = { }, { name: 'output', - type: 'wrapper', + type: 'cblock', tags: ['forms', 'output'], palette: 4 }, { name: 'button', - type: 'wrapper', + type: 'cblock', tags: ['forms', 'button'], palette: 4 }, { name: 'select', - type: 'wrapper', + type: 'cblock', tags: ['forms', 'options', 'select'], palette: 4 }, { name: 'option', - type: 'wrapper', + type: 'cblock', tags: ['forms', 'options', 'option'], palette: 4 }, { name: 'datalist', - type: 'wrapper', + type: 'cblock', tags: ['forms', 'options', 'datalist'], palette: 4 }, { name: 'fieldset', - type: 'wrapper', + type: 'cblock', tags: ['forms', 'fieldset', 'fields'], palette: 4 }, { name: 'legend', - type: 'wrapper', + type: 'cblock', tags: ['forms', 'fields', 'legend'], palette: 4 }, @@ -447,7 +447,7 @@ var filter = { /* Blocks for CSS */ { name: 'selector', - type: 'wrapper', + type: 'cblock', tags: ['selection', 'selector'], palette: 7, ftype: 'css' diff --git a/resources/js/blocks.js b/resources/js/blocks.js index d8ae428..a46a122 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -13,10 +13,10 @@ replaceBody(); // a more generic abstraction of a block // it can have children, so it can be a script -function Draggy(inPalette) { +function BlockWrapper(inPalette) { this.x = 0; this.y = 0; - this.type = 'draggy'; + this.type = 'blockWrapper'; this.id = blocksCount++; blocksDatabase[this.id] = this; this.parent = null; @@ -53,7 +53,7 @@ function Draggy(inPalette) { block.parent.children.splice(block.parent.children.indexOf(block), 1); block.parent = null; }; - this.deleteDraggy = function() { + this.deleteBlock = function() { block.removeFromParent(); block.elem.parentElement.removeChild(block.elem); blocksDatabase[block.id] = null; @@ -69,7 +69,7 @@ function Draggy(inPalette) { minDistance; blocks: for(let oblock of scriptBlocks) { if (!oblock - || oblock.type == 'draggy' + || oblock.type == 'blockWrapper' || oblock.unmoveable) continue blocks; // check for descendancy let pblock = block; @@ -90,7 +90,7 @@ function Draggy(inPalette) { dy = oblock.bottom() - block.top(); // move point inside c-blocks to the right - if(oblock.type == 'nullWrapperContent') { + if(oblock.type == 'cblockStart') { dx += oblock.content.style.paddingLeft; } @@ -185,7 +185,7 @@ opts = { */ function Block(type, name, opts) { if(!opts) opts = {}; - Draggy.apply(this, [opts.inPalette]); + BlockWrapper.apply(this, [opts.inPalette]); this.type = type; this.name = name; this.ftype = opts.ftype || 'html'; @@ -194,7 +194,7 @@ function Block(type, name, opts) { this.inPalette = (opts.inPalette !== undefined) ? opts.inPalette : true; this.unmoveable = opts.unmoveable || false; var block = this; - if(type == 'wrapper') { + if(type == 'cblock') { this.elem = document.createElement('ul'); this.elem.classList.add('c-wrapper'); @@ -202,11 +202,11 @@ function Block(type, name, opts) { this.header.classList.add('c-header'); this.elem.appendChild(this.header); - // add a blank draggy inside wrapper - var nullWrapperContent = new Draggy(this.inPalette); - nullWrapperContent.type = 'nullWrapperContent'; - this.insertChild(nullWrapperContent, -1); - nullWrapperContent.elem = nullWrapperContent.content = this.header; + // add a blank blockWrapper inside cblock + var cblockStart = new BlockWrapper(this.inPalette); + cblockStart.type = 'cblockStart'; + this.insertChild(cblockStart, -1); + cblockStart.elem = cblockStart.content = this.header; this.content = document.createElement('ul'); this.content.classList.add('c-content'); @@ -337,7 +337,7 @@ function Block(type, name, opts) { } } -Block.prototype = Object.create(Draggy.prototype); +Block.prototype = Object.create(BlockWrapper.prototype); Block.prototype.constructor = Block.constructor; function BlockInput(defaultValue) { @@ -436,21 +436,21 @@ function _drag_init(block, ev) { var relativeX = ev.pageX - block.left(); var relativeY = ev.pageY - block.top(); // Store the object of the element which needs to be moved - var draggy = new Draggy() - SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); + var blockWrapper = new BlockWrapper() + SCRIPTING_AREA.insertBefore(blockWrapper.elem, SCRIPTING_AREA.firstChild); var curX = ev.pageX - getOffset(SCRIPTING_AREA).left, curY = ev.pageY - getOffset(SCRIPTING_AREA).top; - topLevelBlocks.push(draggy); + topLevelBlocks.push(blockWrapper); var parent = block.parent; var kids = parent.children.slice(block.getIndex()); for(let child of kids) { child.removeFromParent(); - draggy.insertChild(child, -1); + blockWrapper.insertChild(child, -1); child.elem.removeAttribute('style'); } - if(parent.children.length == 0 && parent.type == 'draggy') parent.deleteDraggy(); - draggy.setPosition(curX - relativeX, curY - relativeY); - selected = draggy; + if(parent.children.length == 0 && parent.type == 'blockWrapper') parent.deleteBlock(); + blockWrapper.setPosition(curX - relativeX, curY - relativeY); + selected = blockWrapper; dragOffset.x = mousePos.x - selected.elem.offsetLeft; dragOffset.y = mousePos.y - selected.elem.offsetTop; } @@ -464,16 +464,16 @@ function _palette_drag_init(block, ev) { var newElem = newBlock.elem; newElem.classList.remove('paletteBlock'); // Store the object of the element which needs to be moved - var draggy = new Draggy(); - topLevelBlocks.push(draggy); - SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); + var blockWrapper = new BlockWrapper(); + topLevelBlocks.push(blockWrapper); + SCRIPTING_AREA.insertBefore(blockWrapper.elem, SCRIPTING_AREA.firstChild); selected = newElem; selectedBlock = newBlock; var curX = ev.clientY - getOffset(SCRIPTING_AREA).left, curY = ev.clientY - getOffset(SCRIPTING_AREA).top; - draggy.insertChild(selectedBlock, -1); - draggy.setPosition(curX - relativeX, curY - relativeY); - selected = draggy; + blockWrapper.insertChild(selectedBlock, -1); + blockWrapper.setPosition(curX - relativeX, curY - relativeY); + selected = blockWrapper; dragOffset.x = mousePos.x - selected.elem.offsetLeft; dragOffset.y = mousePos.y - selected.elem.offsetTop; } @@ -487,8 +487,8 @@ function _move_elem(e) { if (selected !== null) { var el = selected.getClosestBlock(); if (el !== null) { - if(el.type == 'CSSNullWrapper') { - document.querySelector('#bodyScript > li.hat').classList.add('drop-area'); + if(el.type == 'CSSStart') { + document.querySelector('#mainScript > li.hat').classList.add('drop-area'); } else { el.elem.classList.add('drop-area'); } @@ -508,11 +508,11 @@ function _destroy(ev) { for(let child of kids) { child.removeFromParent(); child.elem.removeAttribute('style'); - if(topEl.type == 'nullWrapperContent') { - topEl.parent.insertChild(child, 1); // 0 is the null Draggy + if(topEl.type == 'cblockStart') { + topEl.parent.insertChild(child, 1); // 0 is the null BlockWrapper } else if(topEl.type == 'stack' - || topEl.type == 'wrapper' - || topEl.type == 'CSSNullWrapper') { + || topEl.type == 'cblock' + || topEl.type == 'CSSStart') { topEl.parent.insertChild(child, topEl.getIndex() + 1); } } @@ -593,27 +593,26 @@ function clearBlocks(hat) { scriptBlocks = []; topLevelBlocks = []; let child; - if(BODY) BODY.deleteDraggy(); - BODY = bodyScript = undefined; - SCRIPTING_AREA.innerHTML = `
      • ${hat || 'DOCTYPE html'}
      `; + if(BODY) BODY.deleteBlock(); + BODY = mainScript = undefined; + SCRIPTING_AREA.innerHTML = `
      • ${hat || 'DOCTYPE html'}
      `; } -var BODY, bodyScript; +var BODY, mainScript; function replaceBody(bodyBlock) { - bodyScript = new Draggy(); - bodyScript.elem = bodyScript.content = document.querySelector('#bodyScript'); + mainScript = new BlockWrapper(); + mainScript.elem = mainScript.content = document.querySelector('#mainScript'); if(bodyBlock) { BODY = bodyBlock; } else { - BODY = new Block('wrapper', 'body', { + BODY = new Block('cblock', 'body', { hasAttrs: true, hasQuickText: true, - scriptInputContent: null, inPalette: false, unmoveable: true }); } - bodyScript.insertChild(BODY, -1); + mainScript.insertChild(BODY, -1); topLevelBlocks.push(BODY); } @@ -676,20 +675,19 @@ $('.context-menu.scripts .menu-item').on('click', function(ev) { case 'duplicate-script': // do stuff with node... and get stuff beneath it too! var target = RIGHT_CLICKED_SCRIPT; - var draggy = new Draggy(); - SCRIPTING_AREA.insertBefore(draggy.elem, SCRIPTING_AREA.firstChild); - topLevelBlocks.push(draggy); + var blockWrapper = new BlockWrapper(); + SCRIPTING_AREA.insertBefore(blockWrapper.elem, SCRIPTING_AREA.firstChild); + topLevelBlocks.push(blockWrapper); for(let i = target.getIndex(); i < target.parent.children.length; i++) { let child = target.parent.children[i]; - draggy.insertChild(child.clone(false), -1); + blockWrapper.insertChild(child.clone(false), -1); } var relativeX = ev.pageX - target.left(); var relativeY = ev.pageY - target.top(); var curX = ev.pageX - getOffset(SCRIPTING_AREA).left, curY = ev.pageY - getOffset(SCRIPTING_AREA).top; - draggy.elem.style.left = curX - relativeX + 25 + 'px'; - draggy.elem.style.top = curY - relativeY + 25 + 'px'; + blockWrapper.setPosition(curX - relativeX + 25, curY - relativeY + 25) setZebra(); RIGHT_CLICKED_SCRIPT = undefined; diff --git a/resources/js/fileManagement.js b/resources/js/fileManagement.js index 2be7124..7c2f9c6 100644 --- a/resources/js/fileManagement.js +++ b/resources/js/fileManagement.js @@ -3,12 +3,17 @@ document.getElementById('downloadButton').addEventListener('click', function() { var jsonFiles = zip.folder('.elem'); for(let fileName in fileData) { let ext = getExt(fileName); - let out = ''; + let out; if(ext == 'html') { + out = `\n`; let body = fileData[fileName][0]; // first one should always be body - out = blockTreeToHTML(body).outerHTML; + out += blockToHTML(body).outerHTML; + out += ''; } else if(ext == 'css') { - out = blockTreeToCSS(fileData[fileName]); + out = blockToCSS(fileData[fileName]); + } else { + console.log('Can\'t export files of type ' + ext); + continue; } zip.file(fileName, out); } diff --git a/resources/js/files.js b/resources/js/files.js index 1038abd..c04fd76 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -80,7 +80,7 @@ var cssAttrNames = [ var stackElements = []; var wrapperElements = []; filter.blocks.forEach(function(block) { - if (block.type === 'wrapper') { + if (block.type === 'cblock') { wrapperElements.push('e-' + block.name); } else if (block.type === 'stack') { stackElements.push('e-' + block.name); @@ -107,11 +107,11 @@ function generateBlocks(jsonData, ext) { function generateBlock(block) { if(!block.type) return null; let newBlock; - if(block.type == 'draggy') { - newBlock = new Draggy(); + if(block.type == 'blockWrapper') { + newBlock = new BlockWrapper(); topLevelBlocks.push(newBlock) } else if( block.type == 'stack' - || block.type == 'wrapper') { + || block.type == 'cblock') { newBlock = new Block(block.type, block.name, { hasAttrs: block.hasAttrs, hasQuickText: block.hasQuickText, @@ -135,14 +135,14 @@ function generateBlocks(jsonData, ext) { } if(ext == 'css') { clearBlocks(currentFile); - replaceBody(new Draggy()); - BODY.type = 'CSSNullWrapper'; + replaceBody(new BlockWrapper()); + BODY.type = 'CSSStart'; let newBodyScript = jsonData[0]; for(let block of newBodyScript.children) { let newBlock = generateBlock(block); if(newBlock) { - bodyScript.insertChild(newBlock, -1) + mainScript.insertChild(newBlock, -1) } } @@ -232,14 +232,14 @@ function blocksToJSON(fileName) { fileData[fileName] = expArray; } else if (ext == 'css') { // yeah I know I'm ignoring loose blocks - var expArray = [bodyScript.toStringable()]; + var expArray = [mainScript.toStringable()]; for(let block of topLevelBlocks) { - if(block != BODY && block.type != 'CSSNullWrapper') { + if(block != BODY && block.type != 'CSSStart') { expArray.push(block.toStringable()); } } fileData[fileName] = expArray; - // fileData[fileName] = [bodyScript.toStringable()]; + // fileData[fileName] = [mainScript.toStringable()]; } } @@ -268,8 +268,8 @@ function generateFile(fileName) { replaceBody(); } else if (ext == 'css') { clearBlocks(currentFile); - replaceBody(new Draggy()); - BODY.type = 'CSSNullWrapper'; + replaceBody(new BlockWrapper()); + BODY.type = 'CSSStart'; } else { throw 'File type "' + ext + '" not supported.'; } From 782dd42852cdb3f83027434f6eb04b55eff7eef8 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Thu, 13 Apr 2017 23:52:53 -0600 Subject: [PATCH 25/48] add default blocks to new CSS files --- resources/js/files.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/resources/js/files.js b/resources/js/files.js index c04fd76..fd2259f 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -270,6 +270,25 @@ function generateFile(fileName) { clearBlocks(currentFile); replaceBody(new BlockWrapper()); BODY.type = 'CSSStart'; + + // add default blocks + let defaultSelector = new Block('cblock', 'selector', { + hasAttrs: false, + hasQuickText: false, + inputs: ['.selector'], + inPalette: true, + ftype: 'css' + }); + mainScript.insertChild(defaultSelector, -1); + + let defaultRule = new Block('stack', 'rule', { + hasAttrs: false, + hasQuickText: false, + inputs: ['background-color', 'red'], + inPalette: true, + ftype: 'css' + }); + defaultSelector.insertChild(defaultRule, -1); } else { throw 'File type "' + ext + '" not supported.'; } From 7e2bc4933bca299783d73da310eb9a237f3fc90e Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Fri, 14 Apr 2017 01:10:00 -0600 Subject: [PATCH 26/48] refactor dropdown code and add to rule block --- index.html | 2 +- resources/js/blockAttributes.js | 129 ++++++++++++++------------------ resources/js/blocks.js | 7 +- resources/js/files.js | 17 ----- 4 files changed, 64 insertions(+), 91 deletions(-) diff --git a/index.html b/index.html index d99e225..d7ba5e6 100644 --- a/index.html +++ b/index.html @@ -200,7 +200,7 @@ - + diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index b2116f7..da94830 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -1,9 +1,3 @@ -var ATTRIBUTE_MENU = document.getElementById('blockAttributeDropdown'); -var ATTRIBUTE_SEARCH = document.getElementById('propSearch'); -var ATTRIBUTE_RESULTS = document.getElementById('attributeResults'); - -var CLICKED_ATTR; - // both optional function Attr(name, value) { this.elem = document.createElement('span'); @@ -30,46 +24,9 @@ function Attr(name, value) { attr.value = attr.input.textContent; }); - this.dropdown.addEventListener('click', function(e) { - ATTRIBUTE_MENU.classList.remove('hidden'); - ATTRIBUTE_MENU.style.top = attr.top() + attr.elem.offsetHeight + 'px'; - ATTRIBUTE_MENU.style.left = attr.left() + 'px'; - CLICKED_ATTR = attr; - - ATTRIBUTE_SEARCH.focus(); - setTimeout(function() { - document.body.addEventListener('click', function dropdown_blur(e2) { - ATTRIBUTE_MENU.classList.add('hidden'); - CLICKED_ATTR = null; - document.body.removeEventListener('click', dropdown_blur); - attr.name = attr.dropdown.textContent; - }); - }, 0); - }); - - this.left = function() { - var elem = attr.elem; - var offsetLeft = 0; - do { - if ( !isNaN( elem.offsetLeft ) ) - { - offsetLeft += elem.offsetLeft; - } - } while( elem = elem.offsetParent ); - return offsetLeft; - }; - - this.top = function() { - var elem = attr.elem; - var offsetTop = 0; - do { - if ( !isNaN( elem.offsetTop ) ) - { - offsetTop += elem.offsetTop; - } - } while( elem = elem.offsetParent ); - return offsetTop; - }; + attachAttrSearch(attr.dropdown, htmlAttrNames, function(value) { + attr.name = attr.dropdown.textContent = value; + }) this.toStringable = function() { return { @@ -89,33 +46,61 @@ function remove_attr(block) { block.header.removeChild(attr.elem); } -// uses array called attrNames... +function attachAttrSearch(elem, attrNames, callback) { + var ATTRIBUTE_MENU = document.getElementById('blockAttributeDropdown'); + var ATTRIBUTE_SEARCH = document.getElementById('propSearch'); + var ATTRIBUTE_RESULTS = document.getElementById('attributeResults'); + + elem.addEventListener('click', function() { + ATTRIBUTE_MENU.classList.remove('hidden'); + ATTRIBUTE_MENU.style.top = getOffset(elem).bottom + 'px'; + ATTRIBUTE_MENU.style.left = getOffset(elem).left + 'px'; + + ATTRIBUTE_SEARCH.focus(); + + setTimeout(function() { // if the listener is added immediately it fires immediately + document.body.addEventListener('click', function(ev) { + if(ev.target.matches('.attrResult')) callback(ev.target.textContent); + + ATTRIBUTE_MENU.classList.add('hidden'); + ATTRIBUTE_SEARCH.removeEventListener('keyup', attrSearch); + ATTRIBUTE_SEARCH.removeEventListener('paste', attrSearch); + }, {once: true}); + }, 0) + + function attrSearch(ev) { + var searchString = (ev ? ev.target.value : ''); + var validAttrs = attrNames.filter(function(attr) { + return attr.indexOf(searchString) > -1; + }); + var newHtml = []; + for (var i = 0; i < validAttrs.length; i++) { + var attrName = validAttrs[i]; + newHtml.push('
    • ' + attrName + '
    • '); + } + newHtml = newHtml.join(''); + ATTRIBUTE_RESULTS.innerHTML = newHtml; + } -function attrSearch(ev) { - var searchString = ev.target.value; - var validAttrs = attrNames.filter(function(attr) { - return attr.indexOf(searchString) > -1; + ATTRIBUTE_SEARCH.addEventListener('keyup', attrSearch); + ATTRIBUTE_SEARCH.addEventListener('paste', attrSearch); + attrSearch() // initialize list }); - var newHtml = []; - for (var i = 0; i < validAttrs.length; i++) { - var attrName = validAttrs[i]; - newHtml.push('
    • ' + attrName + '
    • '); - } - newHtml = newHtml.join(''); - ATTRIBUTE_RESULTS.innerHTML = newHtml; } -ATTRIBUTE_SEARCH.addEventListener('keyup', attrSearch); -ATTRIBUTE_SEARCH.addEventListener('paste', attrSearch); - -ATTRIBUTE_RESULTS.addEventListener('click', function(ev) { - var attr = ev.target.textContent; - CLICKED_ATTR.dropdown.textContent = attr; -}); - -// initialize the stuff in the menu -var attrString = ''; -for (var i = 0; i < attrNames.length; i++) { - attrString += '
    • ' + attrNames[i] + '
    • '; -} -ATTRIBUTE_RESULTS.innerHTML = attrString; +var htmlAttrNames = [ + 'class', + 'for', + 'form', + 'href', + 'id', + 'rel', + 'src', + 'style', + 'type' +]; //add attrs +var cssAttrNames = [ + 'background-color', + 'height', + 'width' +]; //add attrs diff --git a/resources/js/blocks.js b/resources/js/blocks.js index a46a122..2df8d9a 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -263,7 +263,12 @@ function Block(type, name, opts) { if (opts.inputs.length == 1) { // text and selector (new BlockInput(opts.inputs[0])).attachToBlock(block); } else if (opts.inputs.length == 2) { // rule - (new BlockInput(opts.inputs[0])).attachToBlock(block); + let dropdown = new BlockInput(opts.inputs[0]); + dropdown.attachToBlock(block); + attachAttrSearch(dropdown.elem, cssAttrNames, function(value) { + dropdown.elem.textContent = dropdown.value = value; + }) + this.header.appendChild(document.createTextNode(':\u00A0')); (new BlockInput(opts.inputs[1])).attachToBlock(block); } diff --git a/resources/js/files.js b/resources/js/files.js index fd2259f..cdee934 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -56,23 +56,6 @@ var fileData = {}; var fileNames = ['index.html']; // make this work later var currentFile = 'index.html'; -var attrNames = [ - 'class', - 'for', - 'form', - 'href', - 'id', - 'rel', - 'src', - 'style', - 'type' -]; //add attrs -var cssAttrNames = [ - 'background-color', - 'height', - 'width' -]; //add attrs - // All you have to do to do it right is be lazy -- liam // (just kidding) //var stackElements = ['e-img', 'e-text', 'e-CSS', 'e-style', ]; From 8d1effb3c53584a0044bae44abfc86e74c6aefb1 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Fri, 14 Apr 2017 01:13:07 -0600 Subject: [PATCH 27/48] =?UTF-8?q?rename=20Attr=20to=20BlockAttribute=20to?= =?UTF-8?q?=20match=20other=20constructors=E2=80=99=20snooty=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/blockAttributes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index da94830..7fe91fc 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -1,5 +1,5 @@ // both optional -function Attr(name, value) { +function BlockAttribute(name, value) { this.elem = document.createElement('span'); this.elem.classList.add('attr-holder'); @@ -37,7 +37,7 @@ function Attr(name, value) { } function add_attr(block, name, value) { - var attr = new Attr(name, value); + var attr = new BlockAttribute(name, value); block.header.insertBefore(attr.elem, block.attrControls); block.attrs.push(attr); } From 75940376b927f0b4588e5a64b02715153c66692e Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Fri, 14 Apr 2017 17:24:12 -0600 Subject: [PATCH 28/48] remove old files --- index.html | 4 - resources/js/cssAttributes.js | 59 ------ resources/js/vendor/cssjson.js | 224 --------------------- resources/js/vendor/htmljson.js | 178 ----------------- resources/js/vendor/htmlparser.js | 316 ------------------------------ 5 files changed, 781 deletions(-) delete mode 100644 resources/js/cssAttributes.js delete mode 100644 resources/js/vendor/cssjson.js delete mode 100644 resources/js/vendor/htmljson.js delete mode 100644 resources/js/vendor/htmlparser.js diff --git a/index.html b/index.html index d7ba5e6..c438ef2 100644 --- a/index.html +++ b/index.html @@ -4,12 +4,9 @@ UI v0.0.4 | Elemental - - - @@ -200,7 +197,6 @@ - diff --git a/resources/js/cssAttributes.js b/resources/js/cssAttributes.js deleted file mode 100644 index c535be8..0000000 --- a/resources/js/cssAttributes.js +++ /dev/null @@ -1,59 +0,0 @@ -var CSS_ATTRIBUTE_MENU = document.getElementById('cssAttributeDropdown'); -var CSS_ATTRIBUTE_SEARCH = document.getElementById('cssPropSearch'); -var CSS_ATTRIBUTE_RESULTS = document.getElementById('cssAttributeResults'); - -var CSS_CLICKED_ATTR; - -SCRIPTING_AREA.addEventListener('click', function(ev) { - var el = ev.target; - - // Check if click was on the first input of an attribute - if (ev.target.classList.contains('css-attr-dropdown')) { - - // If so, display the searchable dropdown used for attributes - CSS_ATTRIBUTE_MENU.classList.remove('hidden'); - - // Position dropdown based on input location - CSS_ATTRIBUTE_MENU.style.top = getOffset(el).top + el.offsetHeight + 'px'; - CSS_ATTRIBUTE_MENU.style.left = getOffset(el).left + 'px'; - CSS_CLICKED_ATTR = ev.target; - - ATTRIBUTE_SEARCH.focus(); // Give focus to search input so user can type without clicking - } else { - - // If click was not in one of the previously specified places, hide the dropdown (won't do anything if it was already hidden) - CSS_ATTRIBUTE_MENU.classList.add('hidden'); - CSS_CLICKED_ATTR = null; - } -}); - -// uses array called cssAttrNames... - -function attrSearch(ev) { - var searchString = ev.target.value; - var validAttrs = cssAttrNames.filter(function(attr) { - return attr.indexOf(searchString) > -1; - }); - var newHtml = []; - for (var i = 0; i < validAttrs.length; i++) { - var attrName = validAttrs[i]; - newHtml.push('
    • ' + attrName + '
    • '); - } - newHtml = newHtml.join(''); - CSS_ATTRIBUTE_RESULTS.innerHTML = newHtml; -} - -CSS_ATTRIBUTE_SEARCH.addEventListener('keyup', attrSearch); -CSS_ATTRIBUTE_SEARCH.addEventListener('paste', attrSearch); - -CSS_ATTRIBUTE_RESULTS.addEventListener('click', function(ev) { - var attr = ev.target.textContent; - CSS_CLICKED_ATTR.textContent = attr; -}); - -// initialize the stuff in the menu -var cssAttrString = ''; -for (var i = 0; i < cssAttrNames.length; i++) { - cssAttrString += '
    • ' + cssAttrNames[i] + '
    • '; -} -CSS_ATTRIBUTE_RESULTS.innerHTML = cssAttrString; \ No newline at end of file diff --git a/resources/js/vendor/cssjson.js b/resources/js/vendor/cssjson.js deleted file mode 100644 index 5540289..0000000 --- a/resources/js/vendor/cssjson.js +++ /dev/null @@ -1,224 +0,0 @@ -/** - * CSS-JSON Converter for JavaScript - * Converts CSS to JSON and back. - * Version 2.1 - * - * Released under the MIT license. - * - * Copyright (c) 2013 Aram Kocharyan, http://aramk.com/ - - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated - documentation files (the "Software"), to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and - to permit persons to whom the Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial portions - of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO - THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ - -var CSSJSON = new function () { - - var base = this; - - base.init = function () { - // String functions - String.prototype.trim = function () { - return this.replace(/^\s+|\s+$/g, ''); - }; - - String.prototype.repeat = function (n) { - return new Array(1 + n).join(this); - }; - }; - base.init(); - - var selX = /([^\s\;\{\}][^\;\{\}]*)\{/g; - var endX = /\}/g; - var lineX = /([^\;\{\}]*)\;/g; - var commentX = /\/\*[\s\S]*?\*\//g; - var lineAttrX = /([^\:]+):([^\;]*);/; - - // This is used, a concatenation of all above. We use alternation to - // capture. - var altX = /(\/\*[\s\S]*?\*\/)|([^\s\;\{\}][^\;\{\}]*(?=\{))|(\})|([^\;\{\}]+\;(?!\s*\*\/))/gmi; - - // Capture groups - var capComment = 1; - var capSelector = 2; - var capEnd = 3; - var capAttr = 4; - - var isEmpty = function (x) { - return typeof x == 'undefined' || x.length == 0 || x == null; - }; - - /** - * Input is css string and current pos, returns JSON object - * - * @param cssString - * The CSS string. - * @param args - * An optional argument object. ordered: Whether order of - * comments and other nodes should be kept in the output. This - * will return an object where all the keys are numbers and the - * values are objects containing "name" and "value" keys for each - * node. comments: Whether to capture comments. split: Whether to - * split each comma separated list of selectors. - */ - base.toJSON = function (cssString, args) { - var node = { - children: {}, - attributes: {} - }; - var match = null; - var count = 0; - - if (typeof args == 'undefined') { - var args = { - ordered: false, - comments: false, - stripComments: false, - split: false - }; - } - if (args.stripComments) { - args.comments = false; - cssString = cssString.replace(commentX, ''); - } - - while ((match = altX.exec(cssString)) != null) { - if (!isEmpty(match[capComment]) && args.comments) { - // Comment - var add = match[capComment].trim(); - node[count++] = add; - } else if (!isEmpty(match[capSelector])) { - // New node, we recurse - var name = match[capSelector].trim(); - // This will return when we encounter a closing brace - var newNode = base.toJSON(cssString, args); - if (args.ordered) { - var obj = {}; - obj['name'] = name; - obj['value'] = newNode; - // Since we must use key as index to keep order and not - // name, this will differentiate between a Rule Node and an - // Attribute, since both contain a name and value pair. - obj['type'] = 'rule'; - node[count++] = obj; - } else { - if (args.split) { - var bits = name.split(','); - } else { - var bits = [name]; - } - for (i in bits) { - var sel = bits[i].trim(); - if (sel in node.children) { - for (var att in newNode.attributes) { - node.children[sel].attributes[att] = newNode.attributes[att]; - } - } else { - node.children[sel] = newNode; - } - } - } - } else if (!isEmpty(match[capEnd])) { - // Node has finished - return node; - } else if (!isEmpty(match[capAttr])) { - var line = match[capAttr].trim(); - var attr = lineAttrX.exec(line); - if (attr) { - // Attribute - var name = attr[1].trim(); - var value = attr[2].trim(); - if (args.ordered) { - var obj = {}; - obj['name'] = name; - obj['value'] = value; - obj['type'] = 'attr'; - node[count++] = obj; - } else { - if (name in node.attributes) { - var currVal = node.attributes[name]; - if (!(currVal instanceof Array)) { - node.attributes[name] = [currVal]; - } - node.attributes[name].push(value); - } else { - node.attributes[name] = value; - } - } - } else { - // Semicolon terminated line - node[count++] = line; - } - } - } - - return node; - }; - - /** - * @param node - * A JSON node. - * @param depth - * The depth of the current node; used for indentation and - * optional. - * @param breaks - * Whether to add line breaks in the output. - */ - base.toCSS = function (node, depth, breaks) { - var cssString = ''; - if (typeof depth == 'undefined') { - depth = 0; - } - if (typeof breaks == 'undefined') { - breaks = false; - } - if (node.attributes) { - for (i in node.attributes) { - var att = node.attributes[i]; - if (att instanceof Array) { - for (var j = 0; j < att.length; j++) { - cssString += strAttr(i, att[j], depth); - } - } else { - cssString += strAttr(i, att, depth); - } - } - } - if (node.children) { - var first = true; - for (i in node.children) { - if (breaks && !first) { - cssString += '\n'; - } else { - first = false; - } - cssString += strNode(i, node.children[i], depth); - } - } - return cssString; - }; - - // Helpers - - var strAttr = function (name, value, depth) { - return '\t'.repeat(depth) + name + ': ' + value + ';\n'; - }; - - var strNode = function (name, value, depth) { - var cssString = '\t'.repeat(depth) + name + ' {\n'; - cssString += base.toCSS(value, depth + 1); - cssString += '\t'.repeat(depth) + '}\n'; - return cssString; - }; - -}; \ No newline at end of file diff --git a/resources/js/vendor/htmljson.js b/resources/js/vendor/htmljson.js deleted file mode 100644 index 771c0fc..0000000 --- a/resources/js/vendor/htmljson.js +++ /dev/null @@ -1,178 +0,0 @@ -function parseHtml(html) { - var results = ''; - HTMLParser(html, { - start: function(tag, attrs, unary) { - results += '<' + tag; - for (var i = 0; i < attrs.length; i++) { - results += ' ' + attrs[i].name + '="' + attrs[i].escaped + '"'; - } - results += (unary ? '/' : '') + '>'; - }, - end: function(tag) { - results += ''; - }, - chars: function(text) { - results += text; - }, - comment: function(text) { - results += ''; - } - }); - return results; -} - -function makeMap(str) { - var obj = {}, items = str.split(','); - for (var i = 0; i < items.length; i++) { - obj[items[i]] = true; - } - return obj; -} - -function html2json(html) { - var inline = {}; - - html = html.replace(//, ''); - - var bufArray = []; - var results = {}; - var inlineBuf = []; - bufArray.last = function() { - return this[ this.length - 1]; - }; - HTMLParser(html, { - start: function(tag, attrs, unary) { - if (inline[tag]) { - // inline tag is melted into text - // because syntacs higlight became dirty - // if support it. - // 'hoge tag fuga' - var attributes = ''; - for (var i = 0; i < attrs.length; i++) { - attributes += ' ' + attrs[i].name + '="' + attrs[i].value + '"'; - } - inlineBuf.push('<' + tag + attributes + '>'); - } else { - var buf = {}; // buffer for single tag - buf.tag = tag; - if (attrs.length !== 0) { - var attr = {}; - for (var i = 0; i < attrs.length; i++) { - var attr_name = attrs[i].name; - var attr_value = attrs[i].value; - if (attr_name === 'class') { - attr_value = attr_value.split(' '); - } - attr[attr_name] = attr_value; - } - buf['attr'] = attr; - } - if (unary) { - // if this tag don't has end tag - // like - // add last parents - var last = bufArray.last(); - if (!(last.child instanceof Array)) { - last.child = []; - } - last.child.push(buf); - } else { - bufArray.push(buf); - } - } - }, - end: function(tag) { - if (inline[tag]) { - // if end of inline tag - // inlineBuf is now 'tag' - // melt into last node text - var last = bufArray.last(); - inlineBuf.push(''); - // inlineBuf became 'tag' - if (!last.text) last.text = ''; - last.text += inlineBuf.join(''); - // clear inlineBuf - inlineBuf = []; - } else { - // if block tag - var buf = bufArray.pop(); - if (bufArray.length === 0) { - return results = buf; - } - var last = bufArray.last(); - if (!(last.child instanceof Array)) { - last.child = []; - } - last.child.push(buf); - } - }, - chars: function(text) { - if (inlineBuf.length !== 0) { - // if inlineBuf exists - // this cace inlineBuf is maybe like this - // 'hoge tag' - // so append to last - inlineBuf.push(text); - } else { - var last = bufArray.last(); - if (last) { - if (!last.text) { - last.text = ''; - } - // last.text += text; - if (last.child) { - last.child.push({'tag': '', 'text': text}); - } else { - last.child = []; - last.child.push({'tag': '', 'text': text}); - } - } - } - }, - comment: function(text) { - // results += ""; - } - }); - return results; -} - -function json2html(json) { - var html = ''; - var tag = json.tag; - var text = json.text; - var children = json.child; - var buf = []; - - // Empty Elements - HTML 4.01 - var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'); - - var buildAttr = function(attr) { - for (var k in attr) { - buf.push(' ' + k + '="'); - if (attr[k] instanceof Array) { - buf.push(attr[k].join(' ')); - } else { - buf.push(attr[k]); - } - buf.push('"'); - } - } - - if (tag) { - buf.push('<'); - buf.push(tag); - json.attr ? buf.push(buildAttr(json.attr)) : null; - if (empty[tag]) buf.push('/'); - buf.push('>'); - } - text ? buf.push(text) : null; - if (children) { - for (var j = 0; j < children.length; j++) { - buf.push(json2html(children[j])); - } - } - if (!empty[tag] && tag) { - buf.push(''); - } - return buf.join(''); -} \ No newline at end of file diff --git a/resources/js/vendor/htmlparser.js b/resources/js/vendor/htmlparser.js deleted file mode 100644 index 119abe5..0000000 --- a/resources/js/vendor/htmlparser.js +++ /dev/null @@ -1,316 +0,0 @@ -/* - * HTML5 Parser By Sam Blowes - * - * Designed for HTML5 documents - * - * Original code by John Resig (ejohn.org) - * http://ejohn.org/blog/pure-javascript-html-parser/ - * Original code by Erik Arvidsson, Mozilla Public License - * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js - * - * // Use like so: - * HTMLParser(htmlString, { - * start: function(tag, attrs, unary) {}, - * end: function(tag) {}, - * chars: function(text) {}, - * comment: function(text) {} - * }); - * - * // or to get an XML string: - * HTMLtoXML(htmlString); - * - * // or to get an XML DOM Document - * HTMLtoDOM(htmlString); - * - * // or to inject into an existing document/DOM node - * HTMLtoDOM(htmlString, document); - * HTMLtoDOM(htmlString, document.body); - * - */ - -(function () { - - // Regular Expressions for parsing tags and attributes - var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/, - endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/, - attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; - - // Empty Elements - HTML 5 - var empty = makeMap("area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr"); - - // Block Elements - HTML 5 - var block = makeMap("address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video"); - - // Inline Elements - HTML 5 - var inline = makeMap("a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var"); - - // Elements that you can, intentionally, leave open - // (and which close themselves) - var closeSelf = makeMap("colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr"); - - // Attributes that have their values filled in disabled="disabled" - var fillAttrs = makeMap("checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected"); - - // Special Elements (can contain anything) - var special = makeMap("script,style"); - - var HTMLParser = this.HTMLParser = function (html, handler) { - var index, chars, match, stack = [], last = html; - stack.last = function () { - return this[this.length - 1]; - }; - - while (html) { - chars = true; - - // Make sure we're not in a script or style element - if (!stack.last() || !special[stack.last()]) { - - // Comment - if (html.indexOf(""); - - if (index >= 0) { - if (handler.comment) - handler.comment(html.substring(4, index)); - html = html.substring(index + 3); - chars = false; - } - - // end tag - } else if (html.indexOf("]*>"), function (all, text) { - text = text.replace(/|/g, "$1$2"); - if (handler.chars) - handler.chars(text); - - return ""; - }); - - parseEndTag("", stack.last()); - } - - if (html == last) - throw "Parse Error: " + html; - last = html; - } - - // Clean up any remaining tags - parseEndTag(); - - function parseStartTag(tag, tagName, rest, unary) { - tagName = tagName.toLowerCase(); - - if (block[tagName]) { - while (stack.last() && inline[stack.last()]) { - parseEndTag("", stack.last()); - } - } - - if (closeSelf[tagName] && stack.last() == tagName) { - parseEndTag("", tagName); - } - - unary = empty[tagName] || !!unary; - - if (!unary) - stack.push(tagName); - - if (handler.start) { - var attrs = []; - - rest.replace(attr, function (match, name) { - var value = arguments[2] ? arguments[2] : - arguments[3] ? arguments[3] : - arguments[4] ? arguments[4] : - fillAttrs[name] ? name : ""; - - attrs.push({ - name: name, - value: value, - escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') //" - }); - }); - - if (handler.start) - handler.start(tagName, attrs, unary); - } - } - - function parseEndTag(tag, tagName) { - // If no tag name is provided, clean shop - if (!tagName) - var pos = 0; - - // Find the closest opened tag of the same type - else - for (var pos = stack.length - 1; pos >= 0; pos--) - if (stack[pos] == tagName) - break; - - if (pos >= 0) { - // Close all the open elements, up the stack - for (var i = stack.length - 1; i >= pos; i--) - if (handler.end) - handler.end(stack[i]); - - // Remove the open elements from the stack - stack.length = pos; - } - } - }; - - this.HTMLtoXML = function (html) { - var results = ""; - - HTMLParser(html, { - start: function (tag, attrs, unary) { - results += "<" + tag; - - for (var i = 0; i < attrs.length; i++) - results += " " + attrs[i].name + '="' + attrs[i].escaped + '"'; - results += ">"; - }, - end: function (tag) { - results += ""; - }, - chars: function (text) { - results += text; - }, - comment: function (text) { - results += ""; - } - }); - - return results; - }; - - this.HTMLtoDOM = function (html, doc) { - // There can be only one of these elements - var one = makeMap("html,head,body,title"); - - // Enforce a structure for the document - var structure = { - link: "head", - base: "head" - }; - - if (!doc) { - if (typeof DOMDocument != "undefined") - doc = new DOMDocument(); - else if (typeof document != "undefined" && document.implementation && document.implementation.createDocument) - doc = document.implementation.createDocument("", "", null); - else if (typeof ActiveX != "undefined") - doc = new ActiveXObject("Msxml.DOMDocument"); - - } else - doc = doc.ownerDocument || - doc.getOwnerDocument && doc.getOwnerDocument() || - doc; - - var elems = [], - documentElement = doc.documentElement || - doc.getDocumentElement && doc.getDocumentElement(); - - // If we're dealing with an empty document then we - // need to pre-populate it with the HTML document structure - if (!documentElement && doc.createElement) (function () { - var html = doc.createElement("html"); - var head = doc.createElement("head"); - head.appendChild(doc.createElement("title")); - html.appendChild(head); - html.appendChild(doc.createElement("body")); - doc.appendChild(html); - })(); - - // Find all the unique elements - if (doc.getElementsByTagName) - for (var i in one) - one[i] = doc.getElementsByTagName(i)[0]; - - // If we're working with a document, inject contents into - // the body element - var curParentNode = one.body; - - HTMLParser(html, { - start: function (tagName, attrs, unary) { - // If it's a pre-built element, then we can ignore - // its construction - if (one[tagName]) { - curParentNode = one[tagName]; - if (!unary) { - elems.push(curParentNode); - } - return; - } - - var elem = doc.createElement(tagName); - - for (var attr in attrs) - elem.setAttribute(attrs[attr].name, attrs[attr].value); - - if (structure[tagName] && typeof one[structure[tagName]] != "boolean") - one[structure[tagName]].appendChild(elem); - - else if (curParentNode && curParentNode.appendChild) - curParentNode.appendChild(elem); - - if (!unary) { - elems.push(elem); - curParentNode = elem; - } - }, - end: function (tag) { - elems.length -= 1; - - // Init the new parentNode - curParentNode = elems[elems.length - 1]; - }, - chars: function (text) { - curParentNode.appendChild(doc.createTextNode(text)); - }, - comment: function (text) { - // create comment node - } - }); - - return doc; - }; - - function makeMap(str) { - var obj = {}, items = str.split(","); - for (var i = 0; i < items.length; i++) - obj[items[i]] = true; - return obj; - } -})(); \ No newline at end of file From 80af4f244b3519198ab03c656f90d5864aa7ea09 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Fri, 14 Apr 2017 17:27:48 -0600 Subject: [PATCH 29/48] move function blocksToJSON to block2json.js for obvious reasons --- resources/js/block2json.js | 21 +++++++++++++++++++++ resources/js/files.js | 21 --------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 52ec3f1..5c95651 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -50,6 +50,27 @@ function blockToHTML(block) { } } +function blocksToJSON(fileName) { + var ext = getExt(fileName); + if (ext == 'html') { + var expArray = []; + for(let block of topLevelBlocks) { + if(block) expArray.push(block.toStringable()); + } + fileData[fileName] = expArray; + } else if (ext == 'css') { + // yeah I know I'm ignoring loose blocks + var expArray = [mainScript.toStringable()]; + for(let block of topLevelBlocks) { + if(block != BODY && block.type != 'CSSStart') { + expArray.push(block.toStringable()); + } + } + fileData[fileName] = expArray; + // fileData[fileName] = [mainScript.toStringable()]; + } +} + function setFrameContent(ext) { ext = ext || getExt(currentFile); var previewElement = document.getElementsByClassName('previewBody')[0]; diff --git a/resources/js/files.js b/resources/js/files.js index cdee934..f382dd6 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -205,27 +205,6 @@ function getExt(fileName) { return fileName.match(/\w+$/)[0]; } -function blocksToJSON(fileName) { - var ext = getExt(fileName); - if (ext == 'html') { - var expArray = []; - for(let block of topLevelBlocks) { - if(block) expArray.push(block.toStringable()); - } - fileData[fileName] = expArray; - } else if (ext == 'css') { - // yeah I know I'm ignoring loose blocks - var expArray = [mainScript.toStringable()]; - for(let block of topLevelBlocks) { - if(block != BODY && block.type != 'CSSStart') { - expArray.push(block.toStringable()); - } - } - fileData[fileName] = expArray; - // fileData[fileName] = [mainScript.toStringable()]; - } -} - function generateFile(fileName) { var ext = getExt(fileName); currentFile = fileName; From 68dd70fb6f8f14fba71c0e901e366bf8e6c52b8d Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Fri, 14 Apr 2017 17:31:50 -0600 Subject: [PATCH 30/48] =?UTF-8?q?remove=20default=20scriptingArea=20conten?= =?UTF-8?q?ts=20since=20they=E2=80=99re=20always=20generated=20programmati?= =?UTF-8?q?cally?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/index.html b/index.html index c438ef2..9bd6295 100644 --- a/index.html +++ b/index.html @@ -187,9 +187,7 @@ -
      -
      • DOCTYPE html
      -
      +
      From 52bf2e26e7a732291902de5c730200e789887ead Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Fri, 14 Apr 2017 17:34:09 -0600 Subject: [PATCH 31/48] bugfix: default blocks in new CSS files were marked inPalette --- resources/js/files.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/files.js b/resources/js/files.js index f382dd6..9706aa0 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -238,7 +238,7 @@ function generateFile(fileName) { hasAttrs: false, hasQuickText: false, inputs: ['.selector'], - inPalette: true, + inPalette: false, ftype: 'css' }); mainScript.insertChild(defaultSelector, -1); @@ -247,7 +247,7 @@ function generateFile(fileName) { hasAttrs: false, hasQuickText: false, inputs: ['background-color', 'red'], - inPalette: true, + inPalette: false, ftype: 'css' }); defaultSelector.insertChild(defaultRule, -1); From e5da901f0bc56ad7cb1d31382970bb19b91fec45 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Fri, 14 Apr 2017 17:41:08 -0600 Subject: [PATCH 32/48] clean up blocks2json a lil --- resources/js/block2json.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 5c95651..b5a23c5 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -1,12 +1,3 @@ -//probably should put this in a local function on prod... fine for now tho - -if (!String.prototype.startsWith) { // sweet polyfill - String.prototype.startsWith = function(searchString, position) { - position = position || 0; - return this.indexOf(searchString, position) === position; - }; -} - function blockToCSS(blockList) { function blockToCSS_(block) { if(block.name == 'selector') { @@ -82,8 +73,16 @@ function setFrameContent(ext) { blocksToJSON(currentFile); var previewWindow = previewElement; - previewWindow = (previewWindow.contentWindow) ? previewWindow.contentWindow : (previewWindow.contentDocument.document) ? previewWindow.contentDocument.document : previewWindow.contentDocument; - while(previewWindow.document.firstChild) previewWindow.document.removeChild(previewWindow.document.firstChild); + if(previewElement.contentWindow) { + previewWindow = previewWindow.contentWindow; + } else if(previewElement.contentDocument.document) { + previewWindow = previewElement.contentDocument.document; + } else { + previewWindow = previewWindow.contentDocument + } + var previewDocument = previewWindow.document, + child; + while(child = previewDocument.firstChild) previewDocument.removeChild(child); previewWindow.document.appendChild(parsedHtml); } else { throw 'this should never be thrown though'; From 0427ae8425a68670b8d43a1dc8dd600b5d484078 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Sun, 16 Apr 2017 17:22:00 -0600 Subject: [PATCH 33/48] update zebra to use the new system --- resources/js/blocks.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 2df8d9a..50491c9 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -725,19 +725,18 @@ document.getElementById('trashCan2').addEventListener('mouseout', function(ev) { }); // zebra stuff -function zebra(parent, nestcount) { - var children = parent.children; - for (var i = 0; i < children.length; i++) { - if(children[i].className.indexOf('c-wrapper') != -1) { - children[i].classList.remove('zebra') - if((nestcount % 2) == 1) {children[i].classList.add('zebra');} - zebra(children[i].children[1], nestcount + 1); - } - } -} - function setZebra() { - for(i = 0; i < document.querySelectorAll('.script, .draggy').length; i++) { - zebra(document.querySelectorAll('.script, .draggy')[i], 0); + function zebra(block, nestcount) { + if(block.type == 'cblock') { + block.elem.classList.remove('zebra'); + if((nestcount % 2) == 1) block.elem.classList.add('zebra'); } + for(let child of block.children) { + zebra(child, nestcount + 1); + } + } + + for(let block of topLevelBlocks) { + if(block) zebra(block, block.type == 'blockWrapper' ? 1 : 0); + } } From 31772074e9fb6351a80a0e9f4dc20df1f0c139e6 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Sun, 16 Apr 2017 17:27:04 -0600 Subject: [PATCH 34/48] tweaks --- resources/js/block2json.js | 2 +- resources/js/blocks.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index b5a23c5..8f34c8d 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -53,7 +53,7 @@ function blocksToJSON(fileName) { // yeah I know I'm ignoring loose blocks var expArray = [mainScript.toStringable()]; for(let block of topLevelBlocks) { - if(block != BODY && block.type != 'CSSStart') { + if(block && block != BODY && block.type != 'CSSStart') { expArray.push(block.toStringable()); } } diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 50491c9..123e52e 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -619,6 +619,7 @@ function replaceBody(bodyBlock) { } mainScript.insertChild(BODY, -1); topLevelBlocks.push(BODY); + setZebra(); } function cleanse_contenteditable (ev) { @@ -705,9 +706,6 @@ $('.context-menu.scripts .menu-item').on('click', function(ev) { } }); - -setZebra(); - document.getElementById('trashCan').addEventListener('mouseover', function(ev) { this.classList.add('hovering'); }); From 405eaff0fedce26ec50652903e19e85e017556f0 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Sun, 16 Apr 2017 17:42:14 -0600 Subject: [PATCH 35/48] switch from strings for block types to enum --- resources/js/block2json.js | 4 +- resources/js/blockFilter.js | 129 +++++++++++++++++++----------------- resources/js/blocks.js | 36 +++++----- resources/js/files.js | 18 ++--- 4 files changed, 98 insertions(+), 89 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 8f34c8d..16cde69 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -24,7 +24,7 @@ function blockToCSS(blockList) { } function blockToHTML(block) { - if(block.type !== 'stack' && block.type !== 'cblock') { + if(block.type !== BLOCK_TYPES.stack && block.type !== BLOCK_TYPES.cblock) { return null; } else if(block.name == 'text') { return document.createTextNode(block.inputs[0].value); @@ -53,7 +53,7 @@ function blocksToJSON(fileName) { // yeah I know I'm ignoring loose blocks var expArray = [mainScript.toStringable()]; for(let block of topLevelBlocks) { - if(block && block != BODY && block.type != 'CSSStart') { + if(block && block != BODY && block.type != BLOCK_TYPES.CSSStart) { expArray.push(block.toStringable()); } } diff --git a/resources/js/blockFilter.js b/resources/js/blockFilter.js index a75a3be..27eaa5c 100644 --- a/resources/js/blockFilter.js +++ b/resources/js/blockFilter.js @@ -1,3 +1,12 @@ +// this is defined here instead of in blocks.js because this loads first. +var BLOCK_TYPES = { + stack: 0, + cblock: 1, + blockWrapper: 2, + cblockStart: 3, + CSSStart: 4 +}; + var filter = { type: 'search', // 'palette' or 'search' selectedPalette: 1, @@ -35,7 +44,7 @@ var filter = { for(x = 0; x < blocksToDisplay.length; x++) { var block = filter.blocks[blocksToDisplay[x]]; var newBlock; - if (block.type == 'cblock') { + if (block.type == BLOCK_TYPES.cblock) { if (!block.ftype || block.ftype == 'html') { newBlock = new Block(block.type, block.name, { hasAttrs: true, @@ -73,7 +82,7 @@ var filter = { });; } } else { - newBlock = new Block('stack', 'text', { + newBlock = new Block(BLOCK_TYPES.stack, 'text', { hasAttrs: false, hasQuickText: false, inputs: [DEFAULT_TEXT], @@ -101,151 +110,151 @@ var filter = { { // Moved text node to top because it is basically the most used block name: 'text', - type: 'stack', + type: BLOCK_TYPES.stack, tags: ['text'], palette: 0 }, { name: 'h1', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['heading', 'h1'], palette: 0 }, { name: 'h2', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['heading', 'h2'], palette: 0 }, { name: 'h3', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['heading', 'h3'], palette: 0 }, { name: 'p', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['p', 'paragraph'], palette: 0 }, { name: 'span', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['span'], palette: 0 }, { name: 'pre', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['pre', 'code'], palette: 0 }, { name: 'code', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['code'], palette: 0 }, { name: 'a', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['link', 'a'], palette: 0 }, { name: 'abbr', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['abbrevation', 'abbr'], palette: 0 }, { name: 'b', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['bold', 'b'], palette: 0 }, { name: 'i', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['italics', 'i'], palette: 0 }, { name: 'strong', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['strong'], palette: 0 }, { name: 'em', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['em', 'emphasis'], palette: 0 }, { name: 'mark', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['marker', 'mark', 'highlighted'], palette: 0 }, { name: 'del', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['deleted', 'del', 'update', 'edit'], palette: 0 }, { name: 'ins', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['inserted', 'ins', 'update', 'edit'], palette: 0 }, { name: 'sub', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['subtext', 'sub'], palette: 0 }, { name: 'sup', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['supertext', 'sup'], palette: 0 }, { name: 'kbd', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['keyboard', 'input', 'kbd'], palette: 0 }, { name: 'samp', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['sample', 'output', 'samp'], palette: 0 }, { name: 'var', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['variable', 'var'], palette: 0 }, { name: 'ol', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['lists', 'ordered list', 'ol'], palette: 0 }, { name: 'ul', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['lists', 'unordered list', 'ul'], palette: 0 }, { name: 'li', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['lists', 'list item', 'li'], palette: 0 }, @@ -253,49 +262,49 @@ var filter = { /* Blocks for palette 1 - Media */ { name: 'img', - type: 'stack', + type: BLOCK_TYPES.stack, tags: ['image', 'img', 'picture'], palette: 1 }, { name: 'CSS', - type: 'stack', + type: BLOCK_TYPES.stack, tags: ['css', 'style', 'link'], palette: 1 }, { name: 'audio', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['audio'], palette: 1 }, { name: 'video', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['video'], palette: 1 }, { name: 'object', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['object', 'flash', 'plugin'], palette: 1 }, { name: 'track', - type: 'stack', + type: BLOCK_TYPES.stack, tags: ['audio', 'track'], palette: 1 }, { name: 'source', - type: 'stack', + type: BLOCK_TYPES.stack, tags: ['audio', 'video', 'source'], palette: 1 }, { name: 'param', - type: 'stack', + type: BLOCK_TYPES.stack, tags: ['object', 'flash', 'plugin', 'paramater', 'param'], palette: 1 }, @@ -303,25 +312,25 @@ var filter = { /* Blocks for palette 2 - Sections */ { name: 'div', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['div', 'divider', 'separator'], palette: 2 }, { name: 'navigation', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['nav', 'navigation'], palette: 2 }, { name: 'footer', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['footer', 'foot' /* can i addz feet plz?*/], palette: 2 }, { name: 'article', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['article'], palette: 2 }, @@ -329,61 +338,61 @@ var filter = { /* Blocks for palette 3 - Tables */ { name: 'table', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table'], palette: 3 }, { name: 'caption', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'caption', 'title'], palette: 3 }, { name: 'tbody', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'body', 'tbody'], palette: 3 }, { name: 'thead', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'head', 'header', 'thead'], palette: 3 }, { name: 'tfoot', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'foot', 'footer', 'tfoot'], palette: 3 }, { name: 'tr', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'row', 'tr'], palette: 3 }, { name: 'td', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'cell', 'td'], palette: 3 }, { name: 'th', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'cell', 'th', 'head', 'header'], palette: 3 }, { name: 'col', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'column', 'col'], palette: 3 }, { name: 'colgroup', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['table', 'column', 'colgroup'], palette: 3 }, @@ -391,55 +400,55 @@ var filter = { /* Blocks for palette 4 - forms */ { name: 'form', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['forms', 'form'], palette: 4 }, { name: 'input', - type: 'stack', + type: BLOCK_TYPES.stack, tags: ['forms', 'input'], palette: 4 }, { name: 'output', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['forms', 'output'], palette: 4 }, { name: 'button', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['forms', 'button'], palette: 4 }, { name: 'select', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['forms', 'options', 'select'], palette: 4 }, { name: 'option', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['forms', 'options', 'option'], palette: 4 }, { name: 'datalist', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['forms', 'options', 'datalist'], palette: 4 }, { name: 'fieldset', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['forms', 'fieldset', 'fields'], palette: 4 }, { name: 'legend', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['forms', 'fields', 'legend'], palette: 4 }, @@ -447,14 +456,14 @@ var filter = { /* Blocks for CSS */ { name: 'selector', - type: 'cblock', + type: BLOCK_TYPES.cblock, tags: ['selection', 'selector'], palette: 7, ftype: 'css' }, { name: 'rule', - type: 'stack', + type: BLOCK_TYPES.stack, tags: ['rule'], palette: 7, ftype: 'css' diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 123e52e..fb97f25 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -6,8 +6,8 @@ var selected = null, // Object of the element to be moved var blocksDatabase, // all blocks by ID. Not an array in case we decide to use md5's or something later scriptBlocks, topLevelBlocks, - blocksCount = 0; // not a real bumber of blocks. This value should never be - // decrememnted because it's used to generate a blocks' unique ID + blocksCount = 0; // not a real number of blocks. This value should never be + // decrememnted because it's used to generate a block's unique ID clearBlocks(); replaceBody(); @@ -16,7 +16,7 @@ replaceBody(); function BlockWrapper(inPalette) { this.x = 0; this.y = 0; - this.type = 'blockWrapper'; + this.type = BLOCK_TYPES.blockWrapper; this.id = blocksCount++; blocksDatabase[this.id] = this; this.parent = null; @@ -69,7 +69,7 @@ function BlockWrapper(inPalette) { minDistance; blocks: for(let oblock of scriptBlocks) { if (!oblock - || oblock.type == 'blockWrapper' + || oblock.type == BLOCK_TYPES.blockWrapper || oblock.unmoveable) continue blocks; // check for descendancy let pblock = block; @@ -90,7 +90,7 @@ function BlockWrapper(inPalette) { dy = oblock.bottom() - block.top(); // move point inside c-blocks to the right - if(oblock.type == 'cblockStart') { + if(oblock.type == BLOCK_TYPES.cblockStart) { dx += oblock.content.style.paddingLeft; } @@ -194,7 +194,7 @@ function Block(type, name, opts) { this.inPalette = (opts.inPalette !== undefined) ? opts.inPalette : true; this.unmoveable = opts.unmoveable || false; var block = this; - if(type == 'cblock') { + if(type == BLOCK_TYPES.cblock) { this.elem = document.createElement('ul'); this.elem.classList.add('c-wrapper'); @@ -204,7 +204,7 @@ function Block(type, name, opts) { // add a blank blockWrapper inside cblock var cblockStart = new BlockWrapper(this.inPalette); - cblockStart.type = 'cblockStart'; + cblockStart.type = BLOCK_TYPES.cblockStart; this.insertChild(cblockStart, -1); cblockStart.elem = cblockStart.content = this.header; @@ -223,7 +223,7 @@ function Block(type, name, opts) { footer.appendChild(this.quickText); this.quickText.addEventListener('click', function(ev) { - var newBlock = new Block('stack', 'text', { + var newBlock = new Block(BLOCK_TYPES.stack, 'text', { hasAttrs: false, hasQuickText: false, inputs: [DEFAULT_TEXT], @@ -233,7 +233,7 @@ function Block(type, name, opts) { setFrameContent(); }); } - } else if(type == 'stack') { + } else if(type == BLOCK_TYPES.stack) { this.elem = document.createElement('li'); this.elem.classList.add('stack'); this.header = this.elem; @@ -453,7 +453,7 @@ function _drag_init(block, ev) { blockWrapper.insertChild(child, -1); child.elem.removeAttribute('style'); } - if(parent.children.length == 0 && parent.type == 'blockWrapper') parent.deleteBlock(); + if(parent.children.length == 0 && parent.type == BLOCK_TYPES.blockWrapper) parent.deleteBlock(); blockWrapper.setPosition(curX - relativeX, curY - relativeY); selected = blockWrapper; dragOffset.x = mousePos.x - selected.elem.offsetLeft; @@ -492,7 +492,7 @@ function _move_elem(e) { if (selected !== null) { var el = selected.getClosestBlock(); if (el !== null) { - if(el.type == 'CSSStart') { + if(el.type == BLOCK_TYPES.CSSStart) { document.querySelector('#mainScript > li.hat').classList.add('drop-area'); } else { el.elem.classList.add('drop-area'); @@ -513,11 +513,11 @@ function _destroy(ev) { for(let child of kids) { child.removeFromParent(); child.elem.removeAttribute('style'); - if(topEl.type == 'cblockStart') { + if(topEl.type == BLOCK_TYPES.cblockStart) { topEl.parent.insertChild(child, 1); // 0 is the null BlockWrapper - } else if(topEl.type == 'stack' - || topEl.type == 'cblock' - || topEl.type == 'CSSStart') { + } else if(topEl.type == BLOCK_TYPES.stack + || topEl.type == BLOCK_TYPES.cblock + || topEl.type == BLOCK_TYPES.CSSStart) { topEl.parent.insertChild(child, topEl.getIndex() + 1); } } @@ -610,7 +610,7 @@ function replaceBody(bodyBlock) { if(bodyBlock) { BODY = bodyBlock; } else { - BODY = new Block('cblock', 'body', { + BODY = new Block(BLOCK_TYPES.cblock, 'body', { hasAttrs: true, hasQuickText: true, inPalette: false, @@ -725,7 +725,7 @@ document.getElementById('trashCan2').addEventListener('mouseout', function(ev) { // zebra stuff function setZebra() { function zebra(block, nestcount) { - if(block.type == 'cblock') { + if(block.type == BLOCK_TYPES.cblock) { block.elem.classList.remove('zebra'); if((nestcount % 2) == 1) block.elem.classList.add('zebra'); } @@ -735,6 +735,6 @@ function setZebra() { } for(let block of topLevelBlocks) { - if(block) zebra(block, block.type == 'blockWrapper' ? 1 : 0); + if(block) zebra(block, block.type == BLOCK_TYPES.blockWrapper ? 1 : 0); } } diff --git a/resources/js/files.js b/resources/js/files.js index 9706aa0..f74012a 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -63,9 +63,9 @@ var currentFile = 'index.html'; var stackElements = []; var wrapperElements = []; filter.blocks.forEach(function(block) { - if (block.type === 'cblock') { + if (block.type === BLOCK_TYPES.cblock) { wrapperElements.push('e-' + block.name); - } else if (block.type === 'stack') { + } else if (block.type === BLOCK_TYPES.stack) { stackElements.push('e-' + block.name); } else { console.warn('Invalid block type "' + block.type + '" for element ' + block.name); @@ -90,11 +90,11 @@ function generateBlocks(jsonData, ext) { function generateBlock(block) { if(!block.type) return null; let newBlock; - if(block.type == 'blockWrapper') { + if(block.type == BLOCK_TYPES.blockWrapper) { newBlock = new BlockWrapper(); topLevelBlocks.push(newBlock) - } else if( block.type == 'stack' - || block.type == 'cblock') { + } else if( block.type == BLOCK_TYPES.stack + || block.type == BLOCK_TYPES.cblock) { newBlock = new Block(block.type, block.name, { hasAttrs: block.hasAttrs, hasQuickText: block.hasQuickText, @@ -119,7 +119,7 @@ function generateBlocks(jsonData, ext) { if(ext == 'css') { clearBlocks(currentFile); replaceBody(new BlockWrapper()); - BODY.type = 'CSSStart'; + BODY.type = BLOCK_TYPES.CSSStart; let newBodyScript = jsonData[0]; for(let block of newBodyScript.children) { @@ -231,10 +231,10 @@ function generateFile(fileName) { } else if (ext == 'css') { clearBlocks(currentFile); replaceBody(new BlockWrapper()); - BODY.type = 'CSSStart'; + BODY.type = BLOCK_TYPES.CSSStart; // add default blocks - let defaultSelector = new Block('cblock', 'selector', { + let defaultSelector = new Block(BLOCK_TYPES.cblock, 'selector', { hasAttrs: false, hasQuickText: false, inputs: ['.selector'], @@ -243,7 +243,7 @@ function generateFile(fileName) { }); mainScript.insertChild(defaultSelector, -1); - let defaultRule = new Block('stack', 'rule', { + let defaultRule = new Block(BLOCK_TYPES.stack, 'rule', { hasAttrs: false, hasQuickText: false, inputs: ['background-color', 'red'], From 2f25591cf9a5f56daad4b8cc00dfc56c5fc6c4c4 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Sun, 16 Apr 2017 20:44:46 -0600 Subject: [PATCH 36/48] bug fix with enum --- resources/js/block2json.js | 2 -- resources/js/files.js | 13 ++----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 16cde69..fd9e77a 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -50,7 +50,6 @@ function blocksToJSON(fileName) { } fileData[fileName] = expArray; } else if (ext == 'css') { - // yeah I know I'm ignoring loose blocks var expArray = [mainScript.toStringable()]; for(let block of topLevelBlocks) { if(block && block != BODY && block.type != BLOCK_TYPES.CSSStart) { @@ -58,7 +57,6 @@ function blocksToJSON(fileName) { } } fileData[fileName] = expArray; - // fileData[fileName] = [mainScript.toStringable()]; } } diff --git a/resources/js/files.js b/resources/js/files.js index f74012a..4abbe79 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -77,18 +77,9 @@ var unnamedWrapperElements = wrapperElements.map(function(item) { }); var textInput = 'text'; -function getCSSAttributesHTML(attributes) { - var pushedHtml = []; - for (attr in attributes) { - var attrValue = attributes[attr]; - pushedHtml.push('
    • rule ' + attr + ': ' + attrValue + '
    • '); - } - return pushedHtml.join(''); -} - function generateBlocks(jsonData, ext) { function generateBlock(block) { - if(!block.type) return null; + if(block.type == undefined) return null; let newBlock; if(block.type == BLOCK_TYPES.blockWrapper) { newBlock = new BlockWrapper(); @@ -107,7 +98,7 @@ function generateBlocks(jsonData, ext) { add_attr(newBlock, attr.name, attr.value); } } else { - return null; // other types of Draggies are generated in block constructors + return null; // other types of blocks are generated in block constructors } newBlock.setPosition(block.x, block.y); for(let child of block.children) { From 48ba312470e279ec6293b7baeabaed9fd78637c3 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Sun, 16 Apr 2017 21:18:01 -0600 Subject: [PATCH 37/48] remove a lot of old code and random nits --- resources/js/block2json.js | 2 +- resources/js/blockAttributes.js | 2 +- resources/js/blockFilter.js | 2 +- resources/js/blocks.js | 161 +++++++++----------------------- 4 files changed, 46 insertions(+), 121 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index fd9e77a..14c4a2a 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -76,7 +76,7 @@ function setFrameContent(ext) { } else if(previewElement.contentDocument.document) { previewWindow = previewElement.contentDocument.document; } else { - previewWindow = previewWindow.contentDocument + previewWindow = previewWindow.contentDocument; } var previewDocument = previewWindow.document, child; diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index 7fe91fc..9de265a 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -1,4 +1,4 @@ -// both optional +// both inputs are optional function BlockAttribute(name, value) { this.elem = document.createElement('span'); this.elem.classList.add('attr-holder'); diff --git a/resources/js/blockFilter.js b/resources/js/blockFilter.js index 27eaa5c..729b8bc 100644 --- a/resources/js/blockFilter.js +++ b/resources/js/blockFilter.js @@ -495,7 +495,7 @@ function blockFilterOnload() { // ew multiple onloads var paletteButtons = document.getElementsByClassName("paletteOptionWrap"); for(var i = 0; i < paletteButtons.length; i++) { var buttonElem = paletteButtons[i]; - buttonElem.onclick = handlePaletteClick; + buttonElem.addEventListener('click', handlePaletteClick); } handlePaletteClick(); }; diff --git a/resources/js/blocks.js b/resources/js/blocks.js index fb97f25..a733453 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -368,17 +368,6 @@ function BlockInput(defaultValue) { }; } -function isDescendant(parent, child) { - var node = child.parentNode; - while (node != null) { - if (node == parent) { - return true; - } - node = node.parentNode; - } - return false; -} - function removeDropArea() { let dropArea; while(dropArea = document.querySelector('.drop-area')) { @@ -417,24 +406,6 @@ function getOffset( elem ) { } -// ancestor has parent -function parentHasClass(element, className) { - var regex = new RegExp('\\b' + className + '\\b'); - do { - if (element.classList !== undefined) { - if (element.classList.contains(className)) { - return true; - } - } else { - if (regex.exec(element.className)) { - return true; - } - } - element = element.parentNode; - } while (element); - return false; -} - // Will be called when user starts dragging an element function _drag_init(block, ev) { var elem = block.elem; @@ -451,7 +422,7 @@ function _drag_init(block, ev) { for(let child of kids) { child.removeFromParent(); blockWrapper.insertChild(child, -1); - child.elem.removeAttribute('style'); + child.setPosition(0,0); } if(parent.children.length == 0 && parent.type == BLOCK_TYPES.blockWrapper) parent.deleteBlock(); blockWrapper.setPosition(curX - relativeX, curY - relativeY); @@ -512,7 +483,7 @@ function _destroy(ev) { var kids = selected.children.slice().reverse(); for(let child of kids) { child.removeFromParent(); - child.elem.removeAttribute('style'); + child.setPosition(0,0) if(topEl.type == BLOCK_TYPES.cblockStart) { topEl.parent.insertChild(child, 1); // 0 is the null BlockWrapper } else if(topEl.type == BLOCK_TYPES.stack @@ -536,63 +507,9 @@ function _destroy(ev) { selected = null; } -function _delete(ev) { - var SNAP_CLASSES = currentFile.split('.').pop() == 'css' ? CSS_SNAP_CLASSES : HTML_SNAP_CLASSES; - $(SNAP_CLASSES).each(function(item) { - if (item.classList.contains('drop-area')) { - item.classList.remove('drop-area'); - } - }); - if (selected) { // TODO: make this not ugly - selected.elem.parentNode.removeChild(selected.elem); - } - selected = null; -} - -var HTML_SNAP_CLASSES = [ - '.stack', - '.c-header', - ':not(.e-body) > .c-footer' -].join(', '); -var CSS_SNAP_CLASSES = [ - '.stack', - '.hat', - '.c-header', - ':not(.e-body) > .c-footer' -].join(', '); var MIN_DISTANCE = 50; var BLOCK_PALETTE = $('.blockArea')[0]; -var DRAGGABLE_ELEMENTS = ([ - '.c-wrapper:not(.e-body)', - '.stack', -]).map(function(item) { - return '.scriptingArea ' + item; -}).join(', '); - -var C_ELEMENTS = ([ - '.c-header', - '.c-content', - ':not(.e-body) > .c-footer' -]).map(function(item) { - return '.scriptingArea ' + item; -}).join(', '); - -var DRAGGABLE_PALETTE_ELEMENTS = ([ - '.c-wrapper', - '.stack', -]).map(function(item) { - return '.blockArea ' + item; -}).join(', '); - -var C_PALETTE_ELEMENTS = ([ - '.c-header', - '.c-content', - '.c-footer' -]).map(function(item) { - return '.blockArea ' + item; -}).join(', '); - function clearBlocks(hat) { blocksDatabase = {}; scriptBlocks = []; @@ -654,57 +571,65 @@ function cleanse_contenteditable (ev) { var SCRIPT_MENU = document.querySelector('.context-menu.scripts'); var RIGHT_CLICKED_SCRIPT = undefined; -$('body').on('mousemove', _move_elem) +$('body') + .on('mousemove', _move_elem) .on('mouseup', function(ev) { - if (/* ev.target == BLOCK_PALETTE || parentHasClass(ev.target, 'blockArea') || */ ev.target.className.split(' ').indexOf('trashCan') > -1 || ev.target.className.split(' ').indexOf('trashCan2') > -1) { + if (ev.target.classList.contains('trashCan') || ev.target.classList.contains('trashCan2')) { trashCan = document.getElementById('trashCan'); trashCan.classList.remove('showing'); - _delete(ev); + removeDropArea(); + if (selected) { + selected.deleteBlock() + } + selected = null; } else { if (ev.target == BLOCK_PALETTE) { - trashCan = document.getElementById('trashCan'); - trashCan.classList.remove('showing'); + trashCan = document.getElementById('trashCan'); + trashCan.classList.remove('showing'); } _destroy(ev); } - if (!(ev.target.classList.contains('file') || parentHasClass(ev.target, 'file'))) { + if (!(ev.target.classList.contains('file') + || ev.target.classList.contains('file-name'))) { setFrameContent(); } setZebra(); - }).on('input', function(ev) { + }) + .on('input', function(ev) { setFrameContent(); }); -$('.context-menu.scripts .menu-item').on('click', function(ev) { - if (RIGHT_CLICKED_SCRIPT) { - switch (this.dataset.action) { - case 'duplicate-script': - // do stuff with node... and get stuff beneath it too! - var target = RIGHT_CLICKED_SCRIPT; - var blockWrapper = new BlockWrapper(); - SCRIPTING_AREA.insertBefore(blockWrapper.elem, SCRIPTING_AREA.firstChild); - topLevelBlocks.push(blockWrapper); - for(let i = target.getIndex(); i < target.parent.children.length; i++) { - let child = target.parent.children[i]; - blockWrapper.insertChild(child.clone(false), -1); - } +$('.context-menu.scripts .menu-item') + .on('click', function(ev) { + if (RIGHT_CLICKED_SCRIPT) { + switch (this.dataset.action) { + case 'duplicate-script': + // do stuff with node... and get stuff beneath it too! + var target = RIGHT_CLICKED_SCRIPT; + var blockWrapper = new BlockWrapper(); + SCRIPTING_AREA.insertBefore(blockWrapper.elem, SCRIPTING_AREA.firstChild); + topLevelBlocks.push(blockWrapper); + for(let i = target.getIndex(); i < target.parent.children.length; i++) { + let child = target.parent.children[i]; + blockWrapper.insertChild(child.clone(false), -1); + } - var relativeX = ev.pageX - target.left(); - var relativeY = ev.pageY - target.top(); - var curX = ev.pageX - getOffset(SCRIPTING_AREA).left, - curY = ev.pageY - getOffset(SCRIPTING_AREA).top; - blockWrapper.setPosition(curX - relativeX + 25, curY - relativeY + 25) + var relativeX = ev.pageX - target.left(); + var relativeY = ev.pageY - target.top(); + var curX = ev.pageX - getOffset(SCRIPTING_AREA).left, + curY = ev.pageY - getOffset(SCRIPTING_AREA).top; + blockWrapper.setPosition(curX - relativeX + 25, curY - relativeY + 25) - setZebra(); - RIGHT_CLICKED_SCRIPT = undefined; - SCRIPT_MENU.style.display = 'none'; - break; + setZebra(); + RIGHT_CLICKED_SCRIPT = undefined; + SCRIPT_MENU.style.display = 'none'; + break; - default: - //nothing + default: + //nothing + } } - } -}); + }); document.getElementById('trashCan').addEventListener('mouseover', function(ev) { this.classList.add('hovering'); From a22cf9c3040ee8d7b203d6e20db5b2f7dce7ac62 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Sun, 16 Apr 2017 21:33:14 -0600 Subject: [PATCH 38/48] remove duplicate code --- resources/js/block2json.js | 23 +++++++++++------------ resources/js/files.js | 10 +--------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 14c4a2a..d94795a 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -62,7 +62,17 @@ function blocksToJSON(fileName) { function setFrameContent(ext) { ext = ext || getExt(currentFile); - var previewElement = document.getElementsByClassName('previewBody')[0]; + var previewElement = document.querySelector('.previewBody'); + if(previewElement.contentWindow) { + previewWindow = previewElement.contentWindow; + } else if(previewElement.contentDocument.document) { + previewWindow = previewElement.contentDocument.document; + } else { + previewWindow = previewWindow.contentDocument; + } + var previewDocument = previewWindow.document, + child; + while(child = previewDocument.firstChild) previewDocument.removeChild(child); if (ext == 'css') { blocksToJSON(currentFile); @@ -70,17 +80,6 @@ function setFrameContent(ext) { var parsedHtml = blockToHTML(BODY); blocksToJSON(currentFile); - var previewWindow = previewElement; - if(previewElement.contentWindow) { - previewWindow = previewWindow.contentWindow; - } else if(previewElement.contentDocument.document) { - previewWindow = previewElement.contentDocument.document; - } else { - previewWindow = previewWindow.contentDocument; - } - var previewDocument = previewWindow.document, - child; - while(child = previewDocument.firstChild) previewDocument.removeChild(child); previewWindow.document.appendChild(parsedHtml); } else { throw 'this should never be thrown though'; diff --git a/resources/js/files.js b/resources/js/files.js index 4abbe79..cf2e2d2 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -166,7 +166,6 @@ function loadFile(filename, el) { el.parentNode.classList.add('selected'); } - blockArea = $('.scriptingArea')[0]; generateBlocks(fileJson, getExt(filename)); setFrameContent(); setZebra(); @@ -245,15 +244,8 @@ function generateFile(fileName) { } else { throw 'File type "' + ext + '" not supported.'; } - blockArea = $('.scriptingArea')[0]; - //clear preview window - var previewWindow = document.getElementsByClassName('previewBody')[0]; - previewWindow = (previewWindow.contentWindow) ? previewWindow.contentWindow : (previewWindow.contentDocument.document) ? previewWindow.contentDocument.document : previewWindow.contentDocument; - - previewWindow.document.open(); - previewWindow.document.write(''); - previewWindow.document.close(); + setFrameContent(ext); } var FILE_MENU = document.querySelector('.context-menu.files'); From 27c61d9e4a7a0a445beccd12b1f45959660c0415 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Mon, 17 Apr 2017 01:09:05 -0600 Subject: [PATCH 39/48] element/block highlighting mockup --- resources/js/block2json.js | 22 ++++++++++++++++------ resources/js/blocks.js | 15 +++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/resources/js/block2json.js b/resources/js/block2json.js index d94795a..49d2d2d 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -24,21 +24,31 @@ function blockToCSS(blockList) { } function blockToHTML(block) { + var out = null; if(block.type !== BLOCK_TYPES.stack && block.type !== BLOCK_TYPES.cblock) { - return null; + out = null; } else if(block.name == 'text') { - return document.createTextNode(block.inputs[0].value); + out = document.createTextNode(block.inputs[0].value); } else { - var element = document.createElement(block.name); + out = document.createElement(block.name); for(let attr of block.attrs) { - if(attr.name.trim() && attr.value.trim()) element.setAttribute(attr.name, attr.value); + if(attr.name.trim() && attr.value.trim()) out.setAttribute(attr.name, attr.value); } for(let child of block.children) { let parsedChild = blockToHTML(child); - if(parsedChild) element.appendChild(parsedChild); + if(parsedChild) out.appendChild(parsedChild); } - return element; + block.htmlElem = out; } + if(out) { + out.addEventListener('mouseover', function() { + block.elem.style.outline = '3px solid gold'; + }); + out.addEventListener('mouseout', function() { + block.elem.style.outline = ''; + }); + } + return out; } function blocksToJSON(fileName) { diff --git a/resources/js/blocks.js b/resources/js/blocks.js index a733453..4c158a4 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -320,6 +320,21 @@ function Block(type, name, opts) { return false; } + this.elem.addEventListener('mouseover', function(ev) { + if(block.htmlElem) { + block.htmlElem.style.outline = '3px solid gold'; + } else if(block.name == 'text' && block.parent && block.parent.htmlElem) { + block.parent.htmlElem.style.outline = '3px solid gold'; + } + }); + this.elem.addEventListener('mouseout', function(ev) { + if(block.htmlElem) { + block.htmlElem.style.outline = ''; + } else if(block.name == 'text' && block.parent && block.parent.htmlElem) { + block.parent.htmlElem.style.outline = ''; + } + }); + this.elem.addEventListener('mousedown', function(ev) { if (ev.which == 3 || testBlockContents(ev.target)) return; From 1f27da956cddffc8d0b3f4b84657740af7622f09 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Mon, 17 Apr 2017 10:12:08 -0600 Subject: [PATCH 40/48] slightly simplify file import --- resources/js/files.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/resources/js/files.js b/resources/js/files.js index cf2e2d2..11e92c3 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -128,14 +128,8 @@ function generateBlocks(jsonData, ext) { } } } else if(ext == 'html') { - let body; - for(let block of jsonData) { - if (block.name == 'body') { - body = block; - break; - } - } clearBlocks(); + let body = jsonData[0]; let newBody = generateBlock(body); replaceBody(newBody); for(let block of jsonData) { From cdafc90d8d9b889dcca7547fa56b49624a6802c5 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Mon, 17 Apr 2017 19:30:15 -0600 Subject: [PATCH 41/48] a naive attempt to clog potential memory leaks --- resources/js/blockAttributes.js | 12 ++++++++---- resources/js/blocks.js | 33 +++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index 9de265a..f7e05a5 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -20,7 +20,7 @@ function BlockAttribute(name, value) { this.input.addEventListener('input', cleanse_contenteditable); var attr = this; - this.input.addEventListener('input', function(e) { + this.input.addEventListener('input', attr.on_input = function(e) { attr.value = attr.input.textContent; }); @@ -34,6 +34,10 @@ function BlockAttribute(name, value) { value: attr.value }; } + + this.deleteAttr = function() { + attr.elem.removeEventListener('input', attr.on_input); + } } function add_attr(block, name, value) { @@ -51,10 +55,10 @@ function attachAttrSearch(elem, attrNames, callback) { var ATTRIBUTE_SEARCH = document.getElementById('propSearch'); var ATTRIBUTE_RESULTS = document.getElementById('attributeResults'); - elem.addEventListener('click', function() { + elem.addEventListener('click', function(e) { ATTRIBUTE_MENU.classList.remove('hidden'); - ATTRIBUTE_MENU.style.top = getOffset(elem).bottom + 'px'; - ATTRIBUTE_MENU.style.left = getOffset(elem).left + 'px'; + ATTRIBUTE_MENU.style.top = getOffset(e.target).bottom + 'px'; + ATTRIBUTE_MENU.style.left = getOffset(e.target).left + 'px'; ATTRIBUTE_SEARCH.focus(); diff --git a/resources/js/blocks.js b/resources/js/blocks.js index a733453..ed40983 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -56,6 +56,21 @@ function BlockWrapper(inPalette) { this.deleteBlock = function() { block.removeFromParent(); block.elem.parentElement.removeChild(block.elem); + let child; + while(child = block.children.pop()) child.deleteBlock(); + let attr; + while(attr = block.attrs.pop()) attr.deleteAttr(); + let input; + while(input = block.inputs.pop()) input.deleteInput(); + + if(block.type == BLOCK_TYPES.stack + || block.type == BLOCK_TYPES.cblock) { + if(block.block_context_menu) block.elem.removeEventListener('contextmenu', block.block_context_menu); + if(block.block_mouse_down) block.elem.removeEventListener('mousedown', block.block_mouse_down); + if(block.block_mouse_up) block.elem.removeEventListener('mouseup', block.block_mouse_up); + if(block.add_quicktext) block.quickText.removeEventListener('click', block.add_quicktext); + } + blocksDatabase[block.id] = null; let index1 = scriptBlocks.indexOf(block); if(index1 != -1) scriptBlocks[index1] = null; @@ -222,7 +237,7 @@ function Block(type, name, opts) { this.quickText.appendChild(document.createTextNode('Aa')) footer.appendChild(this.quickText); - this.quickText.addEventListener('click', function(ev) { + this.quickText.addEventListener('click', block.add_quicktext = function(ev) { var newBlock = new Block(BLOCK_TYPES.stack, 'text', { hasAttrs: false, hasQuickText: false, @@ -283,7 +298,7 @@ function Block(type, name, opts) { }); }; - block.elem.addEventListener('contextmenu', function(ev) { + block.elem.addEventListener('contextmenu', block.block_context_menu = function(ev) { ev.preventDefault(); if(block.inPalette || block.unmoveable) return false; @@ -293,11 +308,10 @@ function Block(type, name, opts) { RIGHT_CLICKED_SCRIPT = block; setTimeout(function() { - document.body.addEventListener('click', function context_blur(e2) { + document.body.addEventListener('click', function() { SCRIPT_MENU.style.display = 'none'; RIGHT_CLICKED_SCRIPT = undefined; - document.body.removeEventListener('click', context_blur); - }); + }, {once: true}); }, 0); }); @@ -320,7 +334,7 @@ function Block(type, name, opts) { return false; } - this.elem.addEventListener('mousedown', function(ev) { + this.elem.addEventListener('mousedown', block.block_mouse_down = function(ev) { if (ev.which == 3 || testBlockContents(ev.target)) return; ev.stopPropagation(); @@ -335,7 +349,7 @@ function Block(type, name, opts) { setFrameContent(); }); - this.elem.addEventListener('mouseup', function(ev) { + this.elem.addEventListener('mouseup', block.block_mouse_up = function(ev) { trashCan = document.getElementById('trashCan'); trashCan.classList.remove('showing'); }); @@ -358,7 +372,7 @@ function BlockInput(defaultValue) { this.elem.addEventListener('input', cleanse_contenteditable); var input = this; - this.elem.addEventListener('input', function(e) { + this.elem.addEventListener('input', input.on_input = function(e) { input.value = input.elem.textContent; }); @@ -366,6 +380,9 @@ function BlockInput(defaultValue) { block.header.appendChild(input.elem); block.inputs.push(input); }; + this.deleteInput = function() { + this.elem.removeEventListener('input', input.on_input); + } } function removeDropArea() { From cf3550fdc4bb36360528fd41391e5ad06df9a3bd Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Mon, 17 Apr 2017 19:43:06 -0600 Subject: [PATCH 42/48] more attempt to plug memory leaks, p.s. this is miserable and I have no idea how to know if it works --- resources/js/blockAttributes.js | 11 +---------- resources/js/blocks.js | 26 ++++++++++++++++++-------- resources/js/files.js | 4 +++- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index f7e05a5..74b8b57 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -37,19 +37,10 @@ function BlockAttribute(name, value) { this.deleteAttr = function() { attr.elem.removeEventListener('input', attr.on_input); + attr.elem.parent.removeChild(attr.elem); } } -function add_attr(block, name, value) { - var attr = new BlockAttribute(name, value); - block.header.insertBefore(attr.elem, block.attrControls); - block.attrs.push(attr); -} -function remove_attr(block) { - var attrs = block.attr.pop(); - block.header.removeChild(attr.elem); -} - function attachAttrSearch(elem, attrNames, callback) { var ATTRIBUTE_MENU = document.getElementById('blockAttributeDropdown'); var ATTRIBUTE_SEARCH = document.getElementById('propSearch'); diff --git a/resources/js/blocks.js b/resources/js/blocks.js index ed40983..69076dc 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -69,6 +69,8 @@ function BlockWrapper(inPalette) { if(block.block_mouse_down) block.elem.removeEventListener('mousedown', block.block_mouse_down); if(block.block_mouse_up) block.elem.removeEventListener('mouseup', block.block_mouse_up); if(block.add_quicktext) block.quickText.removeEventListener('click', block.add_quicktext); + if(block.add_attr_ev) block.addAttr.removeEventListener('click', block.add_attr_ev); + if(block.remove_attr_ev) block.removeAttr.removeEventListener('click', block.remove_attr_ev); } blocksDatabase[block.id] = null; @@ -261,15 +263,22 @@ function Block(type, name, opts) { this.attrControls = document.createElement('span'); this.attrControls.classList.add('attr-controls'); - let removeAttr = document.createElement('span'); - removeAttr.classList.add('remove-attr'); - this.attrControls.appendChild(removeAttr); - removeAttr.addEventListener('click', function(e) {remove_attr(block)}); + this.removeAttr = document.createElement('span'); + this.removeAttr.classList.add('remove-attr'); + this.attrControls.appendChild(this.removeAttr); + this.removeAttr.addEventListener('click', block.remove_attr_ev = function(e) { + var attr = block.attr.pop(); + block.header.removeChild(attr.elem); + }); - let addAttr = document.createElement('span'); - addAttr.classList.add('add-attr'); - this.attrControls.appendChild(addAttr); - addAttr.addEventListener('click', function(e) {add_attr(block)}); + this.addAttr = document.createElement('span'); + this.addAttr.classList.add('add-attr'); + this.attrControls.appendChild(this.addAttr); + this.addAttr.addEventListener('click', block.add_attr_ev = function(e) { + var attr = new BlockAttribute(); + block.header.insertBefore(attr.elem, block.attrControls); + block.attrs.push(attr); + }); this.header.appendChild(this.attrControls); } @@ -382,6 +391,7 @@ function BlockInput(defaultValue) { }; this.deleteInput = function() { this.elem.removeEventListener('input', input.on_input); + this.elem.parent.removeChild(this.elem); } } diff --git a/resources/js/files.js b/resources/js/files.js index 11e92c3..dc406d1 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -95,7 +95,9 @@ function generateBlocks(jsonData, ext) { ftype: block.ftype }); for(let attr of block.attrs) { - add_attr(newBlock, attr.name, attr.value); + var newAttr = new BlockAttribute(attr.name, attr.value); + newBlock.header.insertBefore(newAttr.elem, mewBlock.attrControls); + newBlock.attrs.push(newAttr); } } else { return null; // other types of blocks are generated in block constructors From 645f8e0284e8eb4c698514630712c636eaf44894 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Mon, 17 Apr 2017 19:44:09 -0600 Subject: [PATCH 43/48] tpyo --- resources/js/files.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/files.js b/resources/js/files.js index dc406d1..1e6f1dc 100644 --- a/resources/js/files.js +++ b/resources/js/files.js @@ -96,7 +96,7 @@ function generateBlocks(jsonData, ext) { }); for(let attr of block.attrs) { var newAttr = new BlockAttribute(attr.name, attr.value); - newBlock.header.insertBefore(newAttr.elem, mewBlock.attrControls); + newBlock.header.insertBefore(newAttr.elem, newBlock.attrControls); newBlock.attrs.push(newAttr); } } else { From ec872a85b7808662164e01b42759553ee15c0114 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Mon, 17 Apr 2017 20:00:51 -0600 Subject: [PATCH 44/48] delEt aLL th1NGS --- resources/js/blockAttributes.js | 2 +- resources/js/blocks.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index 74b8b57..1ecb4d5 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -37,7 +37,7 @@ function BlockAttribute(name, value) { this.deleteAttr = function() { attr.elem.removeEventListener('input', attr.on_input); - attr.elem.parent.removeChild(attr.elem); + if(attr.elem.parent) attr.elem.parent.removeChild(attr.elem); } } diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 69076dc..fc369db 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -78,6 +78,9 @@ function BlockWrapper(inPalette) { if(index1 != -1) scriptBlocks[index1] = null; let index2 = topLevelBlocks.indexOf(block); if(index2 != -1) topLevelBlocks[index2] = null; + + let keys = Object.keys(block).slice(); + for(let key of keys) delete block[key]; }; this.getClosestBlock = function() { var el = null, @@ -391,7 +394,7 @@ function BlockInput(defaultValue) { }; this.deleteInput = function() { this.elem.removeEventListener('input', input.on_input); - this.elem.parent.removeChild(this.elem); + if(this.elem.parent) this.elem.parent.removeChild(this.elem); } } From 769003ab1361c3da4e3b84d6aa71cc8b9ce6e0c2 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Mon, 17 Apr 2017 22:06:30 -0600 Subject: [PATCH 45/48] everything is garbage --- resources/js/blockAttributes.js | 4 ++++ resources/js/blocks.js | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/resources/js/blockAttributes.js b/resources/js/blockAttributes.js index 1ecb4d5..9832e74 100644 --- a/resources/js/blockAttributes.js +++ b/resources/js/blockAttributes.js @@ -38,6 +38,10 @@ function BlockAttribute(name, value) { this.deleteAttr = function() { attr.elem.removeEventListener('input', attr.on_input); if(attr.elem.parent) attr.elem.parent.removeChild(attr.elem); + + let keys = Object.keys(attr).slice(); + for(let key of keys) delete attr[key]; + attr = null; } } diff --git a/resources/js/blocks.js b/resources/js/blocks.js index fc369db..df5bec7 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -81,6 +81,7 @@ function BlockWrapper(inPalette) { let keys = Object.keys(block).slice(); for(let key of keys) delete block[key]; + block = null; }; this.getClosestBlock = function() { var el = null, @@ -395,6 +396,10 @@ function BlockInput(defaultValue) { this.deleteInput = function() { this.elem.removeEventListener('input', input.on_input); if(this.elem.parent) this.elem.parent.removeChild(this.elem); + + let keys = Object.keys(input).slice(); + for(let key of keys) delete input[key]; + input = null; } } From fe6d86b1cfe82bcb80618db67052b766f303cabf Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Mon, 17 Apr 2017 22:29:07 -0600 Subject: [PATCH 46/48] =?UTF-8?q?bugfix=20that=20I=20don=E2=80=99t=20under?= =?UTF-8?q?stand=20why=20it=E2=80=99s=20necessary=20but=20ok?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/blocks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/js/blocks.js b/resources/js/blocks.js index df5bec7..b4a5dc9 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -96,13 +96,13 @@ function BlockWrapper(inPalette) { let pblock = block; while(pblock) { if (pblock == oblock - || pblock.children.indexOf(oblock) != -1) continue blocks; + || (pblock.children && pblock.children.indexOf(oblock) != -1)) continue blocks; pblock = pblock.parent; } pblock = oblock; while(pblock) { if (pblock == block - || pblock.children.indexOf(block) != -1) continue blocks; + || (pblock.children && pblock.children.indexOf(block) != -1)) continue blocks; pblock = pblock.parent; } From 44e39414b71927f3f2a5899f17700f2d0c7eee00 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 3 May 2017 02:01:41 -0600 Subject: [PATCH 47/48] garbage collection; per request: - prettier (rounded) block highlighting - highlight both block and element simultaneously --- resources/css/blocks.css | 16 ++++++++++++++++ resources/css/blocks.scss | 19 ++++++++++++++++++- resources/css/style.css | 18 ++++++++++++++++++ resources/js/block2json.js | 20 ++++++++++++-------- resources/js/blocks.js | 13 +++++++------ 5 files changed, 71 insertions(+), 15 deletions(-) diff --git a/resources/css/blocks.css b/resources/css/blocks.css index 93d9a4a..e48766b 100644 --- a/resources/css/blocks.css +++ b/resources/css/blocks.css @@ -141,6 +141,22 @@ body { .c-wrapper.zebra > li, .c-wrapper.zebra > ul { background: #F45D5D; } +.highlightBlock { + position: relative; + z-index: 1; } + +.highlightBlock::after { + content: ""; + display: block; + background: gold; + border-radius: 5px; + position: absolute; + top: -3px; + right: -3px; + bottom: -3px; + left: -3px; + z-index: -1; } + .remove-attr { display: inline-block; width: 0px; diff --git a/resources/css/blocks.scss b/resources/css/blocks.scss index 7ecb942..ab8ca3e 100644 --- a/resources/css/blocks.scss +++ b/resources/css/blocks.scss @@ -147,6 +147,23 @@ body { background:#F45D5D; } +.highlightBlock { + position: relative; + z-index: 1; +} +.highlightBlock::after { + content: ""; + display: block; + background: gold; + border-radius: 5px; + position: absolute; + top: -3px; + right: -3px; + bottom: -3px; + left: -3px; + z-index: -1; +} + .remove-attr { display:inline-block; width:0px; @@ -197,4 +214,4 @@ body { color:black; cursor:text; } -} \ No newline at end of file +} diff --git a/resources/css/style.css b/resources/css/style.css index 325703d..752ff52 100644 --- a/resources/css/style.css +++ b/resources/css/style.css @@ -142,6 +142,22 @@ body { .c-wrapper.zebra > li, .c-wrapper.zebra > ul { background: #F45D5D; } +.highlightBlock { + position: relative; + z-index: 1; } + +.highlightBlock::after { + content: ""; + display: block; + background: gold; + border-radius: 5px; + position: absolute; + top: -3px; + right: -3px; + bottom: -3px; + left: -3px; + z-index: -1; } + .remove-attr { display: inline-block; width: 0px; @@ -612,3 +628,5 @@ html, body { @media (max-width: 450px) { .advanceWrap { display: none; } } + +/*# sourceMappingURL=style.css.map */ diff --git a/resources/js/block2json.js b/resources/js/block2json.js index 49d2d2d..c38960e 100644 --- a/resources/js/block2json.js +++ b/resources/js/block2json.js @@ -25,6 +25,15 @@ function blockToCSS(blockList) { function blockToHTML(block) { var out = null; + + // attempt at garbage collection + if(block.htmlElem) { + block.htmlElem.removeEventListener('mouseover', block.block_mouse_over); + block.htmlElem.removeEventListener('mouseout', block.block_mouse_out); + if(block.htmlElem.parentNode) block.htmlElem.parentNode.removeChild(block.htmlElem); + block.htmlElem = null; + } + if(block.type !== BLOCK_TYPES.stack && block.type !== BLOCK_TYPES.cblock) { out = null; } else if(block.name == 'text') { @@ -39,14 +48,9 @@ function blockToHTML(block) { if(parsedChild) out.appendChild(parsedChild); } block.htmlElem = out; - } - if(out) { - out.addEventListener('mouseover', function() { - block.elem.style.outline = '3px solid gold'; - }); - out.addEventListener('mouseout', function() { - block.elem.style.outline = ''; - }); + + out.addEventListener('mouseover', block.block_mouse_over); + out.addEventListener('mouseout', block.block_mouse_out); } return out; } diff --git a/resources/js/blocks.js b/resources/js/blocks.js index 729b01c..a0e0396 100644 --- a/resources/js/blocks.js +++ b/resources/js/blocks.js @@ -67,6 +67,8 @@ function BlockWrapper(inPalette) { || block.type == BLOCK_TYPES.cblock) { if(block.block_context_menu) block.elem.removeEventListener('contextmenu', block.block_context_menu); if(block.block_mouse_down) block.elem.removeEventListener('mousedown', block.block_mouse_down); + if(block.block_mouse_over) block.elem.removeEventListener('mouseover', block.block_mouse_over); + if(block.block_mouse_out) block.elem.removeEventListener('mouseout', block.block_mouse_out); if(block.block_mouse_up) block.elem.removeEventListener('mouseup', block.block_mouse_up); if(block.add_quicktext) block.quickText.removeEventListener('click', block.add_quicktext); if(block.add_attr_ev) block.addAttr.removeEventListener('click', block.add_attr_ev); @@ -347,18 +349,17 @@ function Block(type, name, opts) { return false; } - this.elem.addEventListener('mouseover', function(ev) { + this.elem.addEventListener('mouseover', block.block_mouse_over = function(ev) { if(block.htmlElem) { + ev.stopPropagation(); + block.elem.classList.add('highlightBlock'); block.htmlElem.style.outline = '3px solid gold'; - } else if(block.name == 'text' && block.parent && block.parent.htmlElem) { - block.parent.htmlElem.style.outline = '3px solid gold'; } }); - this.elem.addEventListener('mouseout', function(ev) { + this.elem.addEventListener('mouseout', block.block_mouse_out = function(ev) { if(block.htmlElem) { + block.elem.classList.remove('highlightBlock'); block.htmlElem.style.outline = ''; - } else if(block.name == 'text' && block.parent && block.parent.htmlElem) { - block.parent.htmlElem.style.outline = ''; } }); From 5fe6909c2497b0b1fb5bb989fbc1e57b63f55222 Mon Sep 17 00:00:00 2001 From: Jacob Bloom Date: Wed, 3 May 2017 12:40:32 -0600 Subject: [PATCH 48/48] make highlighting toggleable, more garbage collection stuff --- index.html | 7 +++++++ resources/js/block2json.js | 9 ++++++--- resources/js/blocks.js | 7 +++++-- resources/js/menu.js | 11 +++++++++++ 4 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 resources/js/menu.js diff --git a/index.html b/index.html index 9bd6295..4d73a0d 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,12 @@
    • Find
    +