diff --git a/client/src/entrypoints/admin/telepath/blocks.js b/client/src/entrypoints/admin/telepath/blocks.js index d3264215b6..928a2396f4 100644 --- a/client/src/entrypoints/admin/telepath/blocks.js +++ b/client/src/entrypoints/admin/telepath/blocks.js @@ -279,12 +279,15 @@ class StreamChild { this.blockDef = blockDef; this.type = blockDef.name; this.prefix = prefix; + this.index = index; this.id = id; + const animate = opts && opts.animate; + this.onRequestDelete = opts && opts.onRequestDelete; const dom = $(`
- + @@ -305,7 +308,8 @@ class StreamChild { -
@@ -326,13 +330,30 @@ class StreamChild { this.block = this.blockDef.render(blockElement, this.prefix + '-value', state); this.indexInput = dom.find('[data-streamblock-index]'); + this.deletedInput = dom.find('[data-streamblock-deleted]'); + + dom.find('[data-streamblock-delete-button]').click(() => { + if (this.onRequestDelete) this.onRequestDelete(this.index); + }); if (animate) { dom.hide().slideDown(); } } + markDeleted(animate) { + this.deletedInput.val('1'); + if (animate) { + $(this.element).slideUp().dequeue() + .fadeOut() + .attr('aria-hidden', 'true'); + } else { + $(this.element).hide().attr('aria-hidden', 'true'); + } + } + setIndex(newIndex) { + this.index = newIndex; this.indexInput.val(newIndex); } @@ -417,6 +438,10 @@ class StreamBlockMenu { } } + setIndex(newIndex) { + this.index = newIndex; + } + toggle() { if (this.isOpen) { this.close(true); @@ -444,6 +469,9 @@ class StreamBlockMenu { this.outerContainer.attr('aria-hidden', 'true'); this.isOpen = false; } + delete() { + $(this.element).hide().attr('aria-hidden', 'true'); + } } class StreamBlock { @@ -460,10 +488,21 @@ class StreamBlock { `); $(placeholder).replaceWith(dom); + // StreamChild objects for the current (non-deleted) child blocks this.children = []; + + // StreamBlockMenu objects - there are one more of these than there are children. + // The menu at index n will insert a block at index n this.menus = []; + + // Incrementing counter used to generate block prefixes, also reflected in the + // 'count' hidden input. This count includes deleted items this.blockCounter = 0; this.countInput = dom.find('[data-streamfield-stream-count]'); + + // Parent element of menu and block elements (potentially including deleted items, + // which are left behind as hidden elements with a '-deleted' input so that the + // server-side form handler knows to skip it) this.streamContainer = dom.find('[data-streamfield-stream-container]'); this.setState(initialState || []); } @@ -513,10 +552,13 @@ class StreamBlock { this.children[i].setIndex(i + 1); } for (let i = index + 1; i < this.menus.length; i++) { - this.menus[i].index = i + 1; + this.menus[i].setIndex(i + 1); } - const child = new StreamChild(blockDef, blockPlaceholder, prefix, index, id, value, { animate }); + const child = new StreamChild(blockDef, blockPlaceholder, prefix, index, id, value, { + animate, + onRequestDelete: (i) => { this.deleteBlock(i); } + }); this.children.splice(index, 0, child); const menu = new StreamBlockMenu( @@ -530,7 +572,7 @@ class StreamBlock { ); this.menus.splice(index + 1, 0, menu); - this.countInput.val(this.children.length); + this.countInput.val(this.blockCounter); return child; } @@ -543,6 +585,22 @@ class StreamBlock { newBlock.focus(); } + deleteBlock(index) { + this.children[index].markDeleted(true); + this.menus[index].delete(); + this.children.splice(index, 1); + this.menus.splice(index, 1); + + /* index numbers of children / menus above this index now need updating to match + their array indexes */ + for (let i = index; i < this.children.length; i++) { + this.children[i].setIndex(i); + } + for (let i = index; i < this.menus.length; i++) { + this.menus[i].setIndex(i); + } + } + setState(values) { this.clear(); values.forEach((val, i) => {