Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | 2x 2x 2x 8696x 8696x 8696x 2x 8696x 9068x 8696x 9068x 8696x 8696x 2x 9777x 2155x 20x 20x 28x 28x 28x 28x 28x 26x 2x 2x 28x 52x 52x 52x 52x 44x 42x 2x 2x 52x 5679x 5679x 6x 5679x 27188x 27188x 2x 27188x 27188x 48616x 48616x 3641x 48616x 620x 620x 620x 614x 620x 620x 620x 8x 2610x 2610x 2610x 2x 2610x 2610x 2610x 18x 1852x 1852x 4x 4x 4x 1848x 1848x 1848x 166x | /**
* Copyright 2019 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import {commons} from '../../../coral-utils';
import Collection from './Collection';
import listToArray from './listToArray';
/**
Collection capable of handling non-nested items with a selected attribute. It is useful to manage the
internal state of selection. It currently does not support options.filter for the selection related functions.
*/
class SelectableCollection extends Collection {
constructor(options) {
super(options);
if (this._filter) {
commons._log('warn', 'Coral.SelectableCollection does not support the options.filter');
}
// disabled items will not be a selection candicate although hidden items might
this._selectableItemSelector = this._allItemsSelector.split(',').map(selector => `${selector}:not([disabled])`).join(',');
this._selectedItemSelector = this._allItemsSelector.split(',').map(selector => `${selector}[selected]`).join(',');
this._deselectAllExceptSelector = this._selectedItemSelector;
}
/**
Returns the selectable items. Items that are disabled quality for selection. On the other hand, hidden items
can be selected as this is the default behavior in HTML. Please note that an already selected item could be
returned, since the selection could be toggled.
@returns {Array.<HTMLElement>}
an array of items whose selection could be toggled.
@protected
*/
_getSelectableItems() {
return Array.from(this._container.querySelectorAll(this._selectableItemSelector));
}
/**
Returns the first selectable item. Items that are disabled quality for selection. On the other hand, hidden items
can be selected as this is the default behavior in HTML. Please note that an already selected item could be
returned, since the selection could be toggled.
@returns {HTMLElement}
an item whose selection could be toggled.
@protected
*/
_getFirstSelectable() {
return this._container.querySelector(this._selectableItemSelector) || null;
}
/**
Returns the last selectable item. Items that are disabled quality for selection. On the other hand, hidden items
can be selected as this is the default behavior in HTML. Please note that an already selected item could be
returned, since the selection could be toggled.
@returns {HTMLElement}
an item whose selection could be toggled.
@protected
*/
_getLastSelectable() {
const items = this._container.querySelectorAll(this._selectableItemSelector);
return items[items.length - 1] || null;
}
/**
Returns the previous selectable item.
@param {HTMLElement} item
The reference item.
@returns {HTMLElement}
an item whose selection could be toggled.
@protected
*/
_getPreviousSelectable(item) {
const items = this.getAll();
let index = items.indexOf(item);
let sibling = index > 0 ? items[index - 1] : null;
while (sibling) {
if (sibling.matches(this._selectableItemSelector)) {
break;
} else {
index--;
sibling = index > 0 ? items[index - 1] : null;
}
}
// in case the item is not specified, or it is not inside the collection, we need to return the first selectable
return sibling || (item.matches(this._selectableItemSelector) ? item : this._getFirstSelectable());
}
/**
Returns the next selectable item.
@param {HTMLElement} item
The reference item.
@returns {HTMLElement}
an item whose selection could be toggled.
@protected
*/
_getNextSelectable(item) {
const items = this.getAll();
let index = items.indexOf(item);
let sibling = index < items.length - 1 ? items[index + 1] : null;
while (sibling) {
if (sibling.matches(this._selectableItemSelector)) {
break;
} else {
index++;
sibling = index < items.length - 1 ? items[index + 1] : null;
}
}
return sibling || item;
}
/**
Returns the first item that is selected in the Collection. It allows to configure the attribute used for selection
so that components that use 'selected' and 'active' can share the same implementation.
@param {String} [selectedAttribute=selected]
the attribute that will be used to check for selection.
@returns HTMLElement the first selected item.
@protected
*/
_getFirstSelected(selectedAttribute) {
let selector = this._selectedItemSelector;
if (typeof selectedAttribute === 'string') {
selector = selector.replace('[selected]', `[${selectedAttribute}]`);
}
return this._container.querySelector(selector) || null;
}
/**
Returns the last item that is selected in the Collection. It allows to configure the attribute used for selection
so that components that use 'selected' and 'active' can share the same implementation.
@param {String} [selectedAttribute=selected]
the attribute that will be used to check for selection.
@returns HTMLElment the last selected item.
@protected
*/
_getLastSelected(selectedAttribute) {
let selector = this._selectedItemSelector;
if (typeof selectedAttribute === 'string') {
selector = selector.replace('[selected]', `[${selectedAttribute}]`);
}
// last-of-type did not work so we need to query all
const items = this._container.querySelectorAll(selector);
return items[items.length - 1] || null;
}
/**
Returns an array that contains all the items that are selected.
@param {String} [selectedAttribute=selected]
the attribute that will be used to check for selection.
@protected
@returns Array.<HTMLElement> an array with all the selected items.
*/
_getAllSelected(selectedAttribute) {
let selector = this._selectedItemSelector;
if (typeof selectedAttribute === 'string') {
selector = selector.replace('[selected]', `[${selectedAttribute}]`);
}
return Array.from(this._container.querySelectorAll(selector));
}
/**
Deselects all the items except the first selected item in the Collection. By default the <code>selected</code>
attribute will be removed. The attribute to remove is configurable via the <code>selectedAttribute</code> parameter.
The selected attribute will be removed no matter if the item is <code>disabled</code> or <code>hidden</code>.
@param {String} [selectedAttribute=selected]
the attribute that will be used to check for selection. This attribute will be removed from the matching elements.
@protected
*/
_deselectAllExceptFirst(selectedAttribute) {
let selector = this._deselectAllExceptSelector;
const attributeToRemove = selectedAttribute || 'selected';
if (typeof selectedAttribute === 'string') {
selector = selector.replace('[selected]', `[${selectedAttribute}]`);
}
// we select all the selected attributes except the last one
const items = this._container.querySelectorAll(selector);
const itemsCount = items.length;
// ignores the first item of the list, everything else is deselected
for (let i = 1 ; i < itemsCount ; i++) {
// we use remoteAttribute since we do not know if the element is upgraded
items[i].removeAttribute(attributeToRemove);
}
}
/**
Deselects all the items except the last selected item in the Collecton. By default the <code>selected</code>
attribute will be removed. The attribute to remove is configurable via the <code>selectedAttribute</code> parameter.
@param {String} [selectedAttribute=selected]
the attribute that will be used to check for selection. This attribute will be removed from the matching elements.
@protected
*/
_deselectAllExceptLast(selectedAttribute) {
let selector = this._deselectAllExceptSelector;
const attributeToRemove = selectedAttribute || 'selected';
if (typeof selectedAttribute === 'string') {
selector = selector.replace('[selected]', `[${selectedAttribute}]`);
}
// we query for all matching items with the given attribute
const items = this._container.querySelectorAll(selector);
// we ignore the last item
const itemsCount = items.length - 1;
for (let i = 0 ; i < itemsCount ; i++) {
// we use remoteAttribute since we do not know if the element is upgraded
items[i].removeAttribute(attributeToRemove);
}
}
/**
Deselects all the items except the given item. The provided attribute will be remove from all matching items. By
default the <code>selected</code> attribute will be removed. The attribute to remove is configurable via the
<code>selectedAttribute</code> parameter.
@name Coral.SelectableCollection#_deselectAllExcept
@function
@param {HTMLElement} [itemOrSelectedAttribute]
The item to keep selected. If the item is not provided, all elements will be deselected.
@param {String} [selectedAttribute=selected]
the attribute that will be used to check for selection. This attribute will be removed from the matching elements.
@protected
*/
_deselectAllExcept(itemOrSelectedAttribute, selectedAttribute) {
// if no selectedAttribute we use the unmodified selector as default
let selector = this._deselectAllExceptSelector;
let item;
let attributeToRemove;
// an item was not provided so we use it as 'selectedAttribute'
if (typeof itemOrSelectedAttribute === 'string') {
item = null;
attributeToRemove = itemOrSelectedAttribute || 'selected';
selector = selector.replace('[selected]', `[${attributeToRemove}]`);
} else {
item = itemOrSelectedAttribute;
attributeToRemove = selectedAttribute || 'selected';
if (typeof selectedAttribute === 'string') {
selector = selector.replace('[selected]', `[${attributeToRemove}]`);
}
}
// we query for all matching items with the given attribute
const items = this._container.querySelectorAll(selector);
const itemsCount = items.length;
for (let i = 0 ; i < itemsCount ; i++) {
// we use remoteAttribute since we do not know if the element is upgraded
if (item !== items[i]) {
items[i].removeAttribute(attributeToRemove);
}
}
}
}
export default SelectableCollection;
|