|
|
@@ -0,0 +1,62 @@
|
|
|
+/**
|
|
|
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
|
|
|
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
|
|
+ */
|
|
|
+
|
|
|
+/**
|
|
|
+ * @module watchdog/utils/getsubnodes
|
|
|
+ */
|
|
|
+
|
|
|
+/* globals EventTarget, Event */
|
|
|
+
|
|
|
+export default function getSubNodes( head ) {
|
|
|
+ const nodes = [ head ];
|
|
|
+
|
|
|
+ // Nodes are stored to prevent infinite looping.
|
|
|
+ const subNodes = new Set();
|
|
|
+
|
|
|
+ while ( nodes.length > 0 ) {
|
|
|
+ const node = nodes.shift();
|
|
|
+
|
|
|
+ if ( subNodes.has( node ) || shouldNodeBeSkipped( node ) ) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ subNodes.add( node );
|
|
|
+
|
|
|
+ // Handle arrays, maps, sets, custom collections that implements `[ Symbol.iterator ]()`, etc.
|
|
|
+ if ( node[ Symbol.iterator ] ) {
|
|
|
+ // The custom editor iterators might cause some problems if the editor is crashed.
|
|
|
+ try {
|
|
|
+ nodes.push( ...node );
|
|
|
+ } catch ( err ) {
|
|
|
+ // eslint-disable-line no-empty
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ nodes.push( ...Object.values( node ) );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return subNodes;
|
|
|
+}
|
|
|
+
|
|
|
+function shouldNodeBeSkipped( node ) {
|
|
|
+ const type = Object.prototype.toString.call( node );
|
|
|
+
|
|
|
+ return (
|
|
|
+ type === '[object Number]' ||
|
|
|
+ type === '[object Boolean]' ||
|
|
|
+ type === '[object String]' ||
|
|
|
+ type === '[object Symbol]' ||
|
|
|
+ type === '[object Function]' ||
|
|
|
+ type === '[object Date]' ||
|
|
|
+ type === '[object RegExp]' ||
|
|
|
+
|
|
|
+ node === undefined ||
|
|
|
+ node === null ||
|
|
|
+
|
|
|
+ // Skip native DOM objects, e.g. Window, nodes, events, etc.
|
|
|
+ node instanceof EventTarget ||
|
|
|
+ node instanceof Event
|
|
|
+ );
|
|
|
+}
|