UNPKG

33.1 kBJavaScriptView Raw
1import { Property, InheritedProperty, clearInheritedProperties, propagateInheritableProperties, propagateInheritableCssProperties, initNativeView } from '../properties';
2import { CSSUtils } from '../../../css/system-classes';
3import { Source } from '../../../utils/debug';
4import { Binding } from '../bindable';
5import { Trace } from '../../../trace';
6import { Observable, WrappedValue } from '../../../data/observable';
7import { Style } from '../../styling/style';
8import { paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty } from '../../styling/style-properties';
9// TODO: Remove this import!
10import { getClass } from '../../../utils/types';
11import { profile } from '../../../profiling';
12import * as ssm from '../../styling/style-scope';
13let domNodeModule;
14function ensuredomNodeModule() {
15 if (!domNodeModule) {
16 domNodeModule = require('../../../debugger/dom-node');
17 }
18}
19let styleScopeModule;
20function ensureStyleScopeModule() {
21 if (!styleScopeModule) {
22 styleScopeModule = require('../../styling/style-scope');
23 }
24}
25const defaultBindingSource = {};
26export function getAncestor(view, criterion) {
27 let matcher = null;
28 if (typeof criterion === 'string') {
29 matcher = (view) => view.typeName === criterion;
30 }
31 else {
32 matcher = (view) => view instanceof criterion;
33 }
34 for (let parent = view.parent; parent != null; parent = parent.parent) {
35 if (matcher(parent)) {
36 return parent;
37 }
38 }
39 return null;
40}
41export function getViewById(view, id) {
42 if (!view) {
43 return undefined;
44 }
45 if (view.id === id) {
46 return view;
47 }
48 let retVal;
49 const descendantsCallback = function (child) {
50 if (child.id === id) {
51 retVal = child;
52 // break the iteration by returning false
53 return false;
54 }
55 return true;
56 };
57 eachDescendant(view, descendantsCallback);
58 return retVal;
59}
60export function getViewByDomId(view, domId) {
61 if (!view) {
62 return undefined;
63 }
64 if (view._domId === domId) {
65 return view;
66 }
67 let retVal;
68 const descendantsCallback = function (child) {
69 if (view._domId === domId) {
70 retVal = child;
71 // break the iteration by returning false
72 return false;
73 }
74 return true;
75 };
76 eachDescendant(view, descendantsCallback);
77 return retVal;
78}
79export function eachDescendant(view, callback) {
80 if (!callback || !view) {
81 return;
82 }
83 let continueIteration;
84 const localCallback = function (child) {
85 continueIteration = callback(child);
86 if (continueIteration) {
87 child.eachChild(localCallback);
88 }
89 return continueIteration;
90 };
91 view.eachChild(localCallback);
92}
93let viewIdCounter = 1;
94// const contextMap = new WeakMap<Object, Map<string, WeakRef<Object>[]>>();
95// function getNativeView(context: Object, typeName: string): Object {
96// let typeMap = contextMap.get(context);
97// if (!typeMap) {
98// typeMap = new Map<string, WeakRef<Object>[]>();
99// contextMap.set(context, typeMap);
100// return undefined;
101// }
102// const array = typeMap.get(typeName);
103// if (array) {
104// let nativeView;
105// while (array.length > 0) {
106// const weakRef = array.pop();
107// nativeView = weakRef.get();
108// if (nativeView) {
109// return nativeView;
110// }
111// }
112// }
113// return undefined;
114// }
115// function putNativeView(context: Object, view: ViewBase): void {
116// const typeMap = contextMap.get(context);
117// const typeName = view.typeName;
118// let list = typeMap.get(typeName);
119// if (!list) {
120// list = [];
121// typeMap.set(typeName, list);
122// }
123// list.push(new WeakRef(view.nativeViewProtected));
124// }
125var Flags;
126(function (Flags) {
127 Flags["superOnLoadedCalled"] = "Loaded";
128 Flags["superOnUnloadedCalled"] = "Unloaded";
129})(Flags || (Flags = {}));
130var SuspendType;
131(function (SuspendType) {
132 SuspendType[SuspendType["Incremental"] = 0] = "Incremental";
133 SuspendType[SuspendType["Loaded"] = 1048576] = "Loaded";
134 SuspendType[SuspendType["NativeView"] = 2097152] = "NativeView";
135 SuspendType[SuspendType["UISetup"] = 4194304] = "UISetup";
136 SuspendType[SuspendType["IncrementalCountMask"] = -7340033] = "IncrementalCountMask";
137})(SuspendType || (SuspendType = {}));
138(function (SuspendType) {
139 function toString(type) {
140 return (type ? 'suspended' : 'resumed') + '(' + 'Incremental: ' + (type & SuspendType.IncrementalCountMask) + ', ' + 'Loaded: ' + !(type & SuspendType.Loaded) + ', ' + 'NativeView: ' + !(type & SuspendType.NativeView) + ', ' + 'UISetup: ' + !(type & SuspendType.UISetup) + ')';
141 }
142 SuspendType.toString = toString;
143})(SuspendType || (SuspendType = {}));
144export class ViewBase extends Observable {
145 constructor() {
146 super();
147 this._onLoadedCalled = false;
148 this._onUnloadedCalled = false;
149 this._cssState = new ssm.CssState(new WeakRef(this));
150 this.pseudoClassAliases = {
151 highlighted: ['active', 'pressed'],
152 };
153 this.cssClasses = new Set();
154 this.cssPseudoClasses = new Set();
155 this._domId = viewIdCounter++;
156 this._style = new Style(new WeakRef(this));
157 this.notify({ eventName: ViewBase.createdEvent, type: this.constructor.name, object: this });
158 }
159 // Used in Angular.
160 get parentNode() {
161 return this._templateParent || this.parent;
162 }
163 set parentNode(node) {
164 this._templateParent = node;
165 }
166 get nativeView() {
167 // this._disableNativeViewRecycling = true;
168 return this.nativeViewProtected;
169 }
170 set nativeView(value) {
171 this.setNativeView(value);
172 }
173 // TODO: Use Type.prototype.typeName instead.
174 get typeName() {
175 return getClass(this);
176 }
177 get style() {
178 return this._style;
179 }
180 set style(inlineStyle /* | string */) {
181 if (typeof inlineStyle === 'string') {
182 this.setInlineStyle(inlineStyle);
183 }
184 else {
185 throw new Error('View.style property is read-only.');
186 }
187 }
188 get android() {
189 // this._disableNativeViewRecycling = true;
190 return this._androidView;
191 }
192 get ios() {
193 // this._disableNativeViewRecycling = true;
194 return this._iosView;
195 }
196 get isLoaded() {
197 return this._isLoaded;
198 }
199 get ['class']() {
200 return this.className;
201 }
202 set ['class'](v) {
203 this.className = v;
204 }
205 getViewById(id) {
206 return getViewById(this, id);
207 }
208 getViewByDomId(domId) {
209 return getViewByDomId(this, domId);
210 }
211 get page() {
212 if (this.parent) {
213 return this.parent.page;
214 }
215 return null;
216 }
217 ensureDomNode() {
218 if (!this.domNode) {
219 ensuredomNodeModule();
220 this.domNode = new domNodeModule.DOMNode(this);
221 }
222 }
223 // Overridden so we don't raise `propertyChange`
224 // The property will raise its own event.
225 set(name, value) {
226 this[name] = WrappedValue.unwrap(value);
227 }
228 onLoaded() {
229 this.setFlag(Flags.superOnLoadedCalled, true);
230 if (this._isLoaded) {
231 return;
232 }
233 this._isLoaded = true;
234 this._cssState.onLoaded();
235 this._resumeNativeUpdates(SuspendType.Loaded);
236 this.eachChild((child) => {
237 this.loadView(child);
238 return true;
239 });
240 this._emit('loaded');
241 }
242 onUnloaded() {
243 this.setFlag(Flags.superOnUnloadedCalled, true);
244 if (!this._isLoaded) {
245 return;
246 }
247 this._suspendNativeUpdates(SuspendType.Loaded);
248 this.eachChild((child) => {
249 this.unloadView(child);
250 return true;
251 });
252 this._isLoaded = false;
253 this._cssState.onUnloaded();
254 this._emit('unloaded');
255 }
256 _layoutParent() {
257 if (this.parent) {
258 this.parent._layoutParent();
259 }
260 }
261 _suspendNativeUpdates(type) {
262 if (type) {
263 this._suspendNativeUpdatesCount = this._suspendNativeUpdatesCount | type;
264 }
265 else {
266 this._suspendNativeUpdatesCount++;
267 }
268 }
269 _resumeNativeUpdates(type) {
270 if (type) {
271 this._suspendNativeUpdatesCount = this._suspendNativeUpdatesCount & ~type;
272 }
273 else {
274 if ((this._suspendNativeUpdatesCount & SuspendType.IncrementalCountMask) === 0) {
275 throw new Error(`Invalid call to ${this}._resumeNativeUpdates`);
276 }
277 this._suspendNativeUpdatesCount--;
278 }
279 if (!this._suspendNativeUpdatesCount) {
280 this.onResumeNativeUpdates();
281 }
282 }
283 _batchUpdate(callback) {
284 try {
285 this._suspendNativeUpdates(SuspendType.Incremental);
286 return callback();
287 }
288 finally {
289 this._resumeNativeUpdates(SuspendType.Incremental);
290 }
291 }
292 setFlag(flag, value) {
293 switch (flag) {
294 case Flags.superOnLoadedCalled:
295 this._onLoadedCalled = value;
296 break;
297 case Flags.superOnUnloadedCalled:
298 this._onUnloadedCalled = value;
299 break;
300 }
301 }
302 isFlagSet(flag) {
303 switch (flag) {
304 case Flags.superOnLoadedCalled:
305 return this._onLoadedCalled;
306 case Flags.superOnUnloadedCalled:
307 return this._onUnloadedCalled;
308 }
309 }
310 callFunctionWithSuper(flag, func) {
311 this.setFlag(flag, false);
312 func();
313 if (!this.isFlagSet(flag)) {
314 throw new Error(`super.${flag} not called in ${this}`);
315 }
316 }
317 callLoaded() {
318 this.callFunctionWithSuper(Flags.superOnLoadedCalled, () => this.onLoaded());
319 }
320 callUnloaded() {
321 this.callFunctionWithSuper(Flags.superOnUnloadedCalled, () => this.onUnloaded());
322 }
323 notifyPseudoClassChanged(pseudoClass) {
324 this.notify({ eventName: ':' + pseudoClass, object: this });
325 }
326 getAllAliasedStates(name) {
327 const allStates = [];
328 allStates.push(name);
329 if (name in this.pseudoClassAliases) {
330 for (let i = 0; i < this.pseudoClassAliases[name].length; i++) {
331 allStates.push(this.pseudoClassAliases[name][i]);
332 }
333 }
334 return allStates;
335 }
336 addPseudoClass(name) {
337 const allStates = this.getAllAliasedStates(name);
338 for (let i = 0; i < allStates.length; i++) {
339 if (!this.cssPseudoClasses.has(allStates[i])) {
340 this.cssPseudoClasses.add(allStates[i]);
341 this.notifyPseudoClassChanged(allStates[i]);
342 }
343 }
344 }
345 deletePseudoClass(name) {
346 const allStates = this.getAllAliasedStates(name);
347 for (let i = 0; i < allStates.length; i++) {
348 if (this.cssPseudoClasses.has(allStates[i])) {
349 this.cssPseudoClasses.delete(allStates[i]);
350 this.notifyPseudoClassChanged(allStates[i]);
351 }
352 }
353 }
354 bindingContextChanged(data) {
355 this.bindings.get('bindingContext').bind(data.value);
356 }
357 bind(options, source = defaultBindingSource) {
358 const targetProperty = options.targetProperty;
359 this.unbind(targetProperty);
360 if (!this.bindings) {
361 this.bindings = new Map();
362 }
363 const binding = new Binding(this, options);
364 this.bindings.set(targetProperty, binding);
365 let bindingSource = source;
366 if (bindingSource === defaultBindingSource) {
367 bindingSource = this.bindingContext;
368 binding.sourceIsBindingContext = true;
369 if (targetProperty === 'bindingContext') {
370 this.bindingContextBoundToParentBindingContextChanged = true;
371 const parent = this.parent;
372 if (parent) {
373 parent.on('bindingContextChange', this.bindingContextChanged, this);
374 }
375 else {
376 this.shouldAddHandlerToParentBindingContextChanged = true;
377 }
378 }
379 }
380 binding.bind(bindingSource);
381 }
382 unbind(property) {
383 const bindings = this.bindings;
384 if (!bindings) {
385 return;
386 }
387 const binding = bindings.get(property);
388 if (binding) {
389 binding.unbind();
390 bindings.delete(property);
391 if (binding.sourceIsBindingContext) {
392 if (property === 'bindingContext') {
393 this.shouldAddHandlerToParentBindingContextChanged = false;
394 this.bindingContextBoundToParentBindingContextChanged = false;
395 const parent = this.parent;
396 if (parent) {
397 parent.off('bindingContextChange', this.bindingContextChanged, this);
398 }
399 }
400 }
401 }
402 }
403 performLayout(currentRun = 0) {
404 // if there's an animation in progress we need to delay the layout
405 // we've added a guard of 5000 milliseconds execution
406 // to make sure that the layout will happen even if the animation haven't finished in 5 seconds
407 if (this._shouldDelayLayout() && currentRun < 100) {
408 setTimeout(() => this.performLayout(currentRun), currentRun);
409 currentRun++;
410 }
411 else {
412 this.parent.requestLayout();
413 }
414 }
415 requestLayout() {
416 // Default implementation for non View instances (like TabViewItem).
417 const parent = this.parent;
418 if (parent) {
419 this.performLayout();
420 }
421 }
422 eachChild(callback) {
423 //
424 }
425 _addView(view, atIndex) {
426 if (Trace.isEnabled()) {
427 Trace.write(`${this}._addView(${view}, ${atIndex})`, Trace.categories.ViewHierarchy);
428 }
429 if (!view) {
430 throw new Error('Expecting a valid View instance.');
431 }
432 if (!(view instanceof ViewBase)) {
433 throw new Error(view + ' is not a valid View instance.');
434 }
435 if (view.parent) {
436 throw new Error('View already has a parent. View: ' + view + ' Parent: ' + view.parent);
437 }
438 view.parent = this;
439 this._addViewCore(view, atIndex);
440 view._parentChanged(null);
441 if (this.domNode) {
442 this.domNode.onChildAdded(view);
443 }
444 }
445 _addViewCore(view, atIndex) {
446 propagateInheritableProperties(this, view);
447 view._inheritStyleScope(this._styleScope);
448 propagateInheritableCssProperties(this.style, view.style);
449 if (this._context) {
450 view._setupUI(this._context, atIndex);
451 }
452 if (this._isLoaded) {
453 this.loadView(view);
454 }
455 }
456 loadView(view) {
457 if (view && !view.isLoaded) {
458 view.callLoaded();
459 }
460 }
461 _shouldDelayLayout() {
462 return false;
463 }
464 unloadView(view) {
465 if (view && view.isLoaded) {
466 view.callUnloaded();
467 }
468 }
469 /**
470 * Core logic for removing a child view from this instance. Used by the framework to handle lifecycle events more centralized. Do not use outside the UI Stack implementation.
471 */
472 _removeView(view) {
473 if (Trace.isEnabled()) {
474 Trace.write(`${this}._removeView(${view})`, Trace.categories.ViewHierarchy);
475 }
476 if (view.parent !== this) {
477 throw new Error('View not added to this instance. View: ' + view + ' CurrentParent: ' + view.parent + ' ExpectedParent: ' + this);
478 }
479 if (this.domNode) {
480 this.domNode.onChildRemoved(view);
481 }
482 this._removeViewCore(view);
483 view.parent = undefined;
484 view._parentChanged(this);
485 }
486 /**
487 * Method is intended to be overridden by inheritors and used as "protected"
488 */
489 _removeViewCore(view) {
490 this.unloadView(view);
491 if (view._context) {
492 view._tearDownUI();
493 }
494 }
495 createNativeView() {
496 return undefined;
497 }
498 disposeNativeView() {
499 this.notify({
500 eventName: ViewBase.disposeNativeViewEvent,
501 object: this,
502 });
503 }
504 initNativeView() {
505 //
506 }
507 resetNativeView() {
508 //
509 }
510 resetNativeViewInternal() {
511 // const nativeView = this.nativeViewProtected;
512 // if (nativeView && global.isAndroid) {
513 // const recycle = this.recycleNativeView;
514 // if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
515 // resetNativeView(this);
516 // if (this._isPaddingRelative) {
517 // nativeView.setPaddingRelative(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
518 // } else {
519 // nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
520 // }
521 // this.resetNativeView();
522 // }
523 // }
524 // if (this._cssState) {
525 // this._cancelAllAnimations();
526 // }
527 }
528 _setupAsRootView(context) {
529 this._setupUI(context);
530 }
531 _setupUI(context, atIndex, parentIsLoaded) {
532 if (this._context === context) {
533 // this check is unnecessary as this function should never be called when this._context === context as it means the view was somehow detached,
534 // which is only possible by setting reusable = true. Adding it either way for feature flag safety
535 if (this.reusable) {
536 if (this.parent && !this._isAddedToNativeVisualTree) {
537 const nativeIndex = this.parent._childIndexToNativeChildIndex(atIndex);
538 this._isAddedToNativeVisualTree = this.parent._addViewToNativeVisualTree(this, nativeIndex);
539 }
540 }
541 return;
542 }
543 else if (this._context) {
544 this._tearDownUI(true);
545 }
546 this._context = context;
547 // This will account for nativeView that is created in createNativeView, recycled
548 // or for backward compatibility - set before _setupUI in iOS constructor.
549 let nativeView = this.nativeViewProtected;
550 // if (global.isAndroid) {
551 // const recycle = this.recycleNativeView;
552 // if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
553 // nativeView = <android.view.View>getNativeView(context, this.typeName);
554 // }
555 // }
556 if (!nativeView) {
557 nativeView = this.createNativeView();
558 }
559 if (global.isAndroid) {
560 // this check is also unecessary as this code should never be reached with _androidView != null unless reusable = true
561 // also adding this check for feature flag safety
562 if (this._androidView !== nativeView || !this.reusable) {
563 this._androidView = nativeView;
564 if (nativeView) {
565 if (this._isPaddingRelative === undefined) {
566 this._isPaddingRelative = nativeView.isPaddingRelative();
567 }
568 let result = nativeView.defaultPaddings;
569 if (result === undefined) {
570 result = org.nativescript.widgets.ViewHelper.getPadding(nativeView);
571 nativeView.defaultPaddings = result;
572 }
573 this._defaultPaddingTop = result.top;
574 this._defaultPaddingRight = result.right;
575 this._defaultPaddingBottom = result.bottom;
576 this._defaultPaddingLeft = result.left;
577 const style = this.style;
578 if (!paddingTopProperty.isSet(style)) {
579 this.effectivePaddingTop = this._defaultPaddingTop;
580 }
581 if (!paddingRightProperty.isSet(style)) {
582 this.effectivePaddingRight = this._defaultPaddingRight;
583 }
584 if (!paddingBottomProperty.isSet(style)) {
585 this.effectivePaddingBottom = this._defaultPaddingBottom;
586 }
587 if (!paddingLeftProperty.isSet(style)) {
588 this.effectivePaddingLeft = this._defaultPaddingLeft;
589 }
590 }
591 }
592 }
593 else {
594 this._iosView = nativeView;
595 }
596 this.setNativeView(nativeView);
597 if (this.parent) {
598 const nativeIndex = this.parent._childIndexToNativeChildIndex(atIndex);
599 this._isAddedToNativeVisualTree = this.parent._addViewToNativeVisualTree(this, nativeIndex);
600 }
601 this._resumeNativeUpdates(SuspendType.UISetup);
602 this.eachChild((child) => {
603 child._setupUI(context);
604 return true;
605 });
606 }
607 setNativeView(value) {
608 if (this.__nativeView === value) {
609 return;
610 }
611 if (this.__nativeView) {
612 this._suspendNativeUpdates(SuspendType.NativeView);
613 // We may do a `this.resetNativeView()` here?
614 }
615 this.__nativeView = this.nativeViewProtected = value;
616 if (this.__nativeView) {
617 this._suspendedUpdates = undefined;
618 this.initNativeView();
619 this._resumeNativeUpdates(SuspendType.NativeView);
620 }
621 }
622 destroyNode(forceDestroyChildren) {
623 this.reusable = false;
624 this._tearDownUI(forceDestroyChildren);
625 }
626 _tearDownUI(force) {
627 // No context means we are already teared down.
628 if (!this._context) {
629 return;
630 }
631 const preserveNativeView = this.reusable && !force;
632 this.resetNativeViewInternal();
633 if (!preserveNativeView) {
634 this.eachChild((child) => {
635 child._tearDownUI(force);
636 return true;
637 });
638 }
639 if (this.parent) {
640 this.parent._removeViewFromNativeVisualTree(this);
641 }
642 // const nativeView = this.nativeViewProtected;
643 // if (nativeView && global.isAndroid) {
644 // const recycle = this.recycleNativeView;
645 // let shouldRecycle = false;
646 // if (recycle === "always") {
647 // shouldRecycle = true;
648 // } else if (recycle === "auto" && !this._disableNativeViewRecycling) {
649 // const propertiesSet = Object.getOwnPropertySymbols(this).length + Object.getOwnPropertySymbols(this.style).length / 2;
650 // shouldRecycle = propertiesSet <= this.recyclePropertyCounter;
651 // }
652 // // const nativeParent = global.isAndroid ? (<android.view.View>nativeView).getParent() : (<UIView>nativeView).superview;
653 // const nativeParent = (<android.view.View>nativeView).getParent();
654 // const animation = (<android.view.View>nativeView).getAnimation();
655 // if (shouldRecycle && !nativeParent && !animation) {
656 // putNativeView(this._context, this);
657 // }
658 // }
659 if (!preserveNativeView) {
660 this.disposeNativeView();
661 this._suspendNativeUpdates(SuspendType.UISetup);
662 if (global.isAndroid) {
663 this.setNativeView(null);
664 this._androidView = null;
665 }
666 // this._iosView = null;
667 this._context = null;
668 }
669 if (this.domNode) {
670 this.domNode.dispose();
671 this.domNode = undefined;
672 }
673 }
674 _childIndexToNativeChildIndex(index) {
675 return index;
676 }
677 /**
678 * Method is intended to be overridden by inheritors and used as "protected".
679 */
680 _addViewToNativeVisualTree(view, atIndex) {
681 if (view._isAddedToNativeVisualTree) {
682 throw new Error('Child already added to the native visual tree.');
683 }
684 return true;
685 }
686 /**
687 * Method is intended to be overridden by inheritors and used as "protected"
688 */
689 _removeViewFromNativeVisualTree(view) {
690 view._isAddedToNativeVisualTree = false;
691 }
692 _goToVisualState(state) {
693 if (Trace.isEnabled()) {
694 Trace.write(this + ' going to state: ' + state, Trace.categories.Style);
695 }
696 if (state === this._visualState) {
697 return;
698 }
699 this.deletePseudoClass(this._visualState);
700 this._visualState = state;
701 this.addPseudoClass(state);
702 }
703 /**
704 * @deprecated
705 *
706 * This used to be the way to set attribute values in early {N} versions.
707 * Now attributes are expected to be set as plain properties on the view instances.
708 */
709 _applyXmlAttribute(attribute, value) {
710 console.log('ViewBase._applyXmlAttribute(...) is deprecated; set attributes as plain properties instead');
711 if (attribute === 'style' || attribute === 'rows' || attribute === 'columns' || attribute === 'fontAttributes') {
712 this[attribute] = value;
713 return true;
714 }
715 return false;
716 }
717 setInlineStyle(style) {
718 if (typeof style !== 'string') {
719 throw new Error('Parameter should be valid CSS string!');
720 }
721 ensureStyleScopeModule();
722 styleScopeModule.applyInlineStyle(this, style, undefined);
723 }
724 _parentChanged(oldParent) {
725 const newParent = this.parent;
726 //Overridden
727 if (oldParent) {
728 clearInheritedProperties(this);
729 if (this.bindingContextBoundToParentBindingContextChanged) {
730 oldParent.off('bindingContextChange', this.bindingContextChanged, this);
731 }
732 }
733 else if (this.shouldAddHandlerToParentBindingContextChanged) {
734 newParent.on('bindingContextChange', this.bindingContextChanged, this);
735 this.bindings.get('bindingContext').bind(newParent.bindingContext);
736 }
737 }
738 onResumeNativeUpdates() {
739 // Apply native setters...
740 initNativeView(this, undefined, undefined);
741 }
742 toString() {
743 let str = this.typeName;
744 if (this.id) {
745 str += `<${this.id}>`;
746 }
747 else {
748 str += `(${this._domId})`;
749 }
750 const source = Source.get(this);
751 if (source) {
752 str += `@${source};`;
753 }
754 return str;
755 }
756 _onCssStateChange() {
757 this._cssState.onChange();
758 eachDescendant(this, (child) => {
759 child._cssState.onChange();
760 return true;
761 });
762 }
763 _inheritStyleScope(styleScope) {
764 // If we are styleScope don't inherit parent stylescope.
765 // TODO: Consider adding parent scope and merge selectors.
766 if (this._isStyleScopeHost) {
767 return;
768 }
769 if (this._styleScope !== styleScope) {
770 this._styleScope = styleScope;
771 this._onCssStateChange();
772 this.eachChild((child) => {
773 child._inheritStyleScope(styleScope);
774 return true;
775 });
776 }
777 }
778 showModal(...args) {
779 const parent = this.parent;
780 return parent && parent.showModal(...args);
781 }
782 closeModal(...args) {
783 const parent = this.parent;
784 if (parent) {
785 parent.closeModal(...args);
786 }
787 }
788 _dialogClosed() {
789 eachDescendant(this, (child) => {
790 child._dialogClosed();
791 return true;
792 });
793 }
794 _onRootViewReset() {
795 eachDescendant(this, (child) => {
796 child._onRootViewReset();
797 return true;
798 });
799 }
800}
801ViewBase.loadedEvent = 'loaded';
802ViewBase.unloadedEvent = 'unloaded';
803ViewBase.createdEvent = 'created';
804ViewBase.disposeNativeViewEvent = 'disposeNativeView';
805__decorate([
806 profile,
807 __metadata("design:type", Function),
808 __metadata("design:paramtypes", []),
809 __metadata("design:returntype", void 0)
810], ViewBase.prototype, "onLoaded", null);
811__decorate([
812 profile,
813 __metadata("design:type", Function),
814 __metadata("design:paramtypes", []),
815 __metadata("design:returntype", void 0)
816], ViewBase.prototype, "onUnloaded", null);
817__decorate([
818 profile,
819 __metadata("design:type", Function),
820 __metadata("design:paramtypes", [String]),
821 __metadata("design:returntype", void 0)
822], ViewBase.prototype, "addPseudoClass", null);
823__decorate([
824 profile,
825 __metadata("design:type", Function),
826 __metadata("design:paramtypes", [String]),
827 __metadata("design:returntype", void 0)
828], ViewBase.prototype, "deletePseudoClass", null);
829__decorate([
830 profile,
831 __metadata("design:type", Function),
832 __metadata("design:paramtypes", []),
833 __metadata("design:returntype", void 0)
834], ViewBase.prototype, "requestLayout", null);
835__decorate([
836 profile,
837 __metadata("design:type", Function),
838 __metadata("design:paramtypes", [ViewBase, Number]),
839 __metadata("design:returntype", void 0)
840], ViewBase.prototype, "_addView", null);
841__decorate([
842 profile,
843 __metadata("design:type", Function),
844 __metadata("design:paramtypes", [Object, Number, Boolean]),
845 __metadata("design:returntype", void 0)
846], ViewBase.prototype, "_setupUI", null);
847__decorate([
848 profile,
849 __metadata("design:type", Function),
850 __metadata("design:paramtypes", [Boolean]),
851 __metadata("design:returntype", void 0)
852], ViewBase.prototype, "_tearDownUI", null);
853ViewBase.prototype.isCollapsed = false;
854ViewBase.prototype._oldLeft = 0;
855ViewBase.prototype._oldTop = 0;
856ViewBase.prototype._oldRight = 0;
857ViewBase.prototype._oldBottom = 0;
858ViewBase.prototype.effectiveMinWidth = 0;
859ViewBase.prototype.effectiveMinHeight = 0;
860ViewBase.prototype.effectiveWidth = 0;
861ViewBase.prototype.effectiveHeight = 0;
862ViewBase.prototype.effectiveMarginTop = 0;
863ViewBase.prototype.effectiveMarginRight = 0;
864ViewBase.prototype.effectiveMarginBottom = 0;
865ViewBase.prototype.effectiveMarginLeft = 0;
866ViewBase.prototype.effectivePaddingTop = 0;
867ViewBase.prototype.effectivePaddingRight = 0;
868ViewBase.prototype.effectivePaddingBottom = 0;
869ViewBase.prototype.effectivePaddingLeft = 0;
870ViewBase.prototype.effectiveBorderTopWidth = 0;
871ViewBase.prototype.effectiveBorderRightWidth = 0;
872ViewBase.prototype.effectiveBorderBottomWidth = 0;
873ViewBase.prototype.effectiveBorderLeftWidth = 0;
874ViewBase.prototype._defaultPaddingTop = 0;
875ViewBase.prototype._defaultPaddingRight = 0;
876ViewBase.prototype._defaultPaddingBottom = 0;
877ViewBase.prototype._defaultPaddingLeft = 0;
878ViewBase.prototype._isViewBase = true;
879ViewBase.prototype.recycleNativeView = 'never';
880ViewBase.prototype.reusable = false;
881ViewBase.prototype._suspendNativeUpdatesCount = SuspendType.Loaded | SuspendType.NativeView | SuspendType.UISetup;
882export const bindingContextProperty = new InheritedProperty({
883 name: 'bindingContext',
884});
885bindingContextProperty.register(ViewBase);
886export const hiddenProperty = new Property({
887 name: 'hidden',
888 defaultValue: false,
889 affectsLayout: global.isIOS,
890 valueConverter: booleanConverter,
891 valueChanged: (target, oldValue, newValue) => {
892 if (target) {
893 target.isCollapsed = !!newValue;
894 }
895 },
896});
897hiddenProperty.register(ViewBase);
898export const classNameProperty = new Property({
899 name: 'className',
900 valueChanged(view, oldValue, newValue) {
901 const cssClasses = view.cssClasses;
902 const rootViewsCssClasses = CSSUtils.getSystemCssClasses();
903 const shouldAddModalRootViewCssClasses = cssClasses.has(CSSUtils.MODAL_ROOT_VIEW_CSS_CLASS);
904 const shouldAddRootViewCssClasses = cssClasses.has(CSSUtils.ROOT_VIEW_CSS_CLASS);
905 cssClasses.clear();
906 if (shouldAddModalRootViewCssClasses) {
907 cssClasses.add(CSSUtils.MODAL_ROOT_VIEW_CSS_CLASS);
908 }
909 else if (shouldAddRootViewCssClasses) {
910 cssClasses.add(CSSUtils.ROOT_VIEW_CSS_CLASS);
911 }
912 rootViewsCssClasses.forEach((c) => cssClasses.add(c));
913 if (typeof newValue === 'string' && newValue !== '') {
914 newValue.split(' ').forEach((c) => cssClasses.add(c));
915 }
916 view._onCssStateChange();
917 },
918});
919classNameProperty.register(ViewBase);
920export const idProperty = new Property({
921 name: 'id',
922 valueChanged: (view, oldValue, newValue) => view._onCssStateChange(),
923});
924idProperty.register(ViewBase);
925export function booleanConverter(v) {
926 const lowercase = (v + '').toLowerCase();
927 if (lowercase === 'true') {
928 return true;
929 }
930 else if (lowercase === 'false') {
931 return false;
932 }
933 throw new Error(`Invalid boolean: ${v}`);
934}
935//# sourceMappingURL=index.js.map
\No newline at end of file