• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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