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_ciimport { hasOwn } from '../../../utils/index';
21e484b35bSopenharmony_ci
22e484b35bSopenharmony_ci/**
23e484b35bSopenharmony_ci * This class provides action for page refresh.
24e484b35bSopenharmony_ci */
25e484b35bSopenharmony_ciexport default class Differ {
26e484b35bSopenharmony_ci  private _id: string;
27e484b35bSopenharmony_ci  private _map: object[];
28e484b35bSopenharmony_ci  private _hooks: Function[];
29e484b35bSopenharmony_ci  private _hasTimer: boolean;
30e484b35bSopenharmony_ci
31e484b35bSopenharmony_ci  constructor(id: string) {
32e484b35bSopenharmony_ci    this._id = id;
33e484b35bSopenharmony_ci    this._map = [];
34e484b35bSopenharmony_ci    this._hooks = [];
35e484b35bSopenharmony_ci  }
36e484b35bSopenharmony_ci
37e484b35bSopenharmony_ci  /**
38e484b35bSopenharmony_ci   * Check whether the map is empty.
39e484b35bSopenharmony_ci   * @return {boolean}
40e484b35bSopenharmony_ci   */
41e484b35bSopenharmony_ci  public isEmpty(): boolean {
42e484b35bSopenharmony_ci    return this._map.length === 0;
43e484b35bSopenharmony_ci  }
44e484b35bSopenharmony_ci
45e484b35bSopenharmony_ci  /**
46e484b35bSopenharmony_ci   * Id of the page.
47e484b35bSopenharmony_ci   * @type {string}
48e484b35bSopenharmony_ci   */
49e484b35bSopenharmony_ci  public get id() {
50e484b35bSopenharmony_ci    return this._id;
51e484b35bSopenharmony_ci  }
52e484b35bSopenharmony_ci
53e484b35bSopenharmony_ci  /**
54e484b35bSopenharmony_ci   * Append action.
55e484b35bSopenharmony_ci   * @param {string} type
56e484b35bSopenharmony_ci   * @param {string} ref
57e484b35bSopenharmony_ci   * @param {Function} handler
58e484b35bSopenharmony_ci   */
59e484b35bSopenharmony_ci  public append(type: string, ref: string, handler: Function): void {
60e484b35bSopenharmony_ci    // Ignore depth to speed up render.
61e484b35bSopenharmony_ci    const defaultDepth: number = 1;
62e484b35bSopenharmony_ci    if (!this._hasTimer) {
63e484b35bSopenharmony_ci      this._hasTimer = true;
64e484b35bSopenharmony_ci
65e484b35bSopenharmony_ci      // Use setTimeout instead of setTimeoutDiffer
66e484b35bSopenharmony_ci      // avoid invoking setTimeout after appDestroy
67e484b35bSopenharmony_ci      if (typeof setTimeout === "function") {
68e484b35bSopenharmony_ci        setTimeout(() => {
69e484b35bSopenharmony_ci          this._hasTimer = false;
70e484b35bSopenharmony_ci          this.flush();
71e484b35bSopenharmony_ci        }, 0);
72e484b35bSopenharmony_ci      }
73e484b35bSopenharmony_ci    }
74e484b35bSopenharmony_ci    const map: object[] = this._map;
75e484b35bSopenharmony_ci    if (!map[defaultDepth]) {
76e484b35bSopenharmony_ci      map[defaultDepth] = {};
77e484b35bSopenharmony_ci    }
78e484b35bSopenharmony_ci    const group: object = map[defaultDepth];
79e484b35bSopenharmony_ci    if (!group[type]) {
80e484b35bSopenharmony_ci      group[type] = {};
81e484b35bSopenharmony_ci    }
82e484b35bSopenharmony_ci    if (type === 'element') {
83e484b35bSopenharmony_ci      if (!group[type][ref]) {
84e484b35bSopenharmony_ci        group[type][ref] = [];
85e484b35bSopenharmony_ci      }
86e484b35bSopenharmony_ci      group[type][ref].push(handler);
87e484b35bSopenharmony_ci    } else {
88e484b35bSopenharmony_ci      group[type][ref] = handler;
89e484b35bSopenharmony_ci    }
90e484b35bSopenharmony_ci  }
91e484b35bSopenharmony_ci
92e484b35bSopenharmony_ci  /**
93e484b35bSopenharmony_ci   * Execute actions of differ.
94e484b35bSopenharmony_ci   */
95e484b35bSopenharmony_ci  public flush(): void {
96e484b35bSopenharmony_ci    const map: object[] = this._map.slice();
97e484b35bSopenharmony_ci    this._map.length = 0;
98e484b35bSopenharmony_ci    map.forEach((group) => {
99e484b35bSopenharmony_ci      callTypeList(group, 'element');
100e484b35bSopenharmony_ci      callTypeMap(group, 'repeat');
101e484b35bSopenharmony_ci      callTypeMap(group, 'shown');
102e484b35bSopenharmony_ci    });
103e484b35bSopenharmony_ci
104e484b35bSopenharmony_ci    const hooks: Function[] = this._hooks.slice();
105e484b35bSopenharmony_ci    this._hooks.length = 0;
106e484b35bSopenharmony_ci    hooks.forEach((fn) => {
107e484b35bSopenharmony_ci      fn();
108e484b35bSopenharmony_ci    });
109e484b35bSopenharmony_ci
110e484b35bSopenharmony_ci    if (!this.isEmpty()) {
111e484b35bSopenharmony_ci      this.flush();
112e484b35bSopenharmony_ci    }
113e484b35bSopenharmony_ci  }
114e484b35bSopenharmony_ci  then(fn) {
115e484b35bSopenharmony_ci    this._hooks.push(fn);
116e484b35bSopenharmony_ci  }
117e484b35bSopenharmony_ci}
118e484b35bSopenharmony_ci
119e484b35bSopenharmony_cifunction callTypeMap(group: any, type: string): void {
120e484b35bSopenharmony_ci  const map: Function[] = group[type];
121e484b35bSopenharmony_ci  for (const ref in map) {
122e484b35bSopenharmony_ci    map[ref]();
123e484b35bSopenharmony_ci  }
124e484b35bSopenharmony_ci}
125e484b35bSopenharmony_ci
126e484b35bSopenharmony_cifunction callTypeList(group: any, type: string): void {
127e484b35bSopenharmony_ci  const map: any = group[type];
128e484b35bSopenharmony_ci  for (const ref in map) {
129e484b35bSopenharmony_ci    if (hasOwn(map, ref)) {
130e484b35bSopenharmony_ci      const list: Function[] = map[ref];
131e484b35bSopenharmony_ci      list.forEach((handler) => {
132e484b35bSopenharmony_ci        handler();
133e484b35bSopenharmony_ci      });
134e484b35bSopenharmony_ci    }
135e484b35bSopenharmony_ci  }
136e484b35bSopenharmony_ci}
137