From 541bdfc2c9705c2418fd049d543f20d4825a0c18 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Sat, 16 Oct 2021 17:13:52 +0200 Subject: [PATCH] Fixed next/prev selection. Fixes #3861 --- src/commands/view/ComponentNext.js | 22 +++++++++++---- src/commands/view/ComponentPrev.js | 21 +++++++++++---- src/dom_components/model/Component.js | 39 ++++++++++++++++++++++----- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/commands/view/ComponentNext.js b/src/commands/view/ComponentNext.js index ba1bb8e1f..f99d64aa9 100644 --- a/src/commands/view/ComponentNext.js +++ b/src/commands/view/ComponentNext.js @@ -3,11 +3,23 @@ export default { if (!ed.Canvas.hasFocus()) return; const toSelect = []; - ed.getSelectedAll().forEach(component => { - const coll = component.collection; - const at = coll.indexOf(component); - const next = coll.at(at + 1); - toSelect.push(next || component); + ed.getSelectedAll().forEach(cmp => { + const parent = cmp.parent(); + if (!parent) return; + + const len = parent.components().length; + let incr = 0; + let at = 0; + let next; + + // Get the next selectable component + do { + incr++; + at = cmp.index() + incr; + next = at <= len ? parent.getChildAt(at) : null; + } while (next && !next.get('selectable')); + + toSelect.push(next || cmp); }); toSelect.length && ed.select(toSelect); diff --git a/src/commands/view/ComponentPrev.js b/src/commands/view/ComponentPrev.js index 646ab9097..f466ce2d9 100644 --- a/src/commands/view/ComponentPrev.js +++ b/src/commands/view/ComponentPrev.js @@ -3,11 +3,22 @@ export default { if (!ed.Canvas.hasFocus()) return; const toSelect = []; - ed.getSelectedAll().forEach(component => { - const coll = component.collection; - const at = coll.indexOf(component); - const next = coll.at(at - 1); - toSelect.push(next && at - 1 >= 0 ? next : component); + ed.getSelectedAll().forEach(cmp => { + const parent = cmp.parent(); + if (!parent) return; + + let incr = 0; + let at = 0; + let next; + + // Get the first selectable component + do { + incr++; + at = cmp.index() - incr; + next = at >= 0 ? parent.getChildAt(at) : null; + } while (next && !next.get('selectable')); + + toSelect.push(next || cmp); }); toSelect.length && ed.select(toSelect); diff --git a/src/dom_components/model/Component.js b/src/dom_components/model/Component.js index 9b04a0d96..2fa469449 100644 --- a/src/dom_components/model/Component.js +++ b/src/dom_components/model/Component.js @@ -53,6 +53,8 @@ export const keyUpdateInside = `${keyUpdate}-inside`; * // -> 'span' * ``` * + * [Component]: component.html + * * @typedef Component * @property {String} [type=''] Component type, eg. `text`, `image`, `video`, etc. * @property {String} [tagName='div'] HTML tag of the component, eg. `span`. Default: `div` @@ -268,7 +270,7 @@ export default class Component extends Model.extend(Styleable) { */ index() { const { collection } = this; - return collection && collection.indexOf(this); + return collection ? collection.indexOf(this) : 0; } /** @@ -1016,9 +1018,9 @@ export default class Component extends Model.extend(Styleable) { /** * Set new collection if `components` are provided, otherwise the * current collection is returned - * @param {Component|String} [components] Components to set + * @param {Component|String} [components] Component Definitions or HTML string * @param {Object} [opts={}] Options, same as in `Component.append()` - * @return {Collection|Array} + * @returns {Collection|Array<[Component]>} * @example * // Set new collection * component.components('
'); @@ -1034,10 +1036,35 @@ export default class Component extends Model.extend(Styleable) { return coll; } else { coll.reset(null, opts); - return components && this.append(components, opts); + return components ? this.append(components, opts) : []; } } + /** + * If exists, returns the child component at specific index. + * @param {Number} index Index of the component to return + * @returns {[Component]|null} + * @example + * // Return first child + * component.getChildAt(0); + * // Return second child + * component.getChildAt(1); + */ + getChildAt(index) { + return this.components().at(index || 0) || null; + } + + /** + * If exists, returns the last child component. + * @returns {[Component]|null} + * @example + * const lastChild = component.getLastChild(); + */ + getLastChild() { + const children = this.components(); + return children.at(children.length - 1) || null; + } + /** * Remove all inner components * * @return {this} @@ -1049,14 +1076,14 @@ export default class Component extends Model.extend(Styleable) { /** * Get the parent component, if exists - * @return {Component} + * @return {Component|null} * @example * component.parent(); * // -> Component */ parent(opts = {}) { const coll = this.collection || (opts.prev && this.prevColl); - return coll && coll.parent; + return coll ? coll.parent : null; } /**