• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16type ProvidedVarsMap = Map<string, ObservedPropertyAbstract<any>>;
17type Context = any;
18
19// Nativeview
20// implemented in C++  for release
21// and in utest/view_native_mock.ts for testing
22abstract class View extends NativeView implements
23  IMultiPropertiesChangeSubscriber, IMultiPropertiesReadSubscriber {
24
25  private id_: number;
26  private propsUsedForRender: Set<string> = new Set<string>();
27  private isRenderingInProgress: boolean = false;
28
29  private watchedProps: Map<string, (propName: string) => void>
30    = new Map<string, (propName: string) => void>();
31
32  // @Provide'd variables by this class and its ancestors
33  protected providedVars_: ProvidedVarsMap;
34
35
36  constructor(compilerAssignedUniqueChildId: string, parent: View) {
37    super(compilerAssignedUniqueChildId, parent);
38    this.id_ = SubscriberManager.Get().MakeId();
39    this.providedVars_ = parent ? new Map(parent.providedVars_)
40      : new Map<string, ObservedPropertyAbstract<any>>();
41    SubscriberManager.Get().add(this);
42    console.debug(`${this.constructor.name}: constructor done`);
43  }
44
45  // globally unique id, this is different from compilerAssignedUniqueChildId!
46  id__(): number {
47    return this.id_;
48  }
49
50  // inform the subscribed property
51  // that the View and thereby all properties
52  // are about to be deleted
53  abstract aboutToBeDeleted(): void;
54
55  abstract updateWithValueParams(params: Object): void;
56
57  propertyHasChanged(info?: PropertyInfo): void {
58    if (info) {
59      // need to sync container instanceId to switch instanceId in C++ side.
60      this.syncInstanceId();
61      if (this.propsUsedForRender.has(info)) {
62        console.debug(`${this.constructor.name}: propertyHasChanged ['${info || "unknowm"}']. View needs update`);
63        this.markNeedUpdate();
64      } else {
65        console.debug(`${this.constructor.name}: propertyHasChanged ['${info || "unknowm"}']. View does NOT need update`);
66      }
67      let cb = this.watchedProps.get(info)
68      if (cb) {
69        console.debug(`${this.constructor.name}: propertyHasChanged ['${info || "unknowm"}']. calling @Watch function`);
70        cb.call(this, info);
71      }
72      this.restoreInstanceId();
73    } // if info avail.
74  }
75
76  propertyRead(info?: PropertyInfo): void {
77    console.debug(`${this.constructor.name}: propertyRead ['${info || "unknowm"}'].`);
78    if (info && (info != "unknown") && this.isRenderingInProgress) {
79      this.propsUsedForRender.add(info);
80    }
81  }
82
83
84  // for test purposes
85  public propertiesNeededToRender(): Set<string> {
86    return this.propsUsedForRender;
87  }
88
89  public aboutToRender(): void {
90    console.log(`${this.constructor.name}: aboutToRender`);
91    // reset
92    this.propsUsedForRender = new Set<string>();
93    this.isRenderingInProgress = true;
94  }
95
96  public aboutToContinueRender(): void {
97    // do not reset
98    //this.propsUsedForRender = new Set<string>();
99    this.isRenderingInProgress = true;
100  }
101
102  public onRenderDone(): void {
103    this.isRenderingInProgress = false;
104    console.log(`${this.constructor.name}: onRenderDone: render performed get access to these properties: ${JSON.stringify(Array.from(this.propsUsedForRender))}.`);
105  }
106
107
108  /**
109   * Function to be called from the constructor of the sub component
110   * to register a @Watch varibale
111   * @param propStr name of the variable. Note from @Provide and @Consume this is
112   *      the variable name and not the alias!
113   * @param callback application defined member function of sub-class
114   */
115  protected declareWatch(propStr: string, callback: (propName: string) => void): void {
116    this.watchedProps.set(propStr, callback);
117  }
118
119  /**
120   * This View @Provide's a variable under given name
121   * Call this function from the constructor of the sub class
122   * @param providedPropName either the variable name or the alias defined as
123   *        decorator param
124   * @param store the backing store object for this variable (not the get/set variable!)
125   */
126  protected addProvidedVar<T>(providedPropName: string, store: ObservedPropertyAbstract<T>) {
127    if (this.providedVars_.has(providedPropName)) {
128      throw new ReferenceError(`${this.constructor.name}: duplicate @Provide property with name ${providedPropName}.
129      Property with this name is provided by one of the ancestor Views already.`);
130    }
131    this.providedVars_.set(providedPropName, store);
132  }
133
134  /**
135   * Method for the sub-class to call from its constructor for resolving
136   *       a @Consume variable and initializing its backing store
137   *       with the yncedPropertyTwoWay<T> object created from the
138   *       @Provide variable's backing store.
139   * @param providedPropName the name of the @Provide'd variable.
140   *     This is either the @Consume decortor parameter, or variable name.
141   * @param consumeVarName the @Consume variable name (not the
142   *            @Consume decortor parameter)
143   * @returns initiaizing value of the @Consume backing store
144   */
145  protected initializeConsume<T>(providedPropName: string,
146    consumeVarName: string): ObservedPropertyAbstract<T> {
147    let providedVarStore = this.providedVars_.get(providedPropName);
148    if (providedVarStore === undefined) {
149      throw new ReferenceError(`${this.constructor.name}: missing @Provide property with name ${providedPropName}.
150     Fail to resolve @Consume(${providedPropName}).`);
151    }
152
153    return providedVarStore.createLink(this, consumeVarName);
154  }
155}
156
157function getContentStorage(view: View) : ContentStorage {
158  return view.getContentStorage();
159}
160
161function getContext(view: View) : Context {
162  return view.getContext();
163}
164