1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19/* 20 * 2021.01.08 - Remove docMap. 21 * Copyright (c) 2021 Huawei Device Co., Ltd. 22 */ 23 24import Comment from './Comment'; 25import DocumentElement from './DocumentElement'; 26import Node from './Node'; 27import Element from './Element'; 28import { TaskCenter } from '../main/manage/event/TaskCenter'; 29import { Log } from '../utils'; 30 31/** 32 * When a document is loaded into a application runtime, it becomes a document object.<br> 33 * The document object is the root node of the vdom document. 34 */ 35class Document { 36 private _id: string; 37 private _nodeMap: any; 38 private _taskCenter: TaskCenter; 39 private _documentElement: DocumentElement; 40 private _body: Node; 41 private _url: string 42 43 constructor(id = '', url) { 44 this._id = id; 45 this._url = url; 46 this._nodeMap = {}; 47 this._taskCenter = new TaskCenter(id); 48 this._createDocumentElement(); 49 } 50 51 /** 52 * Body of this document. 53 * @type {Node} 54 * @readonly 55 */ 56 public get body() { 57 return this._body; 58 } 59 60 /** 61 * ID of this document. 62 * @type {string} 63 * @readonly 64 */ 65 public get id() { 66 return this._id; 67 } 68 69 /** 70 * Document element of this document. 71 * @type {DocumentElement} 72 * @readonly 73 */ 74 public get documentElement() { 75 return this._documentElement; 76 } 77 78 /** 79 * url of this document (page). 80 * @type {url} 81 * @readonly 82 */ 83 public get url() { 84 return this._url; 85 } 86 87 /** 88 * Node map of this document. 89 * @type {Map} 90 * @readonly 91 */ 92 public get nodeMap() { 93 return this._nodeMap; 94 } 95 96 /** 97 * Task center of this document. 98 * @type {TaskCenter} 99 * @readonly 100 */ 101 public get taskCenter() { 102 return this._taskCenter; 103 } 104 105 /** 106 * Set up body node. 107 * @param {Node} el - Target element. 108 */ 109 public setElementToBody(el: Element): void { 110 el.role = 'body'; 111 el.depth = 1; 112 delete this._nodeMap[el.nodeId]; 113 el.ref = '_root'; 114 this._nodeMap._root = el; 115 this._body = el; 116 } 117 118 /** 119 * Send body of this Document to native. 120 * @param {Node} node - body element. 121 */ 122 public sentBodyToNative(node: Element): void { 123 const body = node.toJSON(); 124 if (this._taskCenter && typeof this._taskCenter.send === 'function') { 125 this._taskCenter.send('dom', { action: 'createBody' }, [body]); 126 } 127 } 128 129 /** 130 * Get the node from nodeMap. 131 * @param {string} ref - id of target node. 132 * @return {object} node from node map. 133 */ 134 public getRef(ref: string) { 135 return this._nodeMap[ref]; 136 } 137 138 /** 139 * Create element of body. 140 * @param {string} tagName - Tag name of body element. 141 * @param {Object} options - Properties of element. 142 * @return {Node} Body element. 143 */ 144 public createBody(tagName: string, options?: any): Node { 145 if (!this._body) { 146 const el = new Element(tagName, options); 147 this.setElementToBody(el); 148 } 149 return this._body; 150 } 151 152 /** 153 * Create an element. 154 * @param {string} tagName - Tag name of element. 155 * @param {Object} options - Properties of element. 156 * @return {Node} New element 157 */ 158 public createElement(tagName: string, options?: any): Element { 159 return new Element(tagName, options); 160 } 161 162 /** 163 * Create an comment. 164 * @param {string} commentText - Text of comment. 165 * @return {object} comment 166 */ 167 public createComment(commentText: string): Comment { 168 return new Comment(commentText); 169 } 170 171 /** 172 * Fire an event on specified element manually. 173 * @param {Element} element - Event target element. 174 * @param {string} eventType - Event name 175 * @param {Object} eventObj - Event object. 176 * @param {boolean} isDomChanges - if need to change dom 177 * @param {object} options - Event options 178 * @return {*} anything returned by handler function 179 */ 180 public fireEvent(element: Element, eventType: string, eventObj: any, isDomChanges: boolean, options: any) { 181 Log.debug(`Document#fireEvent, element = ${element}, eventType = ${eventType}, eventObj = ${eventObj}, isDomChanges = ${isDomChanges}.`); 182 if (!element) { 183 return; 184 } 185 eventObj = eventObj || {}; 186 eventObj.type = eventObj.type || eventType; 187 eventObj.target = element; 188 eventObj.currentTarget = element; 189 eventObj.timestamp = Date.now(); 190 if (isDomChanges) { 191 this._updateElement(element, isDomChanges); 192 } 193 let isBubble; 194 const $root = this.getRef('_root'); 195 if ($root && $root.attr) { 196 isBubble = $root.attr['bubble'] === 'true'; 197 } 198 return element.fireEvent(eventType, eventObj, isBubble, options); 199 } 200 201 /** 202 * Destroy current document, and remove itself form docMap. 203 */ 204 public destroy() { 205 this.taskCenter.destroyCallback(); 206 delete this._nodeMap; 207 delete this._taskCenter; 208 } 209 210 /** 211 * Create the document element. 212 * @return {object} documentElement 213 */ 214 private _createDocumentElement(): void { 215 if (!this._documentElement) { 216 const el = new DocumentElement('document'); 217 el.docId = this._id; 218 el.ownerDocument = this; 219 el.role = 'documentElement'; 220 el.depth = 0; 221 el.ref = '_documentElement'; 222 this._nodeMap._documentElement = el; 223 this._documentElement = el; 224 } 225 } 226 227 private _updateElement(el: Element, changes: any): void { 228 Log.debug(`Document#_updateElement, el = ${el}, changes = ${JSON.stringify(changes)}.`); 229 const attrs = changes.attrs || {}; 230 for (const name in attrs) { 231 el.setAttr(name, attrs[name], true); 232 } 233 const style = changes.style || {}; 234 for (const name in style) { 235 el.setStyle(name, style[name], true); 236 } 237 } 238} 239 240export default Document; 241