blob: 356296e47166b3406c9f4fcdc166729114d12fe2 [file] [log] [blame]
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {Store, StoreObserver} from 'chrome://resources/js/cr/ui/store.js';
import {StoreClient, StoreClientInterface} from 'chrome://resources/js/cr/ui/store_client.js';
import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/js/i18n_behavior.m.js';
import {IronResizableBehavior} from 'chrome://resources/polymer/v3_0/iron-resizable-behavior/iron-resizable-behavior.js';
import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {emptyState, PersonalizationState, reduce} from './personalization_reducers.js';
/**
* @fileoverview A singleton datastore for the personalization app. Page state
* is publicly readable, but can only be modified by dispatching an Action to
* the store. Any data that is shared between components should go here.
*/
/** @extends {Store<PersonalizationState>} */
export class PersonalizationStore extends Store {
constructor() {
super(emptyState(), reduce);
}
/** @return {!PersonalizationStore} */
static getInstance() {
return instance_ || (instance_ = new PersonalizationStore());
}
/** @param {?PersonalizationStore} instance */
static setInstance(instance) {
instance_ = instance;
}
}
/**
* @type {?PersonalizationStore}
* @private
*/
let instance_ = null;
/**
* @polymerBehavior
*/
const PersonalizationStoreClientImpl = {
/**
* Override onStateChanged so property updates are batched. Reduces churn
* in polymer components when multiple state values change.
* @override
* @param {!PersonalizationState} newState
*/
onStateChanged(newState) {
const changes = this.watches_.reduce((result, watch) => {
const oldValue = this[watch.localProperty];
const newValue = watch.valueGetter(newState);
if (newValue !== oldValue && newValue !== undefined) {
result[watch.localProperty] = newValue;
}
return result;
}, {});
this.setProperties(changes);
},
/**
* @param {string} localProperty
* @param {function(!PersonalizationState):*} valueGetter
*/
watch(localProperty, valueGetter) {
this.watch_(localProperty, valueGetter);
},
/** @return {!PersonalizationState} */
getState() {
return this.getStore().data;
},
/** @return {!PersonalizationStore} */
getStore() {
return PersonalizationStore.getInstance();
},
};
export class PersonalizationStoreClientInterface {
/**
* @param {string} localProperty
* @param {function(!PersonalizationState): *} valueGetter
*/
watch(localProperty, valueGetter) {}
/** @return {!PersonalizationState} */
getState() {}
/** @return {!PersonalizationStore} */
getStore() {}
}
/**
* @polymerBehavior
* @implements {PersonalizationStoreClientInterface}
* @implements {StoreClientInterface}
* @implements {StoreObserver<PersonalizationState>}
* @implements {I18nBehavior}
* @implements {IronResizableBehavior}
*/
export const PersonalizationStoreClient = [
StoreClient,
PersonalizationStoreClientImpl,
I18nBehavior,
IronResizableBehavior,
];
/**
* @constructor
* @extends {PolymerElement}
* @implements {PersonalizationStoreClientInterface}
* @implements {StoreClientInterface}
* @implements {StoreObserver<PersonalizationState>}
* @implements {I18nBehaviorInterface}
*/
export const WithPersonalizationStore =
mixinBehaviors(PersonalizationStoreClient, PolymerElement);