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