1 line
7.2 KiB
Plaintext
1 line
7.2 KiB
Plaintext
|
{"version":3,"file":"until.js","sources":["../../../src/directives/until.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {Part, noChange} from '../lit-html.js';\nimport {isPrimitive} from '../directive-helpers.js';\nimport {directive, AsyncDirective} from '../async-directive.js';\nimport {Pauser, PseudoWeakRef} from './private-async-helpers.js';\n\nconst isPromise = (x: unknown) => {\n return !isPrimitive(x) && typeof (x as {then?: unknown}).then === 'function';\n};\n// Effectively infinity, but a SMI.\nconst _infinity = 0x3fffffff;\n\nexport class UntilDirective extends AsyncDirective {\n private __lastRenderedIndex: number = _infinity;\n private __values: unknown[] = [];\n private __weakThis = new PseudoWeakRef(this);\n private __pauser = new Pauser();\n\n render(...args: Array<unknown>) {\n return args.find((x) => !isPromise(x)) ?? noChange;\n }\n\n override update(_part: Part, args: Array<unknown>) {\n const previousValues = this.__values;\n let previousLength = previousValues.length;\n this.__values = args;\n\n const weakThis = this.__weakThis;\n const pauser = this.__pauser;\n\n // If our initial render occurs while disconnected, ensure that the pauser\n // and weakThis are in the disconnected state\n if (!this.isConnected) {\n this.disconnected();\n }\n\n for (let i = 0; i < args.length; i++) {\n // If we've rendered a higher-priority value already, stop.\n if (i > this.__lastRenderedIndex) {\n break;\n }\n\n const value = args[i];\n\n // Render non-Promise values immediately\n if (!isPromise(value)) {\n this.__lastRenderedIndex = i;\n // Since a lower-priority value will never overwrite a higher-priority\n // synchronous value, we can stop processing now.\n return value;\n }\n\n // If this is a Promise we've already handled, skip it.\n if (i < previousLength && value === previousValues[i]) {\n continue;\n }\n\n // We have a Promise that we haven't seen before, so priorities may have\n // changed. Forget what we rendered before.\n this.__lastRenderedIndex = _infinity;\n previousLength = 0;\n\n // Note, the callback avoids closing over `this` so that the directive\n // can be gc'ed before the promise resolves; instead `this` is retrieved\n // from `weakThis`, which can break the hard reference in the closure when\n // the directive disconnects\n Promise.resolve(value).then(async (result: unknown) => {\n // If we're disconnected, wait until we're (maybe) reconnected\n // The while loop here handles the case that the connection state\n // thrashes, causing the pauser to resume and then get re-paused\n while (pauser.get()) {\n await pauser.get();\n }\n // If the callback gets here and there is no `this`, it means that the\n // directive has been disconnected and garbage collected and we don't\n // need to do anything else\n const _this = weakThis.deref();\n if (_this !== undefined) {\n const index = _this.__values.indexOf(value);\n // If state.values doesn't contain the value, we've re-rendered without\n // the value, so don't render it. Then, only render if the value is\n // higher-priority than what's already been rendered.\n if (index > -1 && index < _this.__lastRenderedIndex) {\n _this.__lastRenderedIndex = index;\n _this.setValue(result);\n }\n }\n });\n }\n\n return noChange;\n }\n\n override disconnected() {\n this.__weakThis.disconnect();\n this.__pauser.pause();\n }\n\n override reconnected() {\n this.__weakThis.reconnect(this);\n this.__pauser.resume();\n }\n}\n\n/**\n * Renders one of a series of values, including Promises, to a Part.\n *\n * Values are rendered in priority order, with the first argument having the\n * highest priority and the last argument havi
|