1e484b35bSopenharmony_ci/* 2e484b35bSopenharmony_ci * Licensed to the Apache Software Foundation (ASF) under one 3e484b35bSopenharmony_ci * or more contributor license agreements. See the NOTICE file 4e484b35bSopenharmony_ci * distributed with this work for additional information 5e484b35bSopenharmony_ci * regarding copyright ownership. The ASF licenses this file 6e484b35bSopenharmony_ci * to you under the Apache License, Version 2.0 (the 7e484b35bSopenharmony_ci * "License"); you may not use this file except in compliance 8e484b35bSopenharmony_ci * with the License. You may obtain a copy of the License at 9e484b35bSopenharmony_ci * 10e484b35bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 11e484b35bSopenharmony_ci * 12e484b35bSopenharmony_ci * Unless required by applicable law or agreed to in writing, 13e484b35bSopenharmony_ci * software distributed under the License is distributed on an 14e484b35bSopenharmony_ci * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15e484b35bSopenharmony_ci * KIND, either express or implied. See the License for the 16e484b35bSopenharmony_ci * specific language governing permissions and limitations 17e484b35bSopenharmony_ci * under the License. 18e484b35bSopenharmony_ci */ 19e484b35bSopenharmony_ci/* 20e484b35bSopenharmony_ci * 2021.01.08 - Move element's method from operation.js to Element class. 21e484b35bSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 22e484b35bSopenharmony_ci */ 23e484b35bSopenharmony_ci 24e484b35bSopenharmony_ciimport { Log } from '../utils/index'; 25e484b35bSopenharmony_ciimport Node from './Node'; 26e484b35bSopenharmony_ciimport NativeElementClassFactory from './NativeElementClassFactory'; 27e484b35bSopenharmony_ciimport Document from './Document'; 28e484b35bSopenharmony_ciimport { TaskCenter } from '../main/manage/event/TaskCenter'; 29e484b35bSopenharmony_ciimport { FragBlockInterface, 30e484b35bSopenharmony_ci TemplateInterface, 31e484b35bSopenharmony_ci compileCustomComponent, 32e484b35bSopenharmony_ci targetIsComposed 33e484b35bSopenharmony_ci} from '../main/model/compiler'; 34e484b35bSopenharmony_ciimport Vm from '../main/model'; 35e484b35bSopenharmony_ciimport { CSS_INHERITANCE } from '../main/app/bundle'; 36e484b35bSopenharmony_ciimport {interceptCallback} from '../main/manage/event/callbackIntercept'; 37e484b35bSopenharmony_ciimport { VmOptions } from '../main/model/vmOptions'; 38e484b35bSopenharmony_ci/** 39e484b35bSopenharmony_ci * Element is a basic class to describe a tree node in vdom. 40e484b35bSopenharmony_ci * @extends Node 41e484b35bSopenharmony_ci */ 42e484b35bSopenharmony_ciclass Element extends Node { 43e484b35bSopenharmony_ci private _style: any; 44e484b35bSopenharmony_ci private _classStyle: any; 45e484b35bSopenharmony_ci private _event: any; 46e484b35bSopenharmony_ci private _idStyle: any; 47e484b35bSopenharmony_ci private _tagStyle: any; 48e484b35bSopenharmony_ci private _attrStyle: any; 49e484b35bSopenharmony_ci private _tagAndTagStyle: any; 50e484b35bSopenharmony_ci private _firstOrLastChildStyle: any; 51e484b35bSopenharmony_ci private _universalStyle: any; 52e484b35bSopenharmony_ci private _id: string | null; 53e484b35bSopenharmony_ci private _classList: any[]; 54e484b35bSopenharmony_ci private _block: FragBlockInterface; 55e484b35bSopenharmony_ci private _vm: Vm; 56e484b35bSopenharmony_ci private _isCustomComponent: boolean; 57e484b35bSopenharmony_ci private _inheritedStyle: object; 58e484b35bSopenharmony_ci private _target:TemplateInterface; 59e484b35bSopenharmony_ci private _hasBefore: boolean; 60e484b35bSopenharmony_ci private _hasAfter: boolean; 61e484b35bSopenharmony_ci private _isOpen: boolean; 62e484b35bSopenharmony_ci 63e484b35bSopenharmony_ci protected _children: Node[]; 64e484b35bSopenharmony_ci protected _pureChildren: Element[]; 65e484b35bSopenharmony_ci protected _role: string; 66e484b35bSopenharmony_ci protected _attr: any; 67e484b35bSopenharmony_ci protected _dataSet: any; 68e484b35bSopenharmony_ci protected _isFirstDyanmicName: boolean; 69e484b35bSopenharmony_ci 70e484b35bSopenharmony_ci constructor(type = 'div', props:any = {}, isExtended: boolean = false) { 71e484b35bSopenharmony_ci super(); 72e484b35bSopenharmony_ci const NativeElementClass = NativeElementClassFactory.nativeElementClassMap.get(type); 73e484b35bSopenharmony_ci if (NativeElementClass && !isExtended) { 74e484b35bSopenharmony_ci if (global.pcPreview && type === 'canvas') { 75e484b35bSopenharmony_ci Object.defineProperty(NativeElementClass.prototype, 'getContext', { 76e484b35bSopenharmony_ci configurable: true, 77e484b35bSopenharmony_ci enumerable: true, 78e484b35bSopenharmony_ci get: function moduleGetter() { 79e484b35bSopenharmony_ci return (...args: any) => { 80e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 81e484b35bSopenharmony_ci if (taskCenter) { 82e484b35bSopenharmony_ci // support aceapp callback style 83e484b35bSopenharmony_ci args = interceptCallback(args); 84e484b35bSopenharmony_ci const ret = taskCenter.send('component', { 85e484b35bSopenharmony_ci ref: this.ref, 86e484b35bSopenharmony_ci component: type, 87e484b35bSopenharmony_ci method: 'getContext' 88e484b35bSopenharmony_ci }, args); 89e484b35bSopenharmony_ci return ret; 90e484b35bSopenharmony_ci } 91e484b35bSopenharmony_ci }; 92e484b35bSopenharmony_ci } 93e484b35bSopenharmony_ci }); 94e484b35bSopenharmony_ci } 95e484b35bSopenharmony_ci return new NativeElementClass(props); 96e484b35bSopenharmony_ci } 97e484b35bSopenharmony_ci 98e484b35bSopenharmony_ci this._nodeType = Node.NodeType.Element; 99e484b35bSopenharmony_ci this._type = type; 100e484b35bSopenharmony_ci this._attr = props.attr || {}; 101e484b35bSopenharmony_ci this._style = props.style || {}; 102e484b35bSopenharmony_ci this._classStyle = props.classStyle || {}; 103e484b35bSopenharmony_ci this._event = {}; 104e484b35bSopenharmony_ci this._idStyle = {}; 105e484b35bSopenharmony_ci this._tagStyle = {}; 106e484b35bSopenharmony_ci this._attrStyle = {}; 107e484b35bSopenharmony_ci this._tagAndTagStyle = {}; 108e484b35bSopenharmony_ci this._firstOrLastChildStyle = {}; 109e484b35bSopenharmony_ci this._universalStyle = {}; 110e484b35bSopenharmony_ci this._id = null; 111e484b35bSopenharmony_ci this._classList = []; 112e484b35bSopenharmony_ci this._children = []; 113e484b35bSopenharmony_ci this._pureChildren = []; 114e484b35bSopenharmony_ci this._isCustomComponent = false; 115e484b35bSopenharmony_ci this._inheritedStyle = {}; 116e484b35bSopenharmony_ci this._dataSet = {}; 117e484b35bSopenharmony_ci this._isFirstDyanmicName = true; 118e484b35bSopenharmony_ci } 119e484b35bSopenharmony_ci 120e484b35bSopenharmony_ci /** 121e484b35bSopenharmony_ci * inherit sytle from parent 122e484b35bSopenharmony_ci * @type {Object} 123e484b35bSopenharmony_ci */ 124e484b35bSopenharmony_ci public set inheritedStyle(inheritedStyle: object) { 125e484b35bSopenharmony_ci this._inheritedStyle = inheritedStyle; 126e484b35bSopenharmony_ci } 127e484b35bSopenharmony_ci 128e484b35bSopenharmony_ci public get inheritedStyle() { 129e484b35bSopenharmony_ci return this._inheritedStyle; 130e484b35bSopenharmony_ci } 131e484b35bSopenharmony_ci 132e484b35bSopenharmony_ci /** 133e484b35bSopenharmony_ci * Children array except comment node. 134e484b35bSopenharmony_ci * @type {Node[]} 135e484b35bSopenharmony_ci */ 136e484b35bSopenharmony_ci public set pureChildren(newPureChildren: Element[]) { 137e484b35bSopenharmony_ci this._pureChildren = newPureChildren; 138e484b35bSopenharmony_ci } 139e484b35bSopenharmony_ci 140e484b35bSopenharmony_ci public get pureChildren() { 141e484b35bSopenharmony_ci return this._pureChildren; 142e484b35bSopenharmony_ci } 143e484b35bSopenharmony_ci 144e484b35bSopenharmony_ci /** 145e484b35bSopenharmony_ci * event of element 146e484b35bSopenharmony_ci * @type {Node[]} 147e484b35bSopenharmony_ci */ 148e484b35bSopenharmony_ci public get event() { 149e484b35bSopenharmony_ci return this._event; 150e484b35bSopenharmony_ci } 151e484b35bSopenharmony_ci 152e484b35bSopenharmony_ci /** 153e484b35bSopenharmony_ci * Children array. 154e484b35bSopenharmony_ci * @type {Node[]} 155e484b35bSopenharmony_ci */ 156e484b35bSopenharmony_ci public set children(newChildren: Node[]) { 157e484b35bSopenharmony_ci this._children = newChildren; 158e484b35bSopenharmony_ci } 159e484b35bSopenharmony_ci 160e484b35bSopenharmony_ci public get children() { 161e484b35bSopenharmony_ci return this._children; 162e484b35bSopenharmony_ci } 163e484b35bSopenharmony_ci 164e484b35bSopenharmony_ci /** 165e484b35bSopenharmony_ci * View model of this Element. 166e484b35bSopenharmony_ci * @type {Vm} 167e484b35bSopenharmony_ci */ 168e484b35bSopenharmony_ci public get vm() { 169e484b35bSopenharmony_ci return this._vm; 170e484b35bSopenharmony_ci } 171e484b35bSopenharmony_ci 172e484b35bSopenharmony_ci public set vm(newVm: Vm) { 173e484b35bSopenharmony_ci this._vm = newVm; 174e484b35bSopenharmony_ci } 175e484b35bSopenharmony_ci 176e484b35bSopenharmony_ci public get hasBefore() { 177e484b35bSopenharmony_ci return this._hasBefore; 178e484b35bSopenharmony_ci } 179e484b35bSopenharmony_ci 180e484b35bSopenharmony_ci public set hasBefore(hasBefore: boolean) { 181e484b35bSopenharmony_ci this._hasBefore = hasBefore; 182e484b35bSopenharmony_ci } 183e484b35bSopenharmony_ci 184e484b35bSopenharmony_ci public get hasAfter() { 185e484b35bSopenharmony_ci return this._hasAfter; 186e484b35bSopenharmony_ci } 187e484b35bSopenharmony_ci 188e484b35bSopenharmony_ci public set hasAfter(hasAfter: boolean) { 189e484b35bSopenharmony_ci this._hasAfter = hasAfter; 190e484b35bSopenharmony_ci } 191e484b35bSopenharmony_ci 192e484b35bSopenharmony_ci public get isOpen() { 193e484b35bSopenharmony_ci return this._isOpen; 194e484b35bSopenharmony_ci } 195e484b35bSopenharmony_ci 196e484b35bSopenharmony_ci public set isOpen(isOpen: boolean) { 197e484b35bSopenharmony_ci this._isOpen = isOpen; 198e484b35bSopenharmony_ci } 199e484b35bSopenharmony_ci 200e484b35bSopenharmony_ci /** 201e484b35bSopenharmony_ci * Class style object of this Element, which keys is style name, and values is style values. 202e484b35bSopenharmony_ci * @type {JSON} 203e484b35bSopenharmony_ci */ 204e484b35bSopenharmony_ci public get classStyle() { 205e484b35bSopenharmony_ci return this._classStyle; 206e484b35bSopenharmony_ci } 207e484b35bSopenharmony_ci 208e484b35bSopenharmony_ci /** 209e484b35bSopenharmony_ci * Id style object of this Element, which keys is style name, and values is style values. 210e484b35bSopenharmony_ci * @type {JSON} 211e484b35bSopenharmony_ci */ 212e484b35bSopenharmony_ci public get idStyle() { 213e484b35bSopenharmony_ci return this._idStyle; 214e484b35bSopenharmony_ci } 215e484b35bSopenharmony_ci 216e484b35bSopenharmony_ci /** 217e484b35bSopenharmony_ci * Block in this Element. 218e484b35bSopenharmony_ci * @type {FragBlock} 219e484b35bSopenharmony_ci */ 220e484b35bSopenharmony_ci public get block() { 221e484b35bSopenharmony_ci return this._block; 222e484b35bSopenharmony_ci } 223e484b35bSopenharmony_ci 224e484b35bSopenharmony_ci public set block(newBlock: FragBlockInterface) { 225e484b35bSopenharmony_ci this._block = newBlock; 226e484b35bSopenharmony_ci } 227e484b35bSopenharmony_ci 228e484b35bSopenharmony_ci /** 229e484b35bSopenharmony_ci * Role of this element. 230e484b35bSopenharmony_ci * @type {string} 231e484b35bSopenharmony_ci */ 232e484b35bSopenharmony_ci public set role(role: string) { 233e484b35bSopenharmony_ci this._role = role; 234e484b35bSopenharmony_ci } 235e484b35bSopenharmony_ci 236e484b35bSopenharmony_ci public get role() { 237e484b35bSopenharmony_ci return this._role; 238e484b35bSopenharmony_ci } 239e484b35bSopenharmony_ci 240e484b35bSopenharmony_ci /** 241e484b35bSopenharmony_ci * ID of this element. 242e484b35bSopenharmony_ci * @type {string} 243e484b35bSopenharmony_ci */ 244e484b35bSopenharmony_ci public get id() { 245e484b35bSopenharmony_ci return this._id; 246e484b35bSopenharmony_ci } 247e484b35bSopenharmony_ci 248e484b35bSopenharmony_ci public set id(value) { 249e484b35bSopenharmony_ci this._id = value; 250e484b35bSopenharmony_ci } 251e484b35bSopenharmony_ci 252e484b35bSopenharmony_ci /** 253e484b35bSopenharmony_ci * Class list of this element. 254e484b35bSopenharmony_ci * @type {string[]} 255e484b35bSopenharmony_ci */ 256e484b35bSopenharmony_ci public get classList() { 257e484b35bSopenharmony_ci return this._classList; 258e484b35bSopenharmony_ci } 259e484b35bSopenharmony_ci 260e484b35bSopenharmony_ci public set classList(value: string[]) { 261e484b35bSopenharmony_ci this._classList = value.slice(0); 262e484b35bSopenharmony_ci } 263e484b35bSopenharmony_ci 264e484b35bSopenharmony_ci /** 265e484b35bSopenharmony_ci * Attributes object of this Element. 266e484b35bSopenharmony_ci * @type {Object} 267e484b35bSopenharmony_ci */ 268e484b35bSopenharmony_ci public set attr(attr: any) { 269e484b35bSopenharmony_ci this._attr = attr; 270e484b35bSopenharmony_ci } 271e484b35bSopenharmony_ci 272e484b35bSopenharmony_ci public get attr() { 273e484b35bSopenharmony_ci return this._attr; 274e484b35bSopenharmony_ci } 275e484b35bSopenharmony_ci 276e484b35bSopenharmony_ci /** 277e484b35bSopenharmony_ci * DataSet object of this Element. 278e484b35bSopenharmony_ci * @type {Object} 279e484b35bSopenharmony_ci */ 280e484b35bSopenharmony_ci public set dataSet(dataSet: any) { 281e484b35bSopenharmony_ci this._dataSet = dataSet; 282e484b35bSopenharmony_ci } 283e484b35bSopenharmony_ci 284e484b35bSopenharmony_ci public get dataSet() { 285e484b35bSopenharmony_ci return this._dataSet; 286e484b35bSopenharmony_ci } 287e484b35bSopenharmony_ci 288e484b35bSopenharmony_ci /** 289e484b35bSopenharmony_ci * Flag of whether the element is the root of customeComponent. 290e484b35bSopenharmony_ci * @param {bollean} 291e484b35bSopenharmony_ci */ 292e484b35bSopenharmony_ci public set isCustomComponent(isCustomComponent: boolean) { 293e484b35bSopenharmony_ci this._isCustomComponent = isCustomComponent; 294e484b35bSopenharmony_ci } 295e484b35bSopenharmony_ci 296e484b35bSopenharmony_ci public get isCustomComponent() { 297e484b35bSopenharmony_ci return this._isCustomComponent; 298e484b35bSopenharmony_ci } 299e484b35bSopenharmony_ci 300e484b35bSopenharmony_ci /** 301e484b35bSopenharmony_ci * Style object of this Element. 302e484b35bSopenharmony_ci * @type {Object} 303e484b35bSopenharmony_ci */ 304e484b35bSopenharmony_ci public set style(style: any) { 305e484b35bSopenharmony_ci this._style = style; 306e484b35bSopenharmony_ci } 307e484b35bSopenharmony_ci 308e484b35bSopenharmony_ci public get style() { 309e484b35bSopenharmony_ci return this._style; 310e484b35bSopenharmony_ci } 311e484b35bSopenharmony_ci 312e484b35bSopenharmony_ci /** 313e484b35bSopenharmony_ci * target object of this Element. 314e484b35bSopenharmony_ci * @type {Object} 315e484b35bSopenharmony_ci */ 316e484b35bSopenharmony_ci public set target(target: TemplateInterface) { 317e484b35bSopenharmony_ci this._target = target; 318e484b35bSopenharmony_ci } 319e484b35bSopenharmony_ci 320e484b35bSopenharmony_ci public get target() { 321e484b35bSopenharmony_ci return this._target; 322e484b35bSopenharmony_ci } 323e484b35bSopenharmony_ci 324e484b35bSopenharmony_ci /** 325e484b35bSopenharmony_ci * Get TaskCenter instance by id. 326e484b35bSopenharmony_ci * @param {string} id 327e484b35bSopenharmony_ci * @return {TaskCenter} TaskCenter 328e484b35bSopenharmony_ci */ 329e484b35bSopenharmony_ci public getTaskCenter(id: string): TaskCenter | null { 330e484b35bSopenharmony_ci const doc: Document = this._ownerDocument; 331e484b35bSopenharmony_ci if (doc && doc.taskCenter) { 332e484b35bSopenharmony_ci return doc.taskCenter; 333e484b35bSopenharmony_ci } 334e484b35bSopenharmony_ci return null; 335e484b35bSopenharmony_ci } 336e484b35bSopenharmony_ci 337e484b35bSopenharmony_ci /** 338e484b35bSopenharmony_ci * Establish the connection between parent and child node. 339e484b35bSopenharmony_ci * @param {Node} child - Target node. 340e484b35bSopenharmony_ci */ 341e484b35bSopenharmony_ci public linkChild(child: Node): void { 342e484b35bSopenharmony_ci child.parentNode = this; 343e484b35bSopenharmony_ci if (this._docId) { 344e484b35bSopenharmony_ci child.docId = this._docId; 345e484b35bSopenharmony_ci child.ownerDocument = this._ownerDocument; 346e484b35bSopenharmony_ci if (child.ownerDocument) { 347e484b35bSopenharmony_ci child.ownerDocument.nodeMap[child.nodeId] = child; 348e484b35bSopenharmony_ci } 349e484b35bSopenharmony_ci child.depth = this._depth + 1; 350e484b35bSopenharmony_ci } 351e484b35bSopenharmony_ci if (child.nodeType === Node.NodeType.Element) { 352e484b35bSopenharmony_ci const element = child as Element; 353e484b35bSopenharmony_ci element.children.forEach((grandChild: Node) => { 354e484b35bSopenharmony_ci element.linkChild(grandChild); 355e484b35bSopenharmony_ci }); 356e484b35bSopenharmony_ci } 357e484b35bSopenharmony_ci } 358e484b35bSopenharmony_ci 359e484b35bSopenharmony_ci /** 360e484b35bSopenharmony_ci * Insert a node into list at the specified index. 361e484b35bSopenharmony_ci * @param {Node} target - Target node. 362e484b35bSopenharmony_ci * @param {number} newIndex - Target index. 363e484b35bSopenharmony_ci * @param {Object} [options] - options of insert method. 364e484b35bSopenharmony_ci * @param {boolean} [options.changeSibling=false] - If need to change sibling's index. 365e484b35bSopenharmony_ci * @param {boolean} [options.isInPureChildren=false] - If in pure children array or children array. 366e484b35bSopenharmony_ci * @return {number} New index of node. 367e484b35bSopenharmony_ci */ 368e484b35bSopenharmony_ci public insertIndex(target: Node, newIndex: number, { changeSibling = false, isInPureChildren = false }): number { 369e484b35bSopenharmony_ci const list: Node[] = isInPureChildren ? this._pureChildren : this._children; 370e484b35bSopenharmony_ci if (newIndex < 0) { 371e484b35bSopenharmony_ci newIndex = 0; 372e484b35bSopenharmony_ci } 373e484b35bSopenharmony_ci const before: Node = list[newIndex - 1]; 374e484b35bSopenharmony_ci const after: Node = list[newIndex]; 375e484b35bSopenharmony_ci list.splice(newIndex, 0, target); 376e484b35bSopenharmony_ci if (changeSibling) { 377e484b35bSopenharmony_ci before && (before.nextSibling = target); 378e484b35bSopenharmony_ci target.previousSibling = before; 379e484b35bSopenharmony_ci target.nextSibling = after; 380e484b35bSopenharmony_ci after && (after.previousSibling = target); 381e484b35bSopenharmony_ci } 382e484b35bSopenharmony_ci return newIndex; 383e484b35bSopenharmony_ci } 384e484b35bSopenharmony_ci 385e484b35bSopenharmony_ci /** 386e484b35bSopenharmony_ci * Move the node to a new index in list. 387e484b35bSopenharmony_ci * @param {Node} target - Target node. 388e484b35bSopenharmony_ci * @param {number} newIndex - Target index. 389e484b35bSopenharmony_ci * @param {Object} [options] - options of insert method. 390e484b35bSopenharmony_ci * @param {boolean} [options.changeSibling=false] - If need to change sibling's index. 391e484b35bSopenharmony_ci * @param {boolean} [options.isInPureChildren=false] - If in pure children array or children array. 392e484b35bSopenharmony_ci * @return {number} New index of node. 393e484b35bSopenharmony_ci */ 394e484b35bSopenharmony_ci public moveIndex(target: Node, newIndex: number, { changeSibling = false, isInPureChildren = false }): number { 395e484b35bSopenharmony_ci const list: Node[] = isInPureChildren ? this._pureChildren : this._children; 396e484b35bSopenharmony_ci const index: number = list.indexOf(target); 397e484b35bSopenharmony_ci if (index < 0) { 398e484b35bSopenharmony_ci return -1; 399e484b35bSopenharmony_ci } 400e484b35bSopenharmony_ci if (changeSibling) { 401e484b35bSopenharmony_ci const before: Node = list[index - 1]; 402e484b35bSopenharmony_ci const after: Node = list[index + 1]; 403e484b35bSopenharmony_ci before && (before.nextSibling = after); 404e484b35bSopenharmony_ci after && (after.previousSibling = before); 405e484b35bSopenharmony_ci } 406e484b35bSopenharmony_ci list.splice(index, 1); 407e484b35bSopenharmony_ci let newIndexAfter = newIndex; 408e484b35bSopenharmony_ci if (index <= newIndex) { 409e484b35bSopenharmony_ci newIndexAfter = newIndex - 1; 410e484b35bSopenharmony_ci } 411e484b35bSopenharmony_ci const beforeNew: Node = list[newIndexAfter - 1]; 412e484b35bSopenharmony_ci const afterNew: Node = list[newIndexAfter]; 413e484b35bSopenharmony_ci list.splice(newIndexAfter, 0, target); 414e484b35bSopenharmony_ci if (changeSibling) { 415e484b35bSopenharmony_ci if (beforeNew) { 416e484b35bSopenharmony_ci beforeNew.nextSibling = target; 417e484b35bSopenharmony_ci } 418e484b35bSopenharmony_ci target.previousSibling = beforeNew; 419e484b35bSopenharmony_ci target.nextSibling = afterNew; 420e484b35bSopenharmony_ci if (afterNew) { 421e484b35bSopenharmony_ci afterNew.previousSibling = target; 422e484b35bSopenharmony_ci } 423e484b35bSopenharmony_ci } 424e484b35bSopenharmony_ci if (index === newIndexAfter) { 425e484b35bSopenharmony_ci return -1; 426e484b35bSopenharmony_ci } 427e484b35bSopenharmony_ci return newIndex; 428e484b35bSopenharmony_ci } 429e484b35bSopenharmony_ci 430e484b35bSopenharmony_ci /** 431e484b35bSopenharmony_ci * Remove the node from list. 432e484b35bSopenharmony_ci * @param {Node} target - Target node. 433e484b35bSopenharmony_ci * @param {Object} [options] - options of insert method. 434e484b35bSopenharmony_ci * @param {boolean} [options.changeSibling=false] - If need to change sibling's index. 435e484b35bSopenharmony_ci * @param {boolean} [options.isInPureChildren=false] - If in pure children array or children array. 436e484b35bSopenharmony_ci */ 437e484b35bSopenharmony_ci public removeIndex(target, { changeSibling = false, isInPureChildren = false}): void { 438e484b35bSopenharmony_ci const list: Node[] = isInPureChildren ? this._pureChildren : this._children; 439e484b35bSopenharmony_ci const index: number = list.indexOf(target); 440e484b35bSopenharmony_ci if (index < 0) { 441e484b35bSopenharmony_ci return; 442e484b35bSopenharmony_ci } 443e484b35bSopenharmony_ci if (changeSibling) { 444e484b35bSopenharmony_ci const before: Node = list[index - 1]; 445e484b35bSopenharmony_ci const after: Node = list[index + 1]; 446e484b35bSopenharmony_ci before && (before.nextSibling = after); 447e484b35bSopenharmony_ci after && (after.previousSibling = before); 448e484b35bSopenharmony_ci } 449e484b35bSopenharmony_ci list.splice(index, 1); 450e484b35bSopenharmony_ci } 451e484b35bSopenharmony_ci 452e484b35bSopenharmony_ci /** 453e484b35bSopenharmony_ci * Get the next sibling element. 454e484b35bSopenharmony_ci * @param {Node} node - Target node. 455e484b35bSopenharmony_ci * @return {Node} Next node of target node. 456e484b35bSopenharmony_ci */ 457e484b35bSopenharmony_ci public nextElement(node: Node): Element { 458e484b35bSopenharmony_ci while (node) { 459e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 460e484b35bSopenharmony_ci return node as Element; 461e484b35bSopenharmony_ci } 462e484b35bSopenharmony_ci node = node.nextSibling; 463e484b35bSopenharmony_ci } 464e484b35bSopenharmony_ci } 465e484b35bSopenharmony_ci 466e484b35bSopenharmony_ci /** 467e484b35bSopenharmony_ci * Get the previous sibling element. 468e484b35bSopenharmony_ci * @param {Node} node - Target node. 469e484b35bSopenharmony_ci * @return {Node} Previous node of target node. 470e484b35bSopenharmony_ci */ 471e484b35bSopenharmony_ci public previousElement(node: Node): Element { 472e484b35bSopenharmony_ci while (node) { 473e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 474e484b35bSopenharmony_ci return node as Element; 475e484b35bSopenharmony_ci } 476e484b35bSopenharmony_ci node = node.previousSibling; 477e484b35bSopenharmony_ci } 478e484b35bSopenharmony_ci } 479e484b35bSopenharmony_ci 480e484b35bSopenharmony_ci /** 481e484b35bSopenharmony_ci * Append a child node. 482e484b35bSopenharmony_ci * @param {Node} node - Target node. 483e484b35bSopenharmony_ci * @return {number} the signal sent by native 484e484b35bSopenharmony_ci */ 485e484b35bSopenharmony_ci public appendChild(node: Node): void { 486e484b35bSopenharmony_ci if (node.parentNode && node.parentNode !== this) { 487e484b35bSopenharmony_ci return; 488e484b35bSopenharmony_ci } 489e484b35bSopenharmony_ci 490e484b35bSopenharmony_ci if (!node.parentNode) { 491e484b35bSopenharmony_ci this.linkChild(node as Element); 492e484b35bSopenharmony_ci this.insertIndex(node, this.children.length, { changeSibling: true }); 493e484b35bSopenharmony_ci if (this.docId) { 494e484b35bSopenharmony_ci this.registerNode(node); 495e484b35bSopenharmony_ci } 496e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 497e484b35bSopenharmony_ci const element = node as Element; 498e484b35bSopenharmony_ci this.insertIndex(element, this.pureChildren.length, { isInPureChildren: true }); 499e484b35bSopenharmony_ci this.inheritStyle(node, true); 500e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 501e484b35bSopenharmony_ci if (taskCenter) { 502e484b35bSopenharmony_ci return taskCenter.send( 503e484b35bSopenharmony_ci 'dom', 504e484b35bSopenharmony_ci { action: 'addElement' }, 505e484b35bSopenharmony_ci [this.ref, element.toJSON(), -1] 506e484b35bSopenharmony_ci ); 507e484b35bSopenharmony_ci } 508e484b35bSopenharmony_ci } 509e484b35bSopenharmony_ci } else { 510e484b35bSopenharmony_ci this.moveIndex(node, this.children.length, { changeSibling: true }); 511e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 512e484b35bSopenharmony_ci this.moveIndex(node, this.pureChildren.length, { isInPureChildren: true }); 513e484b35bSopenharmony_ci } 514e484b35bSopenharmony_ci } 515e484b35bSopenharmony_ci } 516e484b35bSopenharmony_ci 517e484b35bSopenharmony_ci /** 518e484b35bSopenharmony_ci * Insert a node before specified node. 519e484b35bSopenharmony_ci * @param {Node} node - Target node. 520e484b35bSopenharmony_ci * @param {Node} before - The node next to the target position. 521e484b35bSopenharmony_ci * @return {number} the signal sent by native 522e484b35bSopenharmony_ci */ 523e484b35bSopenharmony_ci public insertBefore(node: Node, before: Node): void { 524e484b35bSopenharmony_ci if (node.parentNode && node.parentNode !== this) { 525e484b35bSopenharmony_ci return; 526e484b35bSopenharmony_ci } 527e484b35bSopenharmony_ci if (node === before || node.nextSibling && node.nextSibling === before) { 528e484b35bSopenharmony_ci return; 529e484b35bSopenharmony_ci } 530e484b35bSopenharmony_ci // If before is not exist, return. 531e484b35bSopenharmony_ci if (this.children.indexOf(before) < 0) { 532e484b35bSopenharmony_ci return; 533e484b35bSopenharmony_ci } 534e484b35bSopenharmony_ci if (!node.parentNode) { 535e484b35bSopenharmony_ci this.linkChild(node as Element); 536e484b35bSopenharmony_ci this.insertIndex(node, this.children.indexOf(before), { changeSibling: true }); 537e484b35bSopenharmony_ci if (this.docId) { 538e484b35bSopenharmony_ci this.registerNode(node); 539e484b35bSopenharmony_ci } 540e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 541e484b35bSopenharmony_ci const element = node as Element; 542e484b35bSopenharmony_ci const pureBefore = this.nextElement(before); 543e484b35bSopenharmony_ci const index = this.insertIndex( 544e484b35bSopenharmony_ci element, 545e484b35bSopenharmony_ci pureBefore 546e484b35bSopenharmony_ci ? this.pureChildren.indexOf(pureBefore) 547e484b35bSopenharmony_ci : this.pureChildren.length, 548e484b35bSopenharmony_ci { isInPureChildren: true } 549e484b35bSopenharmony_ci ); 550e484b35bSopenharmony_ci this.inheritStyle(node); 551e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 552e484b35bSopenharmony_ci if (taskCenter) { 553e484b35bSopenharmony_ci return taskCenter.send( 554e484b35bSopenharmony_ci 'dom', 555e484b35bSopenharmony_ci { action: 'addElement' }, 556e484b35bSopenharmony_ci [this.ref, element.toJSON(), index] 557e484b35bSopenharmony_ci ); 558e484b35bSopenharmony_ci } 559e484b35bSopenharmony_ci } 560e484b35bSopenharmony_ci } else { 561e484b35bSopenharmony_ci this.moveIndex(node, this.children.indexOf(before), { changeSibling: true }); 562e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 563e484b35bSopenharmony_ci const pureBefore = this.nextElement(before); 564e484b35bSopenharmony_ci this.moveIndex( 565e484b35bSopenharmony_ci node, 566e484b35bSopenharmony_ci pureBefore 567e484b35bSopenharmony_ci ? this.pureChildren.indexOf(pureBefore) 568e484b35bSopenharmony_ci : this.pureChildren.length, 569e484b35bSopenharmony_ci { isInPureChildren: true} 570e484b35bSopenharmony_ci ); 571e484b35bSopenharmony_ci } 572e484b35bSopenharmony_ci } 573e484b35bSopenharmony_ci } 574e484b35bSopenharmony_ci 575e484b35bSopenharmony_ci /** 576e484b35bSopenharmony_ci * Insert a node after specified node. 577e484b35bSopenharmony_ci * @param {Node} node - Target node. 578e484b35bSopenharmony_ci * @param {Node} after - The node in front of the target position. 579e484b35bSopenharmony_ci * @return {number} the signal sent by native 580e484b35bSopenharmony_ci */ 581e484b35bSopenharmony_ci public insertAfter(node: Node, after: Node) { 582e484b35bSopenharmony_ci if (node.parentNode && node.parentNode !== this) { 583e484b35bSopenharmony_ci return; 584e484b35bSopenharmony_ci } 585e484b35bSopenharmony_ci if (node === after || node.previousSibling && node.previousSibling === after) { 586e484b35bSopenharmony_ci return; 587e484b35bSopenharmony_ci } 588e484b35bSopenharmony_ci if (!node.parentNode) { 589e484b35bSopenharmony_ci this.linkChild(node as Element); 590e484b35bSopenharmony_ci this.insertIndex(node, this.children.indexOf(after) + 1, { changeSibling: true }); 591e484b35bSopenharmony_ci 592e484b35bSopenharmony_ci if (this.docId) { 593e484b35bSopenharmony_ci this.registerNode(node); 594e484b35bSopenharmony_ci } 595e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 596e484b35bSopenharmony_ci const element = node as Element; 597e484b35bSopenharmony_ci const index = this.insertIndex( 598e484b35bSopenharmony_ci element, 599e484b35bSopenharmony_ci this.pureChildren.indexOf(this.previousElement(after)) + 1, 600e484b35bSopenharmony_ci { isInPureChildren: true } 601e484b35bSopenharmony_ci ); 602e484b35bSopenharmony_ci this.inheritStyle(node); 603e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 604e484b35bSopenharmony_ci if (taskCenter) { 605e484b35bSopenharmony_ci return taskCenter.send( 606e484b35bSopenharmony_ci 'dom', 607e484b35bSopenharmony_ci { action: 'addElement' }, 608e484b35bSopenharmony_ci [this.ref, element.toJSON(), index] 609e484b35bSopenharmony_ci ); 610e484b35bSopenharmony_ci } 611e484b35bSopenharmony_ci } 612e484b35bSopenharmony_ci } else { 613e484b35bSopenharmony_ci this.moveIndex(node, this.children.indexOf(after) + 1, { changeSibling: true}); 614e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 615e484b35bSopenharmony_ci this.moveIndex( 616e484b35bSopenharmony_ci node, 617e484b35bSopenharmony_ci this.pureChildren.indexOf(this.previousElement(after)) + 1, 618e484b35bSopenharmony_ci { isInPureChildren: true } 619e484b35bSopenharmony_ci ); 620e484b35bSopenharmony_ci } 621e484b35bSopenharmony_ci } 622e484b35bSopenharmony_ci } 623e484b35bSopenharmony_ci 624e484b35bSopenharmony_ci /** 625e484b35bSopenharmony_ci * Remove a child node, and decide whether it should be destroyed. 626e484b35bSopenharmony_ci * @param {Node} node - Target node. 627e484b35bSopenharmony_ci * @param {boolean} [preserved=false] - If need to keep the target node. 628e484b35bSopenharmony_ci */ 629e484b35bSopenharmony_ci public removeChild(node: Node, preserved: boolean = false): void { 630e484b35bSopenharmony_ci if (node.parentNode) { 631e484b35bSopenharmony_ci this.removeIndex(node, { changeSibling: true }); 632e484b35bSopenharmony_ci if (node.nodeType === Node.NodeType.Element) { 633e484b35bSopenharmony_ci this.removeIndex(node, { isInPureChildren: true}); 634e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 635e484b35bSopenharmony_ci if (taskCenter) { 636e484b35bSopenharmony_ci taskCenter.send( 637e484b35bSopenharmony_ci 'dom', 638e484b35bSopenharmony_ci { action: 'removeElement' }, 639e484b35bSopenharmony_ci [node.ref] 640e484b35bSopenharmony_ci ); 641e484b35bSopenharmony_ci } 642e484b35bSopenharmony_ci } 643e484b35bSopenharmony_ci } 644e484b35bSopenharmony_ci if (!preserved) { 645e484b35bSopenharmony_ci node.destroy(); 646e484b35bSopenharmony_ci } 647e484b35bSopenharmony_ci } 648e484b35bSopenharmony_ci 649e484b35bSopenharmony_ci /** 650e484b35bSopenharmony_ci * Clear all child nodes. 651e484b35bSopenharmony_ci */ 652e484b35bSopenharmony_ci public clear(): void { 653e484b35bSopenharmony_ci const taskCenter: TaskCenter = this.getTaskCenter(this._docId); 654e484b35bSopenharmony_ci if (taskCenter) { 655e484b35bSopenharmony_ci this._pureChildren.forEach(child => { 656e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'removeElement' }, [child.ref]); 657e484b35bSopenharmony_ci }); 658e484b35bSopenharmony_ci } 659e484b35bSopenharmony_ci this._children.forEach(node => { 660e484b35bSopenharmony_ci node.destroy(); 661e484b35bSopenharmony_ci }); 662e484b35bSopenharmony_ci this._children.length = 0; 663e484b35bSopenharmony_ci this._pureChildren.length = 0; 664e484b35bSopenharmony_ci } 665e484b35bSopenharmony_ci 666e484b35bSopenharmony_ci /** 667e484b35bSopenharmony_ci * Set dataSet for an element. 668e484b35bSopenharmony_ci * @param {string} key - dataSet name. 669e484b35bSopenharmony_ci * @param {string} value - dataSet value. 670e484b35bSopenharmony_ci */ 671e484b35bSopenharmony_ci public setData(key: string, value: string): void { 672e484b35bSopenharmony_ci this.dataSet[key] = value; 673e484b35bSopenharmony_ci } 674e484b35bSopenharmony_ci 675e484b35bSopenharmony_ci /** 676e484b35bSopenharmony_ci * Set an attribute, and decide whether the task should be send to native. 677e484b35bSopenharmony_ci * @param {string} key - Arribute name. 678e484b35bSopenharmony_ci * @param {string | number} value - Arribute value. 679e484b35bSopenharmony_ci * @param {boolean} [silent=false] - If use silent mode. 680e484b35bSopenharmony_ci */ 681e484b35bSopenharmony_ci public setAttr(key: string, value: string | number, silent: boolean = false): void { 682e484b35bSopenharmony_ci if (this.attr[key] === value && silent !== false) { 683e484b35bSopenharmony_ci return; 684e484b35bSopenharmony_ci } 685e484b35bSopenharmony_ci this.attr[key] = value; 686e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 687e484b35bSopenharmony_ci if (!silent && taskCenter) { 688e484b35bSopenharmony_ci const result = {}; 689e484b35bSopenharmony_ci result[key] = value; 690e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateAttrs' }, [this.ref, result]); 691e484b35bSopenharmony_ci } 692e484b35bSopenharmony_ci 693e484b35bSopenharmony_ci if (this._type === 'compontent' && key === 'name') { 694e484b35bSopenharmony_ci if (this._isFirstDyanmicName === true) { 695e484b35bSopenharmony_ci Log.info('compontent first setAttr name = ' + value); 696e484b35bSopenharmony_ci this._isFirstDyanmicName = false; 697e484b35bSopenharmony_ci } else { 698e484b35bSopenharmony_ci Log.info('compontent second setAttr name,' + value); 699e484b35bSopenharmony_ci if (taskCenter) { 700e484b35bSopenharmony_ci const node = this._nextSibling; 701e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'removeElement' }, [node.ref]); 702e484b35bSopenharmony_ci } 703e484b35bSopenharmony_ci const parentNode = this._parentNode as Element; 704e484b35bSopenharmony_ci const component: VmOptions | null = targetIsComposed(this._vm, value.toString()); 705e484b35bSopenharmony_ci const meta = {}; 706e484b35bSopenharmony_ci if (component) { 707e484b35bSopenharmony_ci compileCustomComponent(this._vm, component, this._target, parentNode, value.toString(), meta); 708e484b35bSopenharmony_ci return; 709e484b35bSopenharmony_ci } 710e484b35bSopenharmony_ci } 711e484b35bSopenharmony_ci } 712e484b35bSopenharmony_ci } 713e484b35bSopenharmony_ci 714e484b35bSopenharmony_ci /** 715e484b35bSopenharmony_ci * Set a style property, and decide whether the task should be send to native. 716e484b35bSopenharmony_ci * @param {string} key - Style name. 717e484b35bSopenharmony_ci * @param {string | number} value - Style value. 718e484b35bSopenharmony_ci * @param {boolean} [silent=false] - If use silent mode. 719e484b35bSopenharmony_ci */ 720e484b35bSopenharmony_ci public setStyle(key: string, value: string | number, silent: boolean = false): void { 721e484b35bSopenharmony_ci if (this.style[key] === value && silent !== false) { 722e484b35bSopenharmony_ci return; 723e484b35bSopenharmony_ci } 724e484b35bSopenharmony_ci this.style[key] = value; 725e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 726e484b35bSopenharmony_ci if (!silent && taskCenter) { 727e484b35bSopenharmony_ci const result = {}; 728e484b35bSopenharmony_ci result[key] = value; 729e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, this.toStyle()]); 730e484b35bSopenharmony_ci if (CSS_INHERITANCE.includes(key)) { 731e484b35bSopenharmony_ci this.broadcastStyle(); 732e484b35bSopenharmony_ci } 733e484b35bSopenharmony_ci } 734e484b35bSopenharmony_ci } 735e484b35bSopenharmony_ci 736e484b35bSopenharmony_ci /** 737e484b35bSopenharmony_ci * Set style properties from class. 738e484b35bSopenharmony_ci * @param {object} classStyle - Style properties. 739e484b35bSopenharmony_ci */ 740e484b35bSopenharmony_ci public setClassStyle(classStyle: any): void { 741e484b35bSopenharmony_ci let canUpdate: boolean = false; 742e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 743e484b35bSopenharmony_ci Object.keys(classStyle).forEach(key => { 744e484b35bSopenharmony_ci if (CSS_INHERITANCE.includes(key) && taskCenter) { 745e484b35bSopenharmony_ci if (!this.isSameStyle(this.classStyle[key], classStyle[key], key)) { 746e484b35bSopenharmony_ci canUpdate = true; 747e484b35bSopenharmony_ci } 748e484b35bSopenharmony_ci } 749e484b35bSopenharmony_ci }); 750e484b35bSopenharmony_ci for (const key in this._classStyle) { 751e484b35bSopenharmony_ci this._classStyle[key] = ''; 752e484b35bSopenharmony_ci } 753e484b35bSopenharmony_ci 754e484b35bSopenharmony_ci Object.assign(this._classStyle, classStyle); 755e484b35bSopenharmony_ci if (taskCenter) { 756e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, this.toStyle()]); 757e484b35bSopenharmony_ci if (canUpdate) { 758e484b35bSopenharmony_ci this.broadcastStyle(); 759e484b35bSopenharmony_ci } 760e484b35bSopenharmony_ci } 761e484b35bSopenharmony_ci } 762e484b35bSopenharmony_ci 763e484b35bSopenharmony_ci /** 764e484b35bSopenharmony_ci * Set style properties from class. 765e484b35bSopenharmony_ci * @param {object} classStyle - Style properties. 766e484b35bSopenharmony_ci */ 767e484b35bSopenharmony_ci public setCustomFlag(): void { 768e484b35bSopenharmony_ci this._isCustomComponent = true; 769e484b35bSopenharmony_ci } 770e484b35bSopenharmony_ci 771e484b35bSopenharmony_ci /** 772e484b35bSopenharmony_ci * Set IdStyle properties from class. 773e484b35bSopenharmony_ci * @param {string} key - Style name. 774e484b35bSopenharmony_ci * @param {string|number} value - Style value. 775e484b35bSopenharmony_ci * @param {boolean} [silent=false] - If use silent mode. 776e484b35bSopenharmony_ci */ 777e484b35bSopenharmony_ci public setIdStyle(key: string, value: string | number, silent: boolean = false): void { 778e484b35bSopenharmony_ci if (this._idStyle[key] === value && silent !== false) { 779e484b35bSopenharmony_ci return; 780e484b35bSopenharmony_ci } 781e484b35bSopenharmony_ci // if inline style has define return 782e484b35bSopenharmony_ci if (this.style[key]) { 783e484b35bSopenharmony_ci return; 784e484b35bSopenharmony_ci } 785e484b35bSopenharmony_ci this._idStyle[key] = value; 786e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 787e484b35bSopenharmony_ci if (!silent && taskCenter) { 788e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, this._idStyle]); 789e484b35bSopenharmony_ci if (CSS_INHERITANCE.includes(key)) { 790e484b35bSopenharmony_ci this.broadcastStyle(); 791e484b35bSopenharmony_ci } 792e484b35bSopenharmony_ci } 793e484b35bSopenharmony_ci } 794e484b35bSopenharmony_ci 795e484b35bSopenharmony_ci /** 796e484b35bSopenharmony_ci * Set TagStyle properties from class. 797e484b35bSopenharmony_ci * @param {string} key - Style name. 798e484b35bSopenharmony_ci * @param {string|number} value - Style value. 799e484b35bSopenharmony_ci * @param {boolean} [silent=false] - If use silent mode. 800e484b35bSopenharmony_ci */ 801e484b35bSopenharmony_ci public setTagStyle(key: string, value: string | number, silent: boolean = false): void { 802e484b35bSopenharmony_ci if (this._tagStyle[key] === value && silent !== false) { 803e484b35bSopenharmony_ci return; 804e484b35bSopenharmony_ci } 805e484b35bSopenharmony_ci // If inline id class style has define return. 806e484b35bSopenharmony_ci if (this.style[key] || this._idStyle[key] || this._attrStyle[key] || this._classStyle[key] || this._firstOrLastChildStyle[key] || this._tagAndTagStyle[key]) { 807e484b35bSopenharmony_ci return; 808e484b35bSopenharmony_ci } 809e484b35bSopenharmony_ci this._tagStyle[key] = value; 810e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 811e484b35bSopenharmony_ci if (!silent && taskCenter) { 812e484b35bSopenharmony_ci const result = {}; 813e484b35bSopenharmony_ci result[key] = value; 814e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, result]); 815e484b35bSopenharmony_ci } 816e484b35bSopenharmony_ci } 817e484b35bSopenharmony_ci 818e484b35bSopenharmony_ci public setAttrStyle(key: string, value: string | number, silent: boolean = false): void { 819e484b35bSopenharmony_ci if (this._attrStyle[key] === value && silent !== false) { 820e484b35bSopenharmony_ci return; 821e484b35bSopenharmony_ci } 822e484b35bSopenharmony_ci // If inline id style define return. 823e484b35bSopenharmony_ci if (this.style[key] || this._idStyle[key]) { 824e484b35bSopenharmony_ci return; 825e484b35bSopenharmony_ci } 826e484b35bSopenharmony_ci this._attrStyle[key] = value; 827e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 828e484b35bSopenharmony_ci if (!silent && taskCenter) { 829e484b35bSopenharmony_ci const result = {}; 830e484b35bSopenharmony_ci result[key] = value; 831e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, result]); 832e484b35bSopenharmony_ci } 833e484b35bSopenharmony_ci } 834e484b35bSopenharmony_ci 835e484b35bSopenharmony_ci public setTagAndTagStyle(key: string, value: string | number, silent: boolean = false): void { 836e484b35bSopenharmony_ci if (this._tagAndTagStyle[key] === value && silent !== false) { 837e484b35bSopenharmony_ci return; 838e484b35bSopenharmony_ci } 839e484b35bSopenharmony_ci // If inline id class style has define return. 840e484b35bSopenharmony_ci if (this.style[key] || this._idStyle[key] || this._attrStyle[key] || this._classStyle[key] || this._firstOrLastChildStyle[key]) { 841e484b35bSopenharmony_ci return; 842e484b35bSopenharmony_ci } 843e484b35bSopenharmony_ci this._tagAndTagStyle[key] = value; 844e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 845e484b35bSopenharmony_ci if (!silent && taskCenter) { 846e484b35bSopenharmony_ci const result = {}; 847e484b35bSopenharmony_ci result[key] = value; 848e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, result]); 849e484b35bSopenharmony_ci } 850e484b35bSopenharmony_ci } 851e484b35bSopenharmony_ci 852e484b35bSopenharmony_ci public setFirstOrLastChildStyle(key: string, value: string | number, silent: boolean = false): void { 853e484b35bSopenharmony_ci if (this._firstOrLastChildStyle[key] === value && silent !== false) { 854e484b35bSopenharmony_ci return; 855e484b35bSopenharmony_ci } 856e484b35bSopenharmony_ci // If inline id class style has define return. 857e484b35bSopenharmony_ci if (this.style[key] || this._idStyle[key] || this._attrStyle[key]) { 858e484b35bSopenharmony_ci return; 859e484b35bSopenharmony_ci } 860e484b35bSopenharmony_ci this._firstOrLastChildStyle[key] = value; 861e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 862e484b35bSopenharmony_ci if (!silent && taskCenter) { 863e484b35bSopenharmony_ci const result = {}; 864e484b35bSopenharmony_ci result[key] = value; 865e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, result]); 866e484b35bSopenharmony_ci } 867e484b35bSopenharmony_ci } 868e484b35bSopenharmony_ci 869e484b35bSopenharmony_ci public setUniversalStyle(key: string, value: string | number, silent: boolean = false): void { 870e484b35bSopenharmony_ci if (this._universalStyle[key] === value && silent !== false) { 871e484b35bSopenharmony_ci return; 872e484b35bSopenharmony_ci } 873e484b35bSopenharmony_ci // If inline id class style has define return. 874e484b35bSopenharmony_ci if (this.style[key] || this._idStyle[key] || this._classStyle[key] || this._tagStyle[key] || this._tagAndTagStyle[key]) { 875e484b35bSopenharmony_ci return; 876e484b35bSopenharmony_ci } 877e484b35bSopenharmony_ci this._universalStyle[key] = value; 878e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 879e484b35bSopenharmony_ci if (!silent && taskCenter) { 880e484b35bSopenharmony_ci const result = {}; 881e484b35bSopenharmony_ci result[key] = value; 882e484b35bSopenharmony_ci taskCenter.send('dom', { action: 'updateStyle' }, [this.ref, result]); 883e484b35bSopenharmony_ci } 884e484b35bSopenharmony_ci } 885e484b35bSopenharmony_ci 886e484b35bSopenharmony_ci /** 887e484b35bSopenharmony_ci * Add an event handler. 888e484b35bSopenharmony_ci * @param {string} type - Event name. 889e484b35bSopenharmony_ci * @param {Function} handler - Event handler. 890e484b35bSopenharmony_ci * @param {Object} [params] - Event parameters. 891e484b35bSopenharmony_ci */ 892e484b35bSopenharmony_ci public addEvent(type: string, handler?: Function, params?: any): void { 893e484b35bSopenharmony_ci if (!this._event) { 894e484b35bSopenharmony_ci this._event = {}; 895e484b35bSopenharmony_ci } 896e484b35bSopenharmony_ci if (!this._event[type]) { 897e484b35bSopenharmony_ci this._event[type] = { handler, params }; 898e484b35bSopenharmony_ci } 899e484b35bSopenharmony_ci } 900e484b35bSopenharmony_ci 901e484b35bSopenharmony_ci /** 902e484b35bSopenharmony_ci * Remove an event handler. 903e484b35bSopenharmony_ci * @param {string} type - Event name 904e484b35bSopenharmony_ci */ 905e484b35bSopenharmony_ci public removeEvent(type: string): void { 906e484b35bSopenharmony_ci if (this._event && this._event[type]) { 907e484b35bSopenharmony_ci delete this._event[type]; 908e484b35bSopenharmony_ci } 909e484b35bSopenharmony_ci } 910e484b35bSopenharmony_ci 911e484b35bSopenharmony_ci /** 912e484b35bSopenharmony_ci * Fire an event manually. 913e484b35bSopenharmony_ci * @param {string} type - Event name. 914e484b35bSopenharmony_ci * @param {function} event - Event handler. 915e484b35bSopenharmony_ci * @param {boolean} isBubble - Whether or not event bubble 916e484b35bSopenharmony_ci * @param {boolean} [options] - Event options 917e484b35bSopenharmony_ci * @return {*} anything returned by handler function. 918e484b35bSopenharmony_ci */ 919e484b35bSopenharmony_ci public fireEvent(type: string, event: any, isBubble?: boolean, options?: any) { 920e484b35bSopenharmony_ci Log.debug(`Element#fireEvent, type = ${type}, event = ${event}, isBubble = ${isBubble}, options = ${options}.`); 921e484b35bSopenharmony_ci const BUBBLE_EVENTS = [ 922e484b35bSopenharmony_ci 'mouse', 'click', 'longpress', 'touchstart', 923e484b35bSopenharmony_ci 'touchmove', 'touchend', 'panstart', 'panmove', 924e484b35bSopenharmony_ci 'panend', 'horizontalpan', 'verticalpan', 'swipe' 925e484b35bSopenharmony_ci ]; 926e484b35bSopenharmony_ci let result = null; 927e484b35bSopenharmony_ci let isStopPropagation = false; 928e484b35bSopenharmony_ci const eventDesc = this._event[type]; 929e484b35bSopenharmony_ci if (eventDesc && event) { 930e484b35bSopenharmony_ci const handler = eventDesc.handler; 931e484b35bSopenharmony_ci event.stopPropagation = () => { 932e484b35bSopenharmony_ci isStopPropagation = true; 933e484b35bSopenharmony_ci }; 934e484b35bSopenharmony_ci if (options && options.params) { 935e484b35bSopenharmony_ci result = handler.call(this, event, ...options.params); 936e484b35bSopenharmony_ci } else { 937e484b35bSopenharmony_ci result = handler.call(this, event); 938e484b35bSopenharmony_ci } 939e484b35bSopenharmony_ci } 940e484b35bSopenharmony_ci 941e484b35bSopenharmony_ci if (!isStopPropagation && isBubble && BUBBLE_EVENTS.indexOf(type) !== -1) { 942e484b35bSopenharmony_ci if (this._parentNode) { 943e484b35bSopenharmony_ci const parentNode = this._parentNode as Element; 944e484b35bSopenharmony_ci event.currentTarget = parentNode; 945e484b35bSopenharmony_ci parentNode.fireEvent(type, event, isBubble); // no options 946e484b35bSopenharmony_ci } 947e484b35bSopenharmony_ci } 948e484b35bSopenharmony_ci 949e484b35bSopenharmony_ci return result; 950e484b35bSopenharmony_ci } 951e484b35bSopenharmony_ci 952e484b35bSopenharmony_ci /** 953e484b35bSopenharmony_ci * Get all styles of current element. 954e484b35bSopenharmony_ci * @return {object} style 955e484b35bSopenharmony_ci */ 956e484b35bSopenharmony_ci public toStyle(): any { 957e484b35bSopenharmony_ci // Selector Specificity inline > #id > .class > tag > inheritance. 958e484b35bSopenharmony_ci const style = Object.assign({}, this._inheritedStyle); 959e484b35bSopenharmony_ci this.assignStyle(style, this._universalStyle); 960e484b35bSopenharmony_ci this.assignStyle(style, this._tagStyle); 961e484b35bSopenharmony_ci this.assignStyle(style, this._tagAndTagStyle); 962e484b35bSopenharmony_ci this.assignStyle(style, this._classStyle); 963e484b35bSopenharmony_ci this.assignStyle(style, this._attrStyle); 964e484b35bSopenharmony_ci this.assignStyle(style, this._firstOrLastChildStyle); 965e484b35bSopenharmony_ci this.assignStyle(style, this._idStyle); 966e484b35bSopenharmony_ci this.assignStyle(style, this.style); 967e484b35bSopenharmony_ci return style; 968e484b35bSopenharmony_ci } 969e484b35bSopenharmony_ci 970e484b35bSopenharmony_ci /** 971e484b35bSopenharmony_ci * Assign style. 972e484b35bSopenharmony_ci * @param {*} src - Source style object. 973e484b35bSopenharmony_ci * @param {*} dest - Target style object. 974e484b35bSopenharmony_ci */ 975e484b35bSopenharmony_ci public assignStyle(src: any, dest: any): void { 976e484b35bSopenharmony_ci if (dest) { 977e484b35bSopenharmony_ci const keys = Object.keys(dest); 978e484b35bSopenharmony_ci 979e484b35bSopenharmony_ci // Margin and padding style: the style should be empty in the first. 980e484b35bSopenharmony_ci keys.sort(function(style1, style2) { 981e484b35bSopenharmony_ci if (dest[style1] === '') { 982e484b35bSopenharmony_ci return 1; 983e484b35bSopenharmony_ci } else { 984e484b35bSopenharmony_ci return -1; 985e484b35bSopenharmony_ci } 986e484b35bSopenharmony_ci }); 987e484b35bSopenharmony_ci let i = keys.length; 988e484b35bSopenharmony_ci while (i--) { 989e484b35bSopenharmony_ci const key = keys[i]; 990e484b35bSopenharmony_ci const val = dest[key]; 991e484b35bSopenharmony_ci if (val) { 992e484b35bSopenharmony_ci src[key] = val; 993e484b35bSopenharmony_ci } else { 994e484b35bSopenharmony_ci if ((val === '' || val === undefined) && src[key]) { 995e484b35bSopenharmony_ci return; 996e484b35bSopenharmony_ci } 997e484b35bSopenharmony_ci src[key] = val; 998e484b35bSopenharmony_ci } 999e484b35bSopenharmony_ci } 1000e484b35bSopenharmony_ci } 1001e484b35bSopenharmony_ci } 1002e484b35bSopenharmony_ci 1003e484b35bSopenharmony_ci /** 1004e484b35bSopenharmony_ci * Convert current element to JSON like object. 1005e484b35bSopenharmony_ci * @param {boolean} [ignoreChildren=false] - whether to ignore child nodes, default false 1006e484b35bSopenharmony_ci * @return {JSON} JSON object of this element. 1007e484b35bSopenharmony_ci */ 1008e484b35bSopenharmony_ci public toJSON(ignoreChildren = false): JSON { 1009e484b35bSopenharmony_ci const result: any = { 1010e484b35bSopenharmony_ci ref: this.ref, 1011e484b35bSopenharmony_ci type: this._type, 1012e484b35bSopenharmony_ci attr: this.attr, 1013e484b35bSopenharmony_ci style: this.toStyle(), 1014e484b35bSopenharmony_ci customComponent: this._isCustomComponent 1015e484b35bSopenharmony_ci }; 1016e484b35bSopenharmony_ci const event = []; 1017e484b35bSopenharmony_ci for (const type in this._event) { 1018e484b35bSopenharmony_ci const { params } = this._event[type]; 1019e484b35bSopenharmony_ci if (!params) { 1020e484b35bSopenharmony_ci event.push(type); 1021e484b35bSopenharmony_ci } else { 1022e484b35bSopenharmony_ci event.push({ type, params }); 1023e484b35bSopenharmony_ci } 1024e484b35bSopenharmony_ci } 1025e484b35bSopenharmony_ci if (event.length) { 1026e484b35bSopenharmony_ci result.event = event; 1027e484b35bSopenharmony_ci } 1028e484b35bSopenharmony_ci if (!ignoreChildren && this._pureChildren.length) { 1029e484b35bSopenharmony_ci result.children = this._pureChildren.map(child => child.toJSON()); 1030e484b35bSopenharmony_ci } 1031e484b35bSopenharmony_ci if (this._id) { 1032e484b35bSopenharmony_ci result.id = this._id; 1033e484b35bSopenharmony_ci } 1034e484b35bSopenharmony_ci return result; 1035e484b35bSopenharmony_ci } 1036e484b35bSopenharmony_ci 1037e484b35bSopenharmony_ci /** 1038e484b35bSopenharmony_ci * Convert to HML element tag string. 1039e484b35bSopenharmony_ci * @override 1040e484b35bSopenharmony_ci * @return {string} hml of this element. 1041e484b35bSopenharmony_ci */ 1042e484b35bSopenharmony_ci public toString(): string { 1043e484b35bSopenharmony_ci const id = this._id !== null ? this._id : ''; 1044e484b35bSopenharmony_ci return '<' + this._type + 1045e484b35bSopenharmony_ci ' id =' + id + 1046e484b35bSopenharmony_ci ' attr=' + JSON.stringify(this.attr) + 1047e484b35bSopenharmony_ci ' style=' + JSON.stringify(this.toStyle()) + '>' + 1048e484b35bSopenharmony_ci this.pureChildren.map((child) => child.toString()).join('') + 1049e484b35bSopenharmony_ci '</' + this._type + '>'; 1050e484b35bSopenharmony_ci } 1051e484b35bSopenharmony_ci 1052e484b35bSopenharmony_ci /** 1053e484b35bSopenharmony_ci * Destroy this element 1054e484b35bSopenharmony_ci */ 1055e484b35bSopenharmony_ci public destroy() { 1056e484b35bSopenharmony_ci Log.debug(`Element#destroy this._type = ${this._type}.`); 1057e484b35bSopenharmony_ci if (this._event && this._event['detached']) { 1058e484b35bSopenharmony_ci this.fireEvent('detached', {}); 1059e484b35bSopenharmony_ci } 1060e484b35bSopenharmony_ci this._attr = {}; 1061e484b35bSopenharmony_ci this._style = {}; 1062e484b35bSopenharmony_ci this._classStyle = {}; 1063e484b35bSopenharmony_ci this._event = {}; 1064e484b35bSopenharmony_ci this._idStyle = {}; 1065e484b35bSopenharmony_ci this._tagStyle = {}; 1066e484b35bSopenharmony_ci this._attrStyle = {}; 1067e484b35bSopenharmony_ci this._tagAndTagStyle = {}; 1068e484b35bSopenharmony_ci this._firstOrLastChildStyle = {}; 1069e484b35bSopenharmony_ci this._universalStyle = {}; 1070e484b35bSopenharmony_ci this._classList.length = 0; 1071e484b35bSopenharmony_ci 1072e484b35bSopenharmony_ci if (this.destroyHook) { 1073e484b35bSopenharmony_ci this.destroyHook(); 1074e484b35bSopenharmony_ci this.destroyHook = null; 1075e484b35bSopenharmony_ci } 1076e484b35bSopenharmony_ci if (this._children) { 1077e484b35bSopenharmony_ci this._children.forEach((child: Node): void => { 1078e484b35bSopenharmony_ci child.destroy(); 1079e484b35bSopenharmony_ci }); 1080e484b35bSopenharmony_ci this._children.length = 0; 1081e484b35bSopenharmony_ci } 1082e484b35bSopenharmony_ci if (this._pureChildren) { 1083e484b35bSopenharmony_ci this._pureChildren.length = 0; 1084e484b35bSopenharmony_ci } 1085e484b35bSopenharmony_ci super.destroy(); 1086e484b35bSopenharmony_ci } 1087e484b35bSopenharmony_ci 1088e484b35bSopenharmony_ci /** 1089e484b35bSopenharmony_ci * the judgement of whether the inherited style should update 1090e484b35bSopenharmony_ci * @param {string | Array} oldClassStyle 1091e484b35bSopenharmony_ci * @param {string | Array} newClassStyle 1092e484b35bSopenharmony_ci * @param {string} key 1093e484b35bSopenharmony_ci * @returns {boolean} 1094e484b35bSopenharmony_ci */ 1095e484b35bSopenharmony_ci isSameStyle(oldClassStyle: string | any[], newClassStyle: string | any[], key: string) { 1096e484b35bSopenharmony_ci if (key === 'fontFamily') { 1097e484b35bSopenharmony_ci if (oldClassStyle[0].fontFamily === newClassStyle[0].fontFamily) { 1098e484b35bSopenharmony_ci return true; 1099e484b35bSopenharmony_ci } 1100e484b35bSopenharmony_ci } else { 1101e484b35bSopenharmony_ci if (oldClassStyle === newClassStyle) { 1102e484b35bSopenharmony_ci return true; 1103e484b35bSopenharmony_ci } 1104e484b35bSopenharmony_ci } 1105e484b35bSopenharmony_ci return false; 1106e484b35bSopenharmony_ci } 1107e484b35bSopenharmony_ci 1108e484b35bSopenharmony_ci /** 1109e484b35bSopenharmony_ci * iterate child node for updating inheritedstyle 1110e484b35bSopenharmony_ci */ 1111e484b35bSopenharmony_ci broadcastStyle() { 1112e484b35bSopenharmony_ci if (this.pureChildren) { 1113e484b35bSopenharmony_ci for (const child in this.pureChildren) { 1114e484b35bSopenharmony_ci this.pureChildren[child].setInheritedStyle(); 1115e484b35bSopenharmony_ci this.pureChildren[child].broadcastStyle(); 1116e484b35bSopenharmony_ci } 1117e484b35bSopenharmony_ci } 1118e484b35bSopenharmony_ci } 1119e484b35bSopenharmony_ci 1120e484b35bSopenharmony_ci /** 1121e484b35bSopenharmony_ci * before update inherited style 1122e484b35bSopenharmony_ci * clear up the inherited style 1123e484b35bSopenharmony_ci */ 1124e484b35bSopenharmony_ci resetInheritedStyle() { 1125e484b35bSopenharmony_ci this.inheritedStyle = {}; 1126e484b35bSopenharmony_ci } 1127e484b35bSopenharmony_ci 1128e484b35bSopenharmony_ci /** 1129e484b35bSopenharmony_ci * inherited style from parent 1130e484b35bSopenharmony_ci */ 1131e484b35bSopenharmony_ci public setInheritedStyle() { 1132e484b35bSopenharmony_ci this.resetInheritedStyle(); 1133e484b35bSopenharmony_ci const parentNode: Element = this.parentNode as Element; 1134e484b35bSopenharmony_ci parentNode.inheritStyle(this); 1135e484b35bSopenharmony_ci const taskCenter = this.getTaskCenter(this.docId); 1136e484b35bSopenharmony_ci if (taskCenter) { 1137e484b35bSopenharmony_ci taskCenter.send( 1138e484b35bSopenharmony_ci 'dom', 1139e484b35bSopenharmony_ci { action: 'updateStyle' }, 1140e484b35bSopenharmony_ci [this.ref, this.toStyle()] 1141e484b35bSopenharmony_ci ); 1142e484b35bSopenharmony_ci } 1143e484b35bSopenharmony_ci } 1144e484b35bSopenharmony_ci 1145e484b35bSopenharmony_ci /** 1146e484b35bSopenharmony_ci * inherit style of parent. 1147e484b35bSopenharmony_ci * @return {object} element 1148e484b35bSopenharmony_ci */ 1149e484b35bSopenharmony_ci public inheritStyle(node, isFirst = false) { 1150e484b35bSopenharmony_ci // for first render, save time 1151e484b35bSopenharmony_ci const allStyle = this.toStyle(); 1152e484b35bSopenharmony_ci this.setChildStyle(allStyle, node._inheritedStyle); 1153e484b35bSopenharmony_ci } 1154e484b35bSopenharmony_ci 1155e484b35bSopenharmony_ci /** 1156e484b35bSopenharmony_ci * set inherited style to child 1157e484b35bSopenharmony_ci * @param {object} parentStyle 1158e484b35bSopenharmony_ci * @param {object} childStyle 1159e484b35bSopenharmony_ci * @param {object} node 1160e484b35bSopenharmony_ci */ 1161e484b35bSopenharmony_ci public setChildStyle(parentStyle, childStyle) { 1162e484b35bSopenharmony_ci Object.keys(parentStyle).forEach(key => { 1163e484b35bSopenharmony_ci if (CSS_INHERITANCE.includes(key)) { 1164e484b35bSopenharmony_ci childStyle[key] = parentStyle[key]; 1165e484b35bSopenharmony_ci } 1166e484b35bSopenharmony_ci }); 1167e484b35bSopenharmony_ci } 1168e484b35bSopenharmony_ci 1169e484b35bSopenharmony_ci private registerNode(node) { 1170e484b35bSopenharmony_ci const doc = this._ownerDocument; 1171e484b35bSopenharmony_ci if (doc) { 1172e484b35bSopenharmony_ci doc.nodeMap[node.nodeId] = node; 1173e484b35bSopenharmony_ci } 1174e484b35bSopenharmony_ci } 1175e484b35bSopenharmony_ci} 1176e484b35bSopenharmony_ci 1177e484b35bSopenharmony_ciexport default Element; 1178