kopia lustrzana https://github.com/wagtail/wagtail
Add BaseSequenceBlock superclass
rodzic
320c639255
commit
4ee65760fe
|
@ -1,3 +1,5 @@
|
|||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
/* global $ */
|
||||
|
||||
import { escapeHtml as h } from '../../../utils/text';
|
||||
|
@ -151,3 +153,218 @@ export class BaseInsertionControl {
|
|||
$(this.element).hide().attr('aria-hidden', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class BaseSequenceBlock {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
_createChild(blockDef, placeholder, prefix, index, id, initialState, opts) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
_createInsertionControl(placeholder, opts) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
_getChildDataForInsertion(opts) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.countInput.val(0);
|
||||
this.sequenceContainer.empty();
|
||||
this.children = [];
|
||||
this.blockCounter = 0;
|
||||
|
||||
// Create initial insertion control
|
||||
const placeholder = document.createElement('div');
|
||||
this.sequenceContainer.append(placeholder);
|
||||
this.inserters = [
|
||||
this._createInsertionControl(
|
||||
placeholder, {
|
||||
index: 0,
|
||||
onRequestInsert: (newIndex, opts) => {
|
||||
this._onRequestInsert(newIndex, opts);
|
||||
},
|
||||
strings: this.blockDef.meta.strings,
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
_onRequestInsert(index, opts) {
|
||||
/* handler for an 'insert new block' action */
|
||||
const [blockDef, initialState] = this._getChildDataForInsertion(opts);
|
||||
const newChild = this._insert(blockDef, initialState, null, index, { animate: true });
|
||||
newChild.focus();
|
||||
}
|
||||
|
||||
|
||||
_insert(childBlockDef, initialState, id, index, opts) {
|
||||
const prefix = this.prefix + '-' + this.blockCounter;
|
||||
const animate = opts && opts.animate;
|
||||
this.blockCounter++;
|
||||
|
||||
/*
|
||||
a new inserter and block will be inserted AFTER the inserter with the given index;
|
||||
e.g if there are 3 blocks the children of sequenceContainer will be
|
||||
[inserter 0, block 0, inserter 1, block 1, inserter 2, block 2, inserter 3]
|
||||
and inserting a new block at index 1 will create a new block 1 and inserter 2 after the
|
||||
current inserter 1, and increment everything after that point
|
||||
*/
|
||||
const existingInserterElement = this.inserters[index].element;
|
||||
const blockPlaceholder = document.createElement('div');
|
||||
const inserterPlaceholder = document.createElement('div');
|
||||
$(blockPlaceholder).insertAfter(existingInserterElement);
|
||||
$(inserterPlaceholder).insertAfter(blockPlaceholder);
|
||||
|
||||
/* shuffle up indexes of all blocks / inserters above this index */
|
||||
for (let i = index; i < this.children.length; i++) {
|
||||
this.children[i].setIndex(i + 1);
|
||||
}
|
||||
for (let i = index + 1; i < this.inserters.length; i++) {
|
||||
this.inserters[i].setIndex(i + 1);
|
||||
}
|
||||
|
||||
const child = this._createChild(childBlockDef, blockPlaceholder, prefix, index, id, initialState, {
|
||||
animate,
|
||||
onRequestDuplicate: (i) => { this.duplicateBlock(i); },
|
||||
onRequestDelete: (i) => { this.deleteBlock(i); },
|
||||
onRequestMoveUp: (i) => { this.moveBlock(i, i - 1); },
|
||||
onRequestMoveDown: (i) => { this.moveBlock(i, i + 1); },
|
||||
strings: this.blockDef.meta.strings,
|
||||
});
|
||||
this.children.splice(index, 0, child);
|
||||
|
||||
const inserter = this._createInsertionControl(
|
||||
inserterPlaceholder, {
|
||||
index: index + 1,
|
||||
onRequestInsert: (newIndex, inserterOpts) => {
|
||||
this._onRequestInsert(newIndex, inserterOpts);
|
||||
},
|
||||
strings: this.blockDef.meta.strings,
|
||||
}
|
||||
);
|
||||
this.inserters.splice(index + 1, 0, inserter);
|
||||
|
||||
this.countInput.val(this.blockCounter);
|
||||
|
||||
const isFirstChild = (index === 0);
|
||||
const isLastChild = (index === this.children.length - 1);
|
||||
if (!isFirstChild) {
|
||||
child.enableMoveUp();
|
||||
if (isLastChild) {
|
||||
/* previous child (which was previously the last one) can now move down */
|
||||
this.children[index - 1].enableMoveDown();
|
||||
}
|
||||
}
|
||||
if (!isLastChild) {
|
||||
child.enableMoveDown();
|
||||
if (isFirstChild) {
|
||||
/* next child (which was previously the first one) can now move up */
|
||||
this.children[index + 1].enableMoveUp();
|
||||
}
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
deleteBlock(index) {
|
||||
this.children[index].markDeleted({ animate: true });
|
||||
this.inserters[index].delete();
|
||||
this.children.splice(index, 1);
|
||||
this.inserters.splice(index, 1);
|
||||
|
||||
/* index numbers of children / inserters 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.inserters.length; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
}
|
||||
|
||||
if (index === 0 && this.children.length > 0) {
|
||||
/* we have removed the first child; the new first child cannot be moved up */
|
||||
this.children[0].disableMoveUp();
|
||||
}
|
||||
if (index === this.children.length && this.children.length > 0) {
|
||||
/* we have removed the last child; the new last child cannot be moved down */
|
||||
this.children[this.children.length - 1].disableMoveDown();
|
||||
}
|
||||
}
|
||||
|
||||
moveBlock(oldIndex, newIndex) {
|
||||
if (oldIndex === newIndex) return;
|
||||
const inserterToMove = this.inserters[oldIndex];
|
||||
const childToMove = this.children[oldIndex];
|
||||
|
||||
/* move HTML elements */
|
||||
if (newIndex > oldIndex) {
|
||||
$(inserterToMove.element).insertAfter(this.children[newIndex].element);
|
||||
} else {
|
||||
$(inserterToMove.element).insertBefore(this.inserters[newIndex].element);
|
||||
}
|
||||
$(childToMove.element).insertAfter(inserterToMove.element);
|
||||
|
||||
/* reorder items in the `inserters` and `children` arrays */
|
||||
this.inserters.splice(oldIndex, 1);
|
||||
this.inserters.splice(newIndex, 0, inserterToMove);
|
||||
this.children.splice(oldIndex, 1);
|
||||
this.children.splice(newIndex, 0, childToMove);
|
||||
|
||||
/* update index properties of moved items */
|
||||
if (newIndex > oldIndex) {
|
||||
for (let i = oldIndex; i <= newIndex; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
this.children[i].setIndex(i);
|
||||
}
|
||||
} else {
|
||||
for (let i = newIndex; i <= oldIndex; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
this.children[i].setIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
/* enable/disable up/down arrows as required */
|
||||
const maxIndex = this.children.length - 1;
|
||||
if (oldIndex === 0) {
|
||||
childToMove.enableMoveUp();
|
||||
this.children[0].disableMoveUp();
|
||||
}
|
||||
if (oldIndex === maxIndex) {
|
||||
childToMove.enableMoveDown();
|
||||
this.children[maxIndex].disableMoveDown();
|
||||
}
|
||||
if (newIndex === 0) {
|
||||
childToMove.disableMoveUp();
|
||||
this.children[1].enableMoveUp();
|
||||
}
|
||||
if (newIndex === maxIndex) {
|
||||
childToMove.disableMoveDown();
|
||||
this.children[maxIndex - 1].enableMoveDown();
|
||||
}
|
||||
}
|
||||
|
||||
setState(values) {
|
||||
this.clear();
|
||||
values.forEach((val, i) => {
|
||||
this.insert(val, i);
|
||||
});
|
||||
}
|
||||
|
||||
getState() {
|
||||
return this.children.map(child => child.getState());
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.children.map(child => child.getValue());
|
||||
}
|
||||
|
||||
focus() {
|
||||
if (this.children.length) {
|
||||
this.children[0].focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
import { BaseSequenceChild, BaseInsertionControl } from './BaseSequenceBlock';
|
||||
import { BaseSequenceBlock, BaseSequenceChild, BaseInsertionControl } from './BaseSequenceBlock';
|
||||
import { escapeHtml as h } from '../../../utils/text';
|
||||
|
||||
/* global $ */
|
||||
|
@ -51,7 +51,7 @@ class InsertPosition extends BaseInsertionControl {
|
|||
}
|
||||
}
|
||||
|
||||
export class ListBlock {
|
||||
export class ListBlock extends BaseSequenceBlock {
|
||||
constructor(blockDef, placeholder, prefix, initialState, initialError) {
|
||||
this.blockDef = blockDef;
|
||||
this.type = blockDef.name;
|
||||
|
@ -81,7 +81,7 @@ export class ListBlock {
|
|||
this.inserters = [];
|
||||
this.blockCounter = 0;
|
||||
this.countInput = dom.find('[data-streamfield-list-count]');
|
||||
this.listContainer = dom.find('[data-streamfield-list-container]');
|
||||
this.sequenceContainer = dom.find('[data-streamfield-list-container]');
|
||||
this.setState(initialState || []);
|
||||
|
||||
if (initialError) {
|
||||
|
@ -89,28 +89,6 @@ export class ListBlock {
|
|||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.countInput.val(0);
|
||||
this.listContainer.empty();
|
||||
this.children = [];
|
||||
this.blockCounter = 0;
|
||||
|
||||
// Create initial insert position
|
||||
const placeholder = document.createElement('div');
|
||||
this.listContainer.append(placeholder);
|
||||
this.inserters = [
|
||||
this._createInsertionControl(
|
||||
placeholder, {
|
||||
index: 0,
|
||||
onRequestInsert: (newIndex, opts) => {
|
||||
this._onRequestInsert(newIndex, opts);
|
||||
},
|
||||
strings: this.blockDef.meta.strings,
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
_getChildDataForInsertion() {
|
||||
/* Called when an 'insert new block' action is triggered: given a dict of data from the insertion control,
|
||||
return the block definition and initial state to be used for the new block.
|
||||
|
@ -121,13 +99,6 @@ export class ListBlock {
|
|||
return [blockDef, initialState];
|
||||
}
|
||||
|
||||
_onRequestInsert(index, opts) {
|
||||
/* handler for an 'insert new block' action */
|
||||
const [blockDef, initialState] = this._getChildDataForInsertion(opts);
|
||||
const newChild = this._insert(blockDef, initialState, null, index, { animate: true });
|
||||
newChild.focus();
|
||||
}
|
||||
|
||||
_createChild(blockDef, placeholder, prefix, index, id, initialState, opts) {
|
||||
return new ListChild(blockDef, placeholder, prefix, index, id, initialState, opts);
|
||||
}
|
||||
|
@ -140,163 +111,12 @@ export class ListBlock {
|
|||
return this._insert(this.blockDef.childBlockDef, value, null, index, opts);
|
||||
}
|
||||
|
||||
_insert(childBlockDef, initialState, id, index, opts) {
|
||||
const prefix = this.prefix + '-' + this.blockCounter;
|
||||
const animate = opts && opts.animate;
|
||||
this.blockCounter++;
|
||||
|
||||
/*
|
||||
a new insert position and block will be inserted AFTER the insert position with the given index;
|
||||
e.g if there are 3 blocks the children of listContainer will be
|
||||
[insert pos 0, block 0, insert pos 1, block 1, insert pos 2, block 2, insert pos 3]
|
||||
and inserting a new block at index 1 will create a new block 1 and insert position 2 after the
|
||||
current menu 1, and increment everything after that point
|
||||
*/
|
||||
const existingInsertPositionElement = this.inserters[index].element;
|
||||
const blockPlaceholder = document.createElement('div');
|
||||
const inserterPlaceholder = document.createElement('div');
|
||||
$(blockPlaceholder).insertAfter(existingInsertPositionElement);
|
||||
$(inserterPlaceholder).insertAfter(blockPlaceholder);
|
||||
|
||||
/* shuffle up indexes of all blocks / insert positions above this index */
|
||||
for (let i = index; i < this.children.length; i++) {
|
||||
this.children[i].setIndex(i + 1);
|
||||
}
|
||||
for (let i = index + 1; i < this.inserters.length; i++) {
|
||||
this.inserters[i].setIndex(i + 1);
|
||||
}
|
||||
|
||||
const child = this._createChild(childBlockDef, blockPlaceholder, prefix, index, id, initialState, {
|
||||
animate,
|
||||
onRequestDuplicate: (i) => { this.duplicateBlock(i); },
|
||||
onRequestDelete: (i) => { this.deleteBlock(i); },
|
||||
onRequestMoveUp: (i) => { this.moveBlock(i, i - 1); },
|
||||
onRequestMoveDown: (i) => { this.moveBlock(i, i + 1); },
|
||||
strings: this.blockDef.meta.strings,
|
||||
});
|
||||
this.children.splice(index, 0, child);
|
||||
|
||||
const inserter = this._createInsertionControl(
|
||||
inserterPlaceholder, {
|
||||
index: index + 1,
|
||||
onRequestInsert: (newIndex, inserterOpts) => {
|
||||
this._onRequestInsert(newIndex, inserterOpts);
|
||||
},
|
||||
strings: this.blockDef.meta.strings,
|
||||
}
|
||||
);
|
||||
this.inserters.splice(index + 1, 0, inserter);
|
||||
|
||||
this.countInput.val(this.blockCounter);
|
||||
|
||||
const isFirstChild = (index === 0);
|
||||
const isLastChild = (index === this.children.length - 1);
|
||||
if (!isFirstChild) {
|
||||
child.enableMoveUp();
|
||||
if (isLastChild) {
|
||||
/* previous child (which was previously the last one) can now move down */
|
||||
this.children[index - 1].enableMoveDown();
|
||||
}
|
||||
}
|
||||
if (!isLastChild) {
|
||||
child.enableMoveDown();
|
||||
if (isFirstChild) {
|
||||
/* next child (which was previously the first one) can now move up */
|
||||
this.children[index + 1].enableMoveUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
duplicateBlock(index) {
|
||||
const childState = this.children[index].getState();
|
||||
this.insert(childState, index + 1, { animate: true });
|
||||
this.children[index + 1].focus();
|
||||
}
|
||||
|
||||
deleteBlock(index) {
|
||||
this.children[index].markDeleted({ animate: true });
|
||||
this.inserters[index].delete();
|
||||
this.children.splice(index, 1);
|
||||
this.inserters.splice(index, 1);
|
||||
|
||||
/* index numbers of children / insert positions 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.inserters.length; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
}
|
||||
|
||||
if (index === 0 && this.children.length > 0) {
|
||||
/* we have removed the first child; the new first child cannot be moved up */
|
||||
this.children[0].disableMoveUp();
|
||||
}
|
||||
if (index === this.children.length && this.children.length > 0) {
|
||||
/* we have removed the last child; the new last child cannot be moved down */
|
||||
this.children[this.children.length - 1].disableMoveDown();
|
||||
}
|
||||
}
|
||||
|
||||
moveBlock(oldIndex, newIndex) {
|
||||
if (oldIndex === newIndex) return;
|
||||
const inserterToMove = this.inserters[oldIndex];
|
||||
const childToMove = this.children[oldIndex];
|
||||
|
||||
/* move HTML elements */
|
||||
if (newIndex > oldIndex) {
|
||||
$(inserterToMove.element).insertAfter(this.children[newIndex].element);
|
||||
} else {
|
||||
$(inserterToMove.element).insertBefore(this.inserters[newIndex].element);
|
||||
}
|
||||
$(childToMove.element).insertAfter(inserterToMove.element);
|
||||
|
||||
/* reorder items in the `insert positions` and `children` arrays */
|
||||
this.inserters.splice(oldIndex, 1);
|
||||
this.inserters.splice(newIndex, 0, inserterToMove);
|
||||
this.children.splice(oldIndex, 1);
|
||||
this.children.splice(newIndex, 0, childToMove);
|
||||
|
||||
/* update index properties of moved items */
|
||||
if (newIndex > oldIndex) {
|
||||
for (let i = oldIndex; i <= newIndex; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
this.children[i].setIndex(i);
|
||||
}
|
||||
} else {
|
||||
for (let i = newIndex; i <= oldIndex; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
this.children[i].setIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
/* enable/disable up/down arrows as required */
|
||||
const maxIndex = this.children.length - 1;
|
||||
if (oldIndex === 0) {
|
||||
childToMove.enableMoveUp();
|
||||
this.children[0].disableMoveUp();
|
||||
}
|
||||
if (oldIndex === maxIndex) {
|
||||
childToMove.enableMoveDown();
|
||||
this.children[maxIndex].disableMoveDown();
|
||||
}
|
||||
if (newIndex === 0) {
|
||||
childToMove.disableMoveUp();
|
||||
this.children[1].enableMoveUp();
|
||||
}
|
||||
if (newIndex === maxIndex) {
|
||||
childToMove.disableMoveDown();
|
||||
this.children[maxIndex - 1].enableMoveDown();
|
||||
}
|
||||
}
|
||||
|
||||
setState(values) {
|
||||
this.clear();
|
||||
values.forEach(val => {
|
||||
this.insert(val, this.children.length);
|
||||
});
|
||||
}
|
||||
|
||||
setError(errorList) {
|
||||
if (errorList.length !== 1) {
|
||||
return;
|
||||
|
@ -310,20 +130,6 @@ export class ListBlock {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
getState() {
|
||||
return this.children.map(child => child.getState());
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.children.map(child => child.getValue());
|
||||
}
|
||||
|
||||
focus() {
|
||||
if (this.children.length) {
|
||||
this.children[0].focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ListBlockDefinition {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable no-underscore-dangle */
|
||||
|
||||
import { BaseSequenceChild, BaseInsertionControl } from './BaseSequenceBlock';
|
||||
import { BaseSequenceBlock, BaseSequenceChild, BaseInsertionControl } from './BaseSequenceBlock';
|
||||
import { escapeHtml as h } from '../../../utils/text';
|
||||
|
||||
/* global $ */
|
||||
|
@ -126,7 +126,7 @@ class StreamBlockMenu extends BaseInsertionControl {
|
|||
}
|
||||
}
|
||||
|
||||
export class StreamBlock {
|
||||
export class StreamBlock extends BaseSequenceBlock {
|
||||
constructor(blockDef, placeholder, prefix, initialState, initialError) {
|
||||
this.blockDef = blockDef;
|
||||
this.type = blockDef.name;
|
||||
|
@ -167,7 +167,7 @@ export class StreamBlock {
|
|||
// Parent element of insert control 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.sequenceContainer = dom.find('[data-streamfield-stream-container]');
|
||||
this.setState(initialState || []);
|
||||
this.container = dom;
|
||||
|
||||
|
@ -176,27 +176,6 @@ export class StreamBlock {
|
|||
}
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.countInput.val(0);
|
||||
this.streamContainer.empty();
|
||||
this.children = [];
|
||||
this.blockCounter = 0;
|
||||
|
||||
const placeholder = document.createElement('div');
|
||||
this.streamContainer.append(placeholder);
|
||||
this.inserters = [
|
||||
this._createInsertionControl(
|
||||
placeholder, {
|
||||
index: 0,
|
||||
onRequestInsert: (index, opts) => {
|
||||
this._onRequestInsert(index, opts);
|
||||
},
|
||||
strings: this.blockDef.meta.strings,
|
||||
}
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
_createChild(blockDef, placeholder, prefix, index, id, initialState, opts) {
|
||||
return new StreamChild(blockDef, placeholder, prefix, index, id, initialState, opts);
|
||||
}
|
||||
|
@ -212,75 +191,6 @@ export class StreamBlock {
|
|||
return this._insert(childBlockDef, value, id, index, opts);
|
||||
}
|
||||
|
||||
_insert(childBlockDef, initialState, id, index, opts) {
|
||||
const prefix = this.prefix + '-' + this.blockCounter;
|
||||
const animate = opts && opts.animate;
|
||||
this.blockCounter++;
|
||||
|
||||
/*
|
||||
a new inserter and block will be inserted AFTER the inserter with the given index;
|
||||
e.g if there are 3 blocks the children of streamContainer will be
|
||||
[inserter 0, block 0, inserter 1, block 1, inserter 2, block 2, inserter 3]
|
||||
and inserting a new block at index 1 will create a new block 1 and inserter 2 after the
|
||||
current inserter 1, and increment everything after that point
|
||||
*/
|
||||
const existingMenuElement = this.inserters[index].element;
|
||||
const blockPlaceholder = document.createElement('div');
|
||||
const inserterPlaceholder = document.createElement('div');
|
||||
$(blockPlaceholder).insertAfter(existingMenuElement);
|
||||
$(inserterPlaceholder).insertAfter(blockPlaceholder);
|
||||
|
||||
/* shuffle up indexes of all blocks / inserters above this index */
|
||||
for (let i = index; i < this.children.length; i++) {
|
||||
this.children[i].setIndex(i + 1);
|
||||
}
|
||||
for (let i = index + 1; i < this.inserters.length; i++) {
|
||||
this.inserters[i].setIndex(i + 1);
|
||||
}
|
||||
|
||||
const child = this._createChild(childBlockDef, blockPlaceholder, prefix, index, id, initialState, {
|
||||
animate,
|
||||
onRequestDuplicate: (i) => { this.duplicateBlock(i); },
|
||||
onRequestDelete: (i) => { this.deleteBlock(i); },
|
||||
onRequestMoveUp: (i) => { this.moveBlock(i, i - 1); },
|
||||
onRequestMoveDown: (i) => { this.moveBlock(i, i + 1); },
|
||||
strings: this.blockDef.meta.strings,
|
||||
});
|
||||
this.children.splice(index, 0, child);
|
||||
|
||||
const inserter = this._createInsertionControl(
|
||||
inserterPlaceholder, {
|
||||
index: index + 1,
|
||||
onRequestInsert: (newIndex, inserterOpts) => {
|
||||
this._onRequestInsert(newIndex, inserterOpts);
|
||||
},
|
||||
strings: this.blockDef.meta.strings,
|
||||
}
|
||||
);
|
||||
this.inserters.splice(index + 1, 0, inserter);
|
||||
|
||||
this.countInput.val(this.blockCounter);
|
||||
|
||||
const isFirstChild = (index === 0);
|
||||
const isLastChild = (index === this.children.length - 1);
|
||||
if (!isFirstChild) {
|
||||
child.enableMoveUp();
|
||||
if (isLastChild) {
|
||||
/* previous child (which was previously the last one) can now move down */
|
||||
this.children[index - 1].enableMoveDown();
|
||||
}
|
||||
}
|
||||
if (!isLastChild) {
|
||||
child.enableMoveDown();
|
||||
if (isFirstChild) {
|
||||
/* next child (which was previously the first one) can now move up */
|
||||
this.children[index + 1].enableMoveUp();
|
||||
}
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
_getChildDataForInsertion({ type }) {
|
||||
/* Called when an 'insert new block' action is triggered: given a dict of data from the insertion control,
|
||||
return the block definition and initial state to be used for the new block.
|
||||
|
@ -291,13 +201,6 @@ export class StreamBlock {
|
|||
return [blockDef, initialState];
|
||||
}
|
||||
|
||||
_onRequestInsert(index, opts) {
|
||||
/* handler for an 'insert new block' action */
|
||||
const [blockDef, initialState] = this._getChildDataForInsertion(opts);
|
||||
const newChild = this._insert(blockDef, initialState, null, index, { animate: true });
|
||||
newChild.focus();
|
||||
}
|
||||
|
||||
duplicateBlock(index) {
|
||||
const childState = this.children[index].getState();
|
||||
childState.id = null;
|
||||
|
@ -305,88 +208,8 @@ export class StreamBlock {
|
|||
this.children[index + 1].focus();
|
||||
}
|
||||
|
||||
deleteBlock(index) {
|
||||
this.children[index].markDeleted({ animate: true });
|
||||
this.inserters[index].delete();
|
||||
this.children.splice(index, 1);
|
||||
this.inserters.splice(index, 1);
|
||||
|
||||
/* index numbers of children / inserters 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.inserters.length; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
}
|
||||
|
||||
if (index === 0 && this.children.length > 0) {
|
||||
/* we have removed the first child; the new first child cannot be moved up */
|
||||
this.children[0].disableMoveUp();
|
||||
}
|
||||
if (index === this.children.length && this.children.length > 0) {
|
||||
/* we have removed the last child; the new last child cannot be moved down */
|
||||
this.children[this.children.length - 1].disableMoveDown();
|
||||
}
|
||||
}
|
||||
|
||||
moveBlock(oldIndex, newIndex) {
|
||||
if (oldIndex === newIndex) return;
|
||||
const inserterToMove = this.inserters[oldIndex];
|
||||
const childToMove = this.children[oldIndex];
|
||||
|
||||
/* move HTML elements */
|
||||
if (newIndex > oldIndex) {
|
||||
$(inserterToMove.element).insertAfter(this.children[newIndex].element);
|
||||
} else {
|
||||
$(inserterToMove.element).insertBefore(this.inserters[newIndex].element);
|
||||
}
|
||||
$(childToMove.element).insertAfter(inserterToMove.element);
|
||||
|
||||
/* reorder items in the `inserters` and `children` arrays */
|
||||
this.inserters.splice(oldIndex, 1);
|
||||
this.inserters.splice(newIndex, 0, inserterToMove);
|
||||
this.children.splice(oldIndex, 1);
|
||||
this.children.splice(newIndex, 0, childToMove);
|
||||
|
||||
/* update index properties of moved items */
|
||||
if (newIndex > oldIndex) {
|
||||
for (let i = oldIndex; i <= newIndex; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
this.children[i].setIndex(i);
|
||||
}
|
||||
} else {
|
||||
for (let i = newIndex; i <= oldIndex; i++) {
|
||||
this.inserters[i].setIndex(i);
|
||||
this.children[i].setIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
/* enable/disable up/down arrows as required */
|
||||
const maxIndex = this.children.length - 1;
|
||||
if (oldIndex === 0) {
|
||||
childToMove.enableMoveUp();
|
||||
this.children[0].disableMoveUp();
|
||||
}
|
||||
if (oldIndex === maxIndex) {
|
||||
childToMove.enableMoveDown();
|
||||
this.children[maxIndex].disableMoveDown();
|
||||
}
|
||||
if (newIndex === 0) {
|
||||
childToMove.disableMoveUp();
|
||||
this.children[1].enableMoveUp();
|
||||
}
|
||||
if (newIndex === maxIndex) {
|
||||
childToMove.disableMoveDown();
|
||||
this.children[maxIndex - 1].enableMoveDown();
|
||||
}
|
||||
}
|
||||
|
||||
setState(values) {
|
||||
this.clear();
|
||||
values.forEach((val, i) => {
|
||||
this.insert(val, i);
|
||||
});
|
||||
super.setState(values);
|
||||
if (values.length === 0) {
|
||||
/* for an empty list, begin with the menu open */
|
||||
this.inserters[0].open({ animate: false });
|
||||
|
@ -422,20 +245,6 @@ export class StreamBlock {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
getState() {
|
||||
return this.children.map(child => child.getState());
|
||||
}
|
||||
|
||||
getValue() {
|
||||
return this.children.map(child => child.getValue());
|
||||
}
|
||||
|
||||
focus() {
|
||||
if (this.children.length) {
|
||||
this.children[0].focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class StreamBlockDefinition {
|
||||
|
|
Ładowanie…
Reference in New Issue