@uiloos/core
Version:
The core of the uiloos headless UI
3,061 lines • 106 kB
JavaScript
class _LicenseChecker {
constructor() {
this._licenseKey = '';
this._logOnSuccess = false;
this._success = false;
}
activateLicense(licenseKey, options = { logLicenseActivated: true }) {
this._licenseKey = licenseKey;
this._logOnSuccess = options.logLicenseActivated;
}
_checkLicense() {
if (this._success) {
return;
}
if (this._licenseKey) {
const parts = this._licenseKey.split('-');
if (parts.length !== 2) {
console.warn(`uiloos > license > invalid license key detected: ${this._licenseKey}, ${buy}`);
}
else {
const [_, type] = parts;
if (this._logOnSuccess) {
console.log(`uiloos > license > license activated, this license is for use with ${type} developers. We thank you for your support, you can disable this message if you want to. ${owner}`);
}
this._success = true;
}
}
else {
console.warn(`uiloos > license > you are using commercial software, ${buy}`);
}
}
}
let licenseChecker = new _LicenseChecker();
const owner = 'If you are not the owner of this website please ignore this message.';
const buy = `please purchase a license at https://www.uiloos.dev. ${owner}`;
const common$3 = `uiloos > ActiveList >`;
class ActiveListAutoPlayDurationError extends Error {
constructor() {
super(`${common$3} autoPlay > duration cannot be negative or zero`);
this.name = 'ActiveListAutoPlayDurationError';
}
}
class _AutoPlay {
constructor(activeList, config) {
this._autoPlayTimeoutId = null;
this._autoPlayStarted = new Date();
this._pauseStarted = null;
this._autoPlayCurrentDuration = 0;
this._config = null;
this._activeList = activeList;
this._config = config;
}
_setConfig(config) {
this._config = config;
}
_play(inform) {
this._cancelTimer();
if (!this._config || this._activeList.lastActivatedContent === null) {
return;
}
const duration = this._getDuration(this._config, this._activeList.lastActivatedContent);
if (duration <= 0) {
throw new ActiveListAutoPlayDurationError();
}
this._autoPlayCurrentDuration = duration;
if (this._pauseStarted === null) {
this._activeList.autoPlay.duration = duration;
}
else {
this._pauseStarted = null;
}
this._autoPlayStarted = new Date();
this._autoPlayTimeoutId = window.setTimeout(() => {
this._autoPlayTimeoutId = null;
this._activeList.activateNext({ isUserInteraction: false });
}, duration);
this._activeList.autoPlay.isPlaying = true;
if (inform) {
const event = {
type: 'AUTO_PLAY_PLAYING',
time: new Date(),
};
this._activeList._inform(event);
}
}
_pause() {
if (!this._activeList.autoPlay.isPlaying) {
return;
}
this._pauseStarted = new Date();
this._cancelTimer();
this._activeList.autoPlay.isPlaying = false;
const event = {
type: 'AUTO_PLAY_PAUSED',
time: new Date(),
};
this._activeList._inform(event);
}
_stop() {
if (!this._activeList.autoPlay.isPlaying && !this._pauseStarted) {
return;
}
this._cancelTimer();
this._pauseStarted = null;
this._activeList.autoPlay.isPlaying = false;
this._activeList.autoPlay.duration = 0;
this._activeList.autoPlay.hasBeenStoppedBefore = true;
const event = {
type: 'AUTO_PLAY_STOPPED',
time: new Date(),
};
this._activeList._inform(event);
}
_cancelTimer() {
if (this._autoPlayTimeoutId !== null) {
window.clearTimeout(this._autoPlayTimeoutId);
this._autoPlayTimeoutId = null;
}
}
_onDeactivation(activationOptions) {
if (this._activeList.lastActivatedContent === null) {
this._stop();
return;
}
if (!this._config) {
return;
}
if (this._shouldStopOnUserInteraction(activationOptions, this._config)) {
this._stop();
return;
}
}
onActiveIndexChanged(index, activationOptions) {
if (!this._config) {
return;
}
if (this._shouldStopOnUserInteraction(activationOptions, this._config)) {
this._stop();
}
else if (this._activeList.isCircular === false &&
index === this._activeList.getLastIndex()) {
this._stop();
}
else {
this._play(false);
}
}
_shouldStopOnUserInteraction(activationOptions, config) {
return !!(activationOptions &&
activationOptions.isUserInteraction !== false &&
config.stopsOnUserInteraction);
}
_getDuration(config, lastActivatedContent) {
if (this._pauseStarted) {
return (this._autoPlayCurrentDuration -
(this._pauseStarted.getTime() - this._autoPlayStarted.getTime()));
}
if (typeof config.duration === 'number') {
return config.duration;
}
else {
return config.duration({
index: lastActivatedContent.index,
content: lastActivatedContent,
value: lastActivatedContent.value,
activeList: this._activeList,
});
}
}
}
class ActiveListContent {
constructor(activeList, index, value) {
this.isActive = false;
this.hasBeenActiveBefore = false;
this.isFirst = false;
this.isLast = false;
this.hasNext = false;
this.hasPrevious = false;
this.isNext = false;
this.isPrevious = false;
this.activeList = activeList;
this.index = index;
this.value = value;
}
activate(activationOptions) {
this.activeList.activateByIndex(this.index, activationOptions);
}
deactivate(activationOptions) {
this.activeList.deactivateByIndex(this.index, activationOptions);
}
toggle(activationOptions) {
this.activeList.toggleByIndex(this.index, activationOptions);
}
remove() {
return this.activeList.removeByIndex(this.index);
}
swapWith(item) {
const itemIndex = this.activeList.getIndex(item);
this.swapWithByIndex(itemIndex);
}
swapWithByIndex(index) {
this.activeList.swapByIndex(this.index, index);
}
swapWithNext() {
const nextIndex = this.activeList._getBoundedNextIndex(this.index);
this.swapWithByIndex(nextIndex);
}
swapWithPrevious() {
const previousIndex = this.activeList._getBoundedPreviousIndex(this.index);
this.swapWithByIndex(previousIndex);
}
moveToIndex(to) {
this.activeList.moveByIndex(this.index, to);
}
moveToPredicate(predicate, options) {
this.activeList.moveByIndexByPredicate(this.index, predicate, options);
}
moveToFirst() {
this.activeList.moveByIndex(this.index, 0);
}
moveToLast() {
this.activeList.moveByIndex(this.index, this.activeList.getLastIndex());
}
}
class ActiveListCooldownDurationError extends Error {
constructor() {
super(`${common$3} cooldown > duration cannot be negative or zero`);
this.name = "ActiveListCooldownDurationError";
}
}
class _CooldownTimer {
constructor(activeList, cooldown) {
this._cooldownTimeoutId = null;
this._cooldown = undefined;
if (typeof cooldown === 'number') {
this._assertDuration(cooldown);
}
this._activeList = activeList;
this._cooldown = cooldown;
}
_isActive(activationOptions) {
if (activationOptions.isUserInteraction === false) {
return false;
}
return this._activeList.cooldown.isActive;
}
_setCooldown(activationOptions, content) {
if (activationOptions.isUserInteraction === false) {
return;
}
const duration = this._getDuration(activationOptions, content);
if (duration === -1) {
this._stopCooldown();
return;
}
this._activeList.cooldown.isActive = true;
this._activeList.cooldown.duration = duration;
this._cooldownTimeoutId = window.setTimeout(() => {
this._stopCooldown();
}, duration);
const event = {
type: 'COOLDOWN_STARTED',
time: new Date(),
};
this._activeList._inform(event);
}
_getDuration(activationOptions, content) {
let duration = -1;
if (activationOptions.cooldown !== undefined) {
duration = this._getDurationFromConfig(activationOptions.cooldown, content);
}
else if (this._cooldown !== undefined) {
duration = this._getDurationFromConfig(this._cooldown, content);
}
else {
return -1;
}
this._assertDuration(duration);
return duration;
}
_getDurationFromConfig(cooldownConfig, content) {
if (typeof cooldownConfig === 'number') {
return cooldownConfig;
}
else {
return cooldownConfig({
index: content.index,
content: content,
value: content.value,
activeList: this._activeList,
});
}
}
_assertDuration(cooldownValue) {
if (cooldownValue <= 0) {
throw new ActiveListCooldownDurationError();
}
}
_stopCooldown() {
if (this._cooldownTimeoutId) {
window.clearTimeout(this._cooldownTimeoutId);
}
if (!this._activeList.cooldown.isActive) {
return;
}
this._activeList.cooldown.isActive = false;
this._activeList.cooldown.duration = 0;
const event = {
type: 'COOLDOWN_ENDED',
time: new Date(),
};
this._activeList._inform(event);
}
}
class ActiveListActivationLimitReachedError extends Error {
constructor() {
super(`${common$3} activateByIndex > activation limit reached`);
this.name = 'ActiveListActivationLimitReachedError';
}
}
class ActiveListIndexOutOfBoundsError extends Error {
constructor(message) {
super(message);
this.name = "ActiveListIndexOutOfBoundsError";
}
}
function throwIndexOutOfBoundsError(method, indexName) {
throw new ActiveListIndexOutOfBoundsError(`${common$3} ${method} > "${indexName}" is out of bounds`);
}
class ActiveListItemNotFoundError extends Error {
constructor() {
super(`${common$3} getIndex > index cannot be found, item is not in contents array`);
this.name = 'ActiveListItemNotFoundError';
}
}
class _History {
constructor() {
this._events = [];
this._keepHistoryFor = 0;
}
_push(event) {
if (this._keepHistoryFor > 0) {
this._events.push(event);
if (this._events.length - 1 === this._keepHistoryFor) {
this._events.shift();
}
}
}
_setKeepHistoryFor(_keepHistoryFor = 0) {
this._keepHistoryFor = _keepHistoryFor;
}
}
class _Observer {
constructor() {
this._subscribers = [];
}
_subscribe(subscriber) {
this._subscribers.push(subscriber);
return () => {
this._unsubscribe(subscriber);
};
}
_unsubscribe(subscriber) {
this._subscribers = this._subscribers.filter((s) => subscriber !== s);
}
_clear() {
this._subscribers.length = 0;
}
_inform(observable, event) {
this._subscribers.forEach((subscriber) => subscriber(observable, event));
}
}
class ActiveList {
constructor(config = {}, subscriber) {
this._isInitializing = false;
this.contents = [];
this.maxActivationLimit = 1;
this.maxActivationLimitBehavior = 'circular';
this.active = [];
this.activeContents = [];
this.activeIndexes = [];
this.lastActivated = null;
this.lastActivatedContent = null;
this.lastActivatedIndex = -1;
this.lastDeactivated = null;
this.lastDeactivatedContent = null;
this.lastDeactivatedIndex = -1;
this.isCircular = false;
this.direction = 'right';
this.oppositeDirection = 'left';
this._history = new _History();
this.history = this._history._events;
this._observer = new _Observer();
this.hasActiveChangedAtLeastOnce = false;
this.cooldown = {
isActive: false,
duration: 0,
};
this.autoPlay = {
isPlaying: false,
duration: 0,
hasBeenStoppedBefore: false,
};
licenseChecker._checkLicense();
if (subscriber) {
this.subscribe(subscriber);
}
this.initialize(config);
}
subscribe(subscriber) {
return this._observer._subscribe(subscriber);
}
unsubscribe(subscriber) {
this._observer._unsubscribe(subscriber);
}
unsubscribeAll() {
this._observer._clear();
}
initialize(config) {
this._isInitializing = true;
this.maxActivationLimit =
config.maxActivationLimit !== undefined ? config.maxActivationLimit : 1;
this.maxActivationLimitBehavior = config.maxActivationLimitBehavior
? config.maxActivationLimitBehavior
: 'circular';
this.isCircular = !!config.isCircular;
const contents = config.contents ? config.contents : [];
this.contents.length = 0;
contents.forEach((c, index) => {
this.contents[index] = this._initializeABrokenContent(c, index, contents);
});
this._directions = config.directions
? config.directions
: { next: 'right', previous: 'left' };
this._history._events.length = 0;
this._history._setKeepHistoryFor(config.keepHistoryFor);
this._becameEmpty();
this._activationCooldownTimer = new _CooldownTimer(this, config.cooldown);
this.cooldown.isActive = false;
this.cooldown.duration = 0;
if (config.active !== undefined) {
if (Array.isArray(config.active)) {
config.active.forEach((active) => this.activate(active, { isUserInteraction: false }));
}
else {
this.activate(config.active, { isUserInteraction: false });
}
}
else if (config.activeIndexes !== undefined) {
if (Array.isArray(config.activeIndexes)) {
config.activeIndexes.forEach((index) => this.activateByIndex(index, {
isUserInteraction: false,
}));
}
else {
this.activateByIndex(config.activeIndexes, {
isUserInteraction: false,
});
}
}
this._emptyLastDeactivated();
this.hasActiveChangedAtLeastOnce = false;
this.direction = this._directions.next;
this.oppositeDirection = this._directions.previous;
this.autoPlay.isPlaying = false;
this.autoPlay.duration = 0;
this.autoPlay.hasBeenStoppedBefore = false;
this._autoPlay = new _AutoPlay(this, config.autoPlay ? config.autoPlay : null);
this._autoPlay._play(false);
this._isInitializing = false;
const event = {
type: 'INITIALIZED',
values: [...this.active],
indexes: [...this.activeIndexes],
time: new Date(),
};
this._inform(event);
}
_initializeABrokenContent(value, index, contents) {
const content = new ActiveListContent(this, index, value);
this._repairContent(content, index, contents);
return content;
}
activateByIndex(index, activationOptions = {
isUserInteraction: true,
cooldown: undefined,
}) {
const previousDeactivatedIndex = this.lastDeactivatedIndex;
const activatedContent = this._doActivateByIndex(index, activationOptions);
if (!activatedContent) {
return;
}
let deactivatedIndex = -1;
let deactivatedValue = null;
if (previousDeactivatedIndex !== this.lastDeactivatedIndex) {
deactivatedIndex = this.lastDeactivatedIndex;
deactivatedValue = this.lastDeactivated;
}
const event = {
type: 'ACTIVATED',
value: activatedContent.value,
index,
deactivatedIndex,
deactivatedValue,
time: new Date(),
};
this._inform(event);
this._activationCooldownTimer._setCooldown(activationOptions, this.lastActivatedContent);
}
_doActivateByIndex(index, activationOptions) {
if (this._checkIndex(index)) {
throwIndexOutOfBoundsError('activateByIndex', 'index');
}
if (this.activeIndexes.includes(index)) {
return null;
}
if (this._activationCooldownTimer._isActive(activationOptions)) {
return null;
}
const limitReached = this.maxActivationLimit === false
? false
: this.maxActivationLimit === this.activeIndexes.length;
if (limitReached) {
if (this.maxActivationLimitBehavior === 'error') {
throw new ActiveListActivationLimitReachedError();
}
else if (this.maxActivationLimitBehavior === 'ignore') {
return null;
}
}
const nextIndex = this._getUnboundedNextIndex(index);
const previousIndex = this._getUnboundedPreviousIndex(index);
this.contents.forEach((content, i) => {
content.isActive = content.isActive ? content.isActive : index === i;
content.isNext = nextIndex === i;
content.isPrevious = previousIndex === i;
if (index === i) {
this.activeIndexes.push(i);
this.activeContents.push(content);
this.active.push(content.value);
if (limitReached) {
this.activeIndexes.shift();
this.active.shift();
const content = this.activeContents.shift();
if (content) {
this._deactivateContent(content);
}
}
this.direction = this._getDirectionWhenMovingToIndex(i);
this.oppositeDirection =
this.direction === this._directions.next
? this._directions.previous
: this._directions.next;
this.lastActivated = content.value;
this.lastActivatedContent = content;
this.lastActivatedIndex = i;
content.hasBeenActiveBefore = true;
}
});
if (this._autoPlay) {
this._autoPlay.onActiveIndexChanged(index, activationOptions);
}
this.hasActiveChangedAtLeastOnce = true;
return this.lastActivatedContent;
}
activate(item, activationOptions) {
const index = this.getIndex(item);
this.activateByIndex(index, activationOptions);
}
activateByPredicate(predicate, activationOptions = {
isUserInteraction: true,
cooldown: undefined,
}) {
if (this._activationCooldownTimer._isActive(activationOptions)) {
return undefined;
}
const previousActiveIndexes = [...this.activeIndexes];
let lastActivated = null;
let error = null;
this._execPred(predicate, (index) => {
try {
const content = this._doActivateByIndex(index, activationOptions);
if (content) {
lastActivated = content;
}
}
catch (e) {
if (e instanceof ActiveListActivationLimitReachedError) {
error = e;
return true;
}
}
});
if (lastActivated) {
const values = [];
const indexes = [];
this.activeIndexes.forEach((current) => {
const isNewlyActivated = previousActiveIndexes.every((prev) => prev !== current);
if (isNewlyActivated) {
indexes.push(current);
values.push(this.contents[current].value);
}
});
const deactivatedValues = [];
const deactivatedIndexes = [];
if (this.maxActivationLimit !== false &&
this.maxActivationLimitBehavior === 'circular') {
previousActiveIndexes.forEach((prev) => {
const isNewlyDeactivated = this.activeIndexes.every((current) => prev !== current);
if (isNewlyDeactivated) {
deactivatedIndexes.push(prev);
deactivatedValues.push(this.contents[prev].value);
}
});
}
const event = {
type: 'ACTIVATED_MULTIPLE',
values,
indexes,
deactivatedIndexes,
deactivatedValues,
time: new Date(),
};
this._inform(event);
if (lastActivated) {
this._activationCooldownTimer._setCooldown(activationOptions, lastActivated);
}
}
if (error) {
throw error;
}
}
activateNext(activationOptions) {
if (this.isEmpty()) {
return;
}
const index = this._getBoundedNextIndex(this.lastActivatedIndex);
this.activateByIndex(index, activationOptions);
}
activatePrevious(activationOptions) {
if (this.isEmpty()) {
return;
}
const index = this._getBoundedPreviousIndex(this.lastActivatedIndex);
this.activateByIndex(index, activationOptions);
}
activateFirst(activationOptions) {
if (this.isEmpty()) {
return;
}
this.activateByIndex(0, activationOptions);
}
activateLast(activationOptions) {
if (this.isEmpty()) {
return;
}
this.activateByIndex(this.getLastIndex(), activationOptions);
}
deactivateByIndex(index, activationOptions = {
isUserInteraction: true,
cooldown: undefined,
}) {
const deactivatedContent = this._doDeactivateByIndex(index, activationOptions);
if (!deactivatedContent) {
return;
}
const event = {
type: 'DEACTIVATED',
value: this.contents[index].value,
index,
time: new Date(),
};
this._inform(event);
this._activationCooldownTimer._setCooldown(activationOptions, deactivatedContent);
}
_doDeactivateByIndex(index, activationOptions) {
if (this._checkIndex(index)) {
throwIndexOutOfBoundsError('deactivateByIndex', 'index');
}
const indexOfIndex = this.activeIndexes.indexOf(index);
if (indexOfIndex === -1) {
return null;
}
if (this._activationCooldownTimer._isActive(activationOptions)) {
return null;
}
const deactivatedContent = this.activeContents[indexOfIndex];
this._deactivateContent(deactivatedContent);
this.activeIndexes.splice(indexOfIndex, 1);
this.active.splice(indexOfIndex, 1);
this.activeContents.splice(indexOfIndex, 1);
if (this.activeIndexes.length === 0) {
this._emptyLastActives();
this.direction = this._directions.next;
}
else {
this._setLastActives();
this.direction = this._getDirectionWhenMovingToIndex(deactivatedContent.index);
this.oppositeDirection = this.direction;
this.direction =
this.direction === this._directions.next
? this._directions.previous
: this._directions.next;
}
this._repairContents();
this.hasActiveChangedAtLeastOnce = true;
if (this._autoPlay) {
this._autoPlay._onDeactivation(activationOptions);
}
return deactivatedContent;
}
deactivate(item, activationOptions) {
const index = this.getIndex(item);
this.deactivateByIndex(index, activationOptions);
}
deactivateByPredicate(predicate, activationOptions = {
isUserInteraction: true,
cooldown: undefined,
}) {
if (this._activationCooldownTimer._isActive(activationOptions)) {
return undefined;
}
const deactivatedIndexes = [];
const deactivatedValues = [];
let lastRemoved = null;
this._execPred(predicate, (index) => {
const content = this._doDeactivateByIndex(index, activationOptions);
if (content) {
deactivatedIndexes.push(content.index);
deactivatedValues.push(content.value);
lastRemoved = content;
}
});
if (deactivatedIndexes.length === 0) {
return;
}
const event = {
type: 'DEACTIVATED_MULTIPLE',
values: deactivatedValues,
indexes: deactivatedIndexes,
time: new Date(),
};
this._inform(event);
if (lastRemoved) {
this._activationCooldownTimer._setCooldown(activationOptions, lastRemoved);
}
}
toggleByIndex(index, activationOptions) {
if (this._checkIndex(index)) {
throwIndexOutOfBoundsError('toggleByIndex', 'index');
}
if (this.contents[index].isActive) {
this.deactivateByIndex(index, activationOptions);
}
else {
this.activateByIndex(index, activationOptions);
}
}
toggle(item, activationOptions) {
const index = this.getIndex(item);
this.toggleByIndex(index, activationOptions);
}
play() {
this._autoPlay._play(true);
}
pause() {
this._autoPlay._pause();
}
stop() {
this._autoPlay._stop();
}
configureAutoPlay(autoPlayConfig) {
this._autoPlay._setConfig(autoPlayConfig);
if (autoPlayConfig) {
this._autoPlay._play(true);
}
else {
this._autoPlay._stop();
}
}
insertAtIndex(item, index) {
if (index < 0 || index > this.contents.length) {
throwIndexOutOfBoundsError('insertAtIndex', 'index');
}
const content = this._initializeABrokenContent(item, index, this.contents);
this.activeIndexes.forEach((i, aiIndex) => {
this.activeIndexes[aiIndex] = i >= index ? i + 1 : i;
});
this.contents.splice(index, 0, content);
if (index <= this.lastActivatedIndex) {
this.lastActivatedIndex += 1;
}
this._repairContents();
const event = {
type: 'INSERTED',
value: item,
index,
time: new Date(),
};
this._inform(event);
return content;
}
push(item) {
return this.insertAtIndex(item, this.contents.length);
}
unshift(item) {
return this.insertAtIndex(item, 0);
}
insertByPredicate(item, predicate, options = { mode: 'at' }) {
const mod = this._modeToMod(options.mode);
return this._execPred(predicate, (index) => {
const atIndex = Math.max(0, index + mod);
return this.insertAtIndex(item, atIndex);
});
}
removeByIndex(index) {
const value = this._doRemoveAtIndex(index);
const indexOfIndex = this.activeIndexes.indexOf(index);
if (indexOfIndex !== -1) {
this.activeIndexes.splice(indexOfIndex, 1);
this.active.splice(indexOfIndex, 1);
this.activeContents.splice(indexOfIndex, 1);
this.hasActiveChangedAtLeastOnce = true;
}
this.activeIndexes.map((i, aiIndex) => {
this.activeIndexes[aiIndex] = i >= index ? i - 1 : i;
});
if (this.isEmpty()) {
this._becameEmpty();
this._autoPlay._stop();
}
else {
this._setLastActives();
}
this._repairContents();
const event = {
type: 'REMOVED',
value,
index,
time: new Date(),
};
this._inform(event);
return value;
}
_doRemoveAtIndex(index) {
if (this._checkIndex(index)) {
throwIndexOutOfBoundsError('removeByIndex', 'index');
}
if (this.lastDeactivated && this.lastDeactivatedIndex === index) {
this._emptyLastDeactivated();
}
const value = this.contents[index].value;
this.contents.splice(index, 1);
return value;
}
remove(item) {
const index = this.getIndex(item);
return this.removeByIndex(index);
}
pop() {
if (this.isEmpty()) {
return undefined;
}
return this.removeByIndex(this.getLastIndex());
}
shift() {
if (this.isEmpty()) {
return undefined;
}
return this.removeByIndex(0);
}
removeByPredicate(predicate) {
if (this.isEmpty()) {
return [];
}
const removed = [];
this._execPred(predicate, (index) => {
const content = this.contents[index];
removed.push(content);
});
const removedIndexes = [];
removed.forEach((content, index) => {
const actualIndex = content.index - index;
this._doRemoveAtIndex(actualIndex);
removedIndexes.push(content.index);
});
if (this.isEmpty()) {
this._becameEmpty();
this._autoPlay._stop();
}
else {
removedIndexes.forEach((index) => {
const indexOfIndex = this.activeIndexes.indexOf(index);
if (indexOfIndex !== -1) {
this.activeIndexes.splice(indexOfIndex, 1);
this.active.splice(indexOfIndex, 1);
this.activeContents.splice(indexOfIndex, 1);
this.hasActiveChangedAtLeastOnce = true;
}
});
removedIndexes.forEach((removed) => {
this.activeIndexes.forEach((index, aiIndex) => {
this.activeIndexes[aiIndex] = index >= removed ? index - 1 : index;
});
});
this._setLastActives();
}
const removedValues = removed.map((r) => r.value);
if (removedIndexes.length > 0) {
this._repairContents();
const event = {
type: 'REMOVED_MULTIPLE',
indexes: [...removedIndexes],
values: [...removedValues],
time: new Date(),
};
this._inform(event);
}
return removedValues;
}
swapByIndex(a, b) {
if (this._checkIndex(a)) {
throwIndexOutOfBoundsError('swapByIndex', 'a');
}
if (this._checkIndex(b)) {
throwIndexOutOfBoundsError('swapByIndex', 'b');
}
if (a === b) {
return;
}
const itemA = this.contents[a];
const itemB = this.contents[b];
if (this.lastActivatedIndex === itemA.index) {
this.lastActivatedIndex = itemB.index;
}
else if (this.lastActivatedIndex === itemB.index) {
this.lastActivatedIndex = itemA.index;
}
const indexOfA = this.activeIndexes.indexOf(itemA.index);
const indexOfB = this.activeIndexes.indexOf(itemB.index);
if (indexOfA !== -1) {
this.activeIndexes[indexOfA] = itemB.index;
}
if (indexOfB !== -1) {
this.activeIndexes[indexOfB] = itemA.index;
}
itemA.index = b;
itemB.index = a;
this.contents[a] = itemB;
this.contents[b] = itemA;
this._repairContents();
const event = {
type: 'SWAPPED',
value: {
a: itemA.value,
b: itemB.value,
},
index: {
a,
b,
},
time: new Date(),
};
this._inform(event);
}
swap(a, b) {
const indexA = this.getIndex(a);
const indexB = this.getIndex(b);
this.swapByIndex(indexA, indexB);
}
moveByIndex(from, to) {
if (this._checkIndex(from)) {
throwIndexOutOfBoundsError('moveByIndex', 'from');
}
if (this._checkIndex(to)) {
throwIndexOutOfBoundsError('moveByIndex', 'to');
}
if (from === to) {
return;
}
const lastActivatedIndex = this.lastActivatedIndex;
if (lastActivatedIndex === from) {
this.lastActivatedIndex = to;
}
else if (to === lastActivatedIndex && from > lastActivatedIndex) {
this.lastActivatedIndex += 1;
}
else if (to === lastActivatedIndex && from < lastActivatedIndex) {
this.lastActivatedIndex -= 1;
}
else if (to > lastActivatedIndex && from < lastActivatedIndex) {
this.lastActivatedIndex -= 1;
}
else if (to < lastActivatedIndex && from > lastActivatedIndex) {
this.lastActivatedIndex += 1;
}
this.activeIndexes.forEach((index, aiIndex) => {
if (index === from) {
this.activeIndexes[aiIndex] = to;
return;
}
if (index > from && index > to) {
this.activeIndexes[aiIndex] = index;
return;
}
if (index < from && index < to) {
this.activeIndexes[aiIndex] = index;
return;
}
this.activeIndexes[aiIndex] = from > to ? index + 1 : index - 1;
});
const fromItem = this.contents[from];
this.contents.splice(from, 1);
this.contents.splice(to, 0, fromItem);
this._repairContents();
const event = {
type: 'MOVED',
value: fromItem.value,
index: {
from,
to,
},
time: new Date(),
};
this._inform(event);
}
move(item, to) {
const from = this.getIndex(item);
this.moveByIndex(from, to);
}
moveByIndexByPredicate(index, predicate, options = { mode: 'at' }) {
const mod = this._modeToMod(options.mode);
this._execPred(predicate, (i, length) => {
const atIndex = Math.min(Math.max(0, i + mod), length - 1);
this.moveByIndex(index, atIndex);
return true;
});
}
moveByPredicate(item, predicate, options) {
const index = this.getIndex(item);
this.moveByIndexByPredicate(index, predicate, options);
}
getIndex(item) {
const contents = this.contents;
const length = contents.length;
for (let i = 0; i < length; i++) {
if (contents[i].value === item) {
return i;
}
}
throw new ActiveListItemNotFoundError();
}
getLastIndex() {
return this.contents.length - 1;
}
_getBoundedNextIndex(index) {
let nextIndex = index + 1;
if (nextIndex >= this.contents.length) {
nextIndex = this.isCircular ? 0 : this.getLastIndex();
}
return nextIndex;
}
_getBoundedPreviousIndex(index) {
let previousIndex = index - 1;
if (previousIndex < 0) {
previousIndex = this.isCircular ? this.getLastIndex() : 0;
}
return previousIndex;
}
_getUnboundedNextIndex(index) {
const nextIndex = index + 1;
if (this.isCircular && nextIndex === this.contents.length) {
return 0;
}
return nextIndex;
}
_getUnboundedPreviousIndex(index) {
const previousIndex = index - 1;
if (this.isCircular && previousIndex < 0) {
return this.getLastIndex();
}
return previousIndex;
}
isEmpty() {
return this.contents.length === 0;
}
_getDirectionWhenMovingToIndex(next) {
const lastActivatedIndex = this.lastActivatedIndex;
if (this.isCircular) {
if (this.lastActivatedIndex === -1) {
return this._directions.next;
}
const lastActivatedLargerThanNext = this.lastActivatedIndex > next;
const lastIndex = this.getLastIndex();
const leftDistance = lastActivatedLargerThanNext
? this.lastActivatedIndex - next
: lastIndex - next + this.lastActivatedIndex + 1;
const rightDistance = lastActivatedLargerThanNext
? 1 + next + (lastIndex - this.lastActivatedIndex)
: next - this.lastActivatedIndex;
return leftDistance >= rightDistance
? this._directions.next
: this._directions.previous;
}
else {
return next >= lastActivatedIndex
? this._directions.next
: this._directions.previous;
}
}
_repairContents() {
let nextIndex = null;
let previousIndex = null;
if (this.lastActivatedIndex !== -1) {
nextIndex = this._getUnboundedNextIndex(this.lastActivatedIndex);
previousIndex = this._getUnboundedPreviousIndex(this.lastActivatedIndex);
}
this.contents.forEach((content, index) => {
content.index = index;
content.isNext = nextIndex === index;
content.isPrevious = previousIndex === index;
this._repairContent(content, index, this.contents);
});
}
_repairContent(content, index, contents) {
content.isFirst = index === 0;
content.isLast = index === contents.length - 1;
if (this.isCircular) {
content.hasNext = true;
content.hasPrevious = true;
}
else {
content.hasNext = index + 1 < contents.length;
content.hasPrevious = index - 1 >= 0;
}
}
_emptyLastActives() {
this.lastActivatedIndex = -1;
this.lastActivated = null;
this.lastActivatedContent = null;
}
_emptyLastDeactivated() {
this.lastDeactivatedIndex = -1;
this.lastDeactivated = null;
this.lastDeactivatedContent = null;
}
_becameEmpty() {
this._emptyLastDeactivated();
this._emptyLastActives();
this.activeContents.length = 0;
this.activeIndexes.length = 0;
this.active.length = 0;
this.hasActiveChangedAtLeastOnce = true;
}
_setLastActives() {
if (this.activeIndexes.length === 0) {
this._emptyLastActives();
return;
}
const newLastActiveIndex = this.activeIndexes[this.activeIndexes.length - 1];
const newLastActiveList = this.contents[newLastActiveIndex];
this.lastActivated = newLastActiveList.value;
this.lastActivatedContent = newLastActiveList;
this.lastActivatedIndex = newLastActiveIndex;
}
_deactivateContent(content) {
content.isActive = false;
this.lastDeactivated = content.value;
this.lastDeactivatedContent = content;
this.lastDeactivatedIndex = content.index;
}
_execPred(predicate, action) {
const contents = this.contents;
const length = contents.length;
for (let index = 0; index < length; index++) {
const content = this.contents[index];
const data = {
index,
content,
value: content.value,
activeList: this,
};
if (predicate(data)) {
const result = action(index, length);
if (result !== undefined) {
return result;
}
}
}
return null;
}
_inform(event) {
if (this._isInitializing) {
return;
}
this._history._push(event);
this._observer._inform(this, event);
}
_checkIndex(index) {
return index < 0 || index >= this.contents.length;
}
_modeToMod(mode) {
return mode === 'at' ? 0 : mode === 'after' ? 1 : -1;
}
}
function _callSubscriber(subscriberName, event, component, config) {
const methodName = 'on' +
event.type
.toLowerCase()
.split('_')
.reduce((acc, word) => {
const letters = word.split('');
letters[0] = letters[0].toUpperCase();
return acc + letters.join('');
}, '');
const method = config[methodName];
if (!method) {
if (config.debug) {
console.warn(`uiloos > ${subscriberName} event '${event.type}' was fired but '${methodName}' method is not implemented, this might not be correct.`);
}
return;
}
method(event, component);
}
function createActiveListSubscriber(config) {
return (activeList, event) => {
_callSubscriber('createActiveListSubscriber', event, activeList, config);
};
}
const common$2 = `uiloos > ViewChannel >`;
class ViewChannelAutoDismissDurationError extends Error {
constructor() {
super(`${common$2} autoDismiss > duration cannot be negative or zero`);
this.name = 'ViewChannelAutoDismissDurationError';
}
}
class _AutoDismiss {
constructor(view, config) {
this._autoDismissTimeoutId = null;
this._autoDismissStarted = new Date();
this._pauseStarted = null;
this._autoDismissCurrentDuration = 0;
this._config = null;
this._view = view;
this._config = config;
}
_play(inform) {
if (this._view.autoDismiss.isPlaying) {
return;
}
this._cancelTimer();
if (!this._config) {
return;
}
const duration = this._getDuration(this._config);
if (duration <= 0) {
throw new ViewChannelAutoDismissDurationError();
}
this._autoDismissCurrentDuration = duration;
this._autoDismissStarted = new Date();
if (this._pauseStarted === null) {
this._view.autoDismiss.duration = duration;
}
const result = this._config.result;
this._autoDismissTimeoutId = window.setTimeout(() => {
if (this._view.isPresented) {
this._view.autoDismiss.isPlaying = false;
this._view.autoDismiss.duration = 0;
this._view.viewChannel._doRemoveByIndex(this._view.index, result, 'AUTO_DISMISS');
}
this._autoDismissTimeoutId = null;
}, duration);
this._view.result.then(() => {
this._cancelTimer();
});
this._view.autoDismiss.isPlaying = true;
if (inform) {
const event = {
type: 'AUTO_DISMISS_PLAYING',
view: this._view,
index: this._view.index,
time: new Date(),
};
this._view.viewChannel._inform(event);
}
}
_pause() {
if (!this._view.autoDismiss.isPlaying) {
return;
}
this._pauseStarted = new Date();
this._cancelTimer();
this._view.autoDismiss.isPlaying = false;
const event = {
type: 'AUTO_DISMISS_PAUSED',
view: this._view,
index: this._view.index,
time: new Date(),
};
this._view.viewChannel._inform(event);
}
_stop() {
if (!this._view.autoDismiss.isPlaying && !this._pauseStarted) {
return;
}
this._cancelTimer();
this._pauseStarted = null;
this._view.autoDismiss.isPlaying = false;
this._view.autoDismiss.duration = 0;
const event = {
type: 'AUTO_DISMISS_STOPPED',
view: this._view,
index: this._view.index,
time: new Date(),
};
this._view.viewChannel._inform(event);
}
_cancelTimer() {
if (this._autoDismissTimeoutId !== null) {
window.clearTimeout(this._autoDismissTimeoutId);
this._autoDismissTimeoutId = null;
}
}
_getDuration(config) {
if (this._pauseStarted) {
return (this._autoDismissCurrentDuration -
(this._pauseStarted.getTime() - this._autoDismissStarted.getTime()));
}
return config.duration;
}
}
class ViewChannelView {
constructor(viewChannel, index, data, priority, autoDismissConfig) {
var _a;
this.autoDismiss = {
isPlaying: false,
duration: 0,
};
this._resolve = null;
this.isPresented = true;
this.viewChannel = viewChannel;
this.index = index;
this.data = data;
this.priority = priority;
this.result = new Promise((resolve) => {
this._resolve = resolve;
});
this._autoDismiss = new _AutoDismiss(this, autoDismissConfig);
this._autoDismiss._play(false);
this.autoDismiss.duration = (_a = autoDismissConfig === null || autoDismissConfig === void 0 ? void 0 : autoDismissConfig.duration) !== null && _a !== void 0 ? _a : 0;
}
dismiss(result) {
this.viewChannel.dismiss(this, result);
}
play() {
this._autoDismiss._play(true);
}
pause() {
this._autoDismiss._pause();
}
stop() {
this._autoDismiss._stop();
}
changeData(data) {
this.viewChannel.changeData(this, data);
}
}
class ViewChannelIndexOutOfBoundsError extends Error {
constructor(method) {
super(`${common$2} ${method} > "index" is out of bounds`);
this.name = 'ViewChannelIndexOutOfBoundsError';
}
}
class ViewChannelViewNotFoundError extends Error {
constructor(method) {
super(`${common$2} ${method} > "ViewChannelView" not found in views array`);
this.name = 'ViewChannelViewNotFoundError';
}
}
class ViewChannel {
constructor(config = {}, subscriber) {
this.views = [];
this._history = new _History();
this.history = this._history._events;
this._observer = new _Observer();
licenseChecker._checkLicense();
if (subscriber) {
this.subscribe(subscriber);
}
this.initialize(config);
}
initialize(config) {
this._history._events.length = 0;
this._history._setKeepHistoryFor(config.keepHistoryFor);
this._clearViews();
const event = {
type: 'INITIALIZED',
time: new Date(),
};
this._inform(event);
}
subscribe(subscriber) {
return this._observer._subscribe(subscriber);
}
unsubscribe(subscriber) {
this._observer._unsubscribe(subscriber);
}
unsubscribeAll() {
this._observer._clear();
}
present(viewConfig) {
const priority = viewConfig.priority ? viewConfig.priority : 0;
const priorityArray = Array.isArray(priority) ? priority : [priority];
const index = this._getIndexForPriority(priorityArray);
const view = new ViewChannelView(this, index, viewConfig.data, priorityArray, viewConfig.autoDismiss);
this.views.splice(index, 0, view);
this._repairIndexes();
const event = {
type: 'PRESENTED',
view,
index,
time: new Date(),
};
this._inform(event);
return view;
}
_doRemoveByIndex(index, result, reason) {
if (index < 0 || index >= this.views.length) {
throw new ViewChannelIndexOutOfBoundsError('dismissByIndex');
}
const view = this.views[index];
this.views.splice(index, 1);
this._repairIndexes();
view.isPresented = false;
view.autoDismiss.duration = 0;
view.autoDismiss.isPlaying = false;
view._resolve(result);
const event = {
type: 'DISMISSED',
view,
index,
reason,
time: new Date(),
};
this._inform(event);
}
dismissByIndex(index, result) {
this._doRemoveByIndex(index, result, 'USER_INTERACTION');
}
dismiss(view, result) {
if (!view.isPresented) {
return;
}
const index = this.views.indexOf(view);
if (index === -1) {
throw new ViewChannelViewNotFoundError('dismiss');
}
this.dismissByIndex(index, result);
}
dismissAll(result) {
if (this.views.length === 0) {
return;
}
const indexes = [];
const dismissedViews = [...this.views];
this._clearViews();
dismissedViews.forEach((view) => {
view.isPresented = false;
view._resolve(result);
indexes.push(view.index);
});
const event = {
type: 'DISMISSED_ALL',
views: dismissedViews,
indexes,
time: new Date(),
};
this._inform(event);
}
changeDataByIndex(index, data) {
if (index < 0 || index >= this.views.length) {
throw new ViewChannelIndexOutOfBoundsError('changeDataByIndex');
}
const view = this.views[index];
view.data = data;
const event = {
type: 'DATA_CHANGED',
view: view,
data,
index: view.index,
time: new Date(),
};
this._inform(event);
}
changeData(view, data) {
const index = this.views.indexOf(view);
if (index === -1) {
throw new ViewChannelViewNotFoundError('changeData');
}
this.changeDataByIndex(index, data);
}
_getIndexForPriority(priority) {
for (let view of this.views) {
const largestArray = priority.length > view.priority.length ? priority : view.priority;
for (let level = 0; level < largestArray.length; level++) {
const inserted = this._getPriorityAtLevel(priority, level);
const existing = this._getPriorityAtLevel(view.priority, level);
if (inserted < existing) {
return view.index;
}
}
}
return this.views.length;
}
_getPriorityAtLevel(priorityArray, level) {
const priority = priorityArray[level];
if (priority !== undefined) {
return priority;
}
else {
return 0;
}
}
_repairIndexes() {
this.views.forEach((view, index) => {
view.index = index;
});
}
_clearViews() {
this.views.length = 0;
}
_inform(event) {
this._history._push(event);
this._observer._inform(this, event);
}
}
function createViewChannelSubscriber(config) {
return (viewChannel, event) => {
_callSubscriber('createViewChannelSubscriber', event, viewChannel, config);
};
}
class TypewriterCursor {
constructor(typewriter, position, data, selection) {
this.isBlinking = true;
this._blinkTimeoutId = null;
this._typewriter = typewriter;
this.position = position;
this.selection = selection;
this.data = data;
}
_startBlink() {
if (this.isBlinking) {
return;
}
this._clearBlink();
this._blinkTimeoutId = window.setTimeout(() => {
this.isBlinking = true;
const event = {
type: 'BLINKING',
time: new Date(),
cursor: this,
};
this._typewriter._inform(event);
}, this._typewriter.blinkAfter);
}
_clearBlink() {
if (this._blinkTimeoutId) {
window.clearTimeout(this._blinkTimeoutId);
this._blinkTimeoutId = null;
}
}
}
const name = 'Typewriter';
const common$1 = `uiloos > ${name} >`;
class TypewriterBlinkAfterError extends Error {
constructor() {
super(`${common$1} blinkAfter cannot be negative or zero`);
this.name = `${name}BlinkAfterError`;
}
}
class TypewriterDelayError extends Error {
constructor() {
super(`${common$1} delay cannot be negative or zero`);
this.name = `${name}DelayError`;
}
}
class TypewriterRepeatError extends Error {
constructor() {
super(`${common$1} repeat cannot be negative or zero`);
this.name = `${name}RepeatError`;
}
}
class TypewriterRepeatDelayError extends Error {
constructor() {
super(`${common$1} repeatDelay cannot be a negative number`);
this.name = `${name}RepeatDelayError`;
}
}
class TypewriterCursorOutOfBoundsError extends Error {
constructor() {
super(`${common$1} cursor is out of bounds`);
this.name = `${name}CursorOutOfBoundsError`;
}
}
class TypewriterCursorNotAtSelectionEdgeError extends Error {
constructor() {
super(`${common$1} cursor is not placed on edges of selection`);
this.name = `${name}CursorNotAtSelectionEdgeError`;
}
}
class TypewriterCursorSelectionInvalidRangeError extends Error {
constructor() {
super(`${common$1} cursors selection has an invalid range: start is equal or larger than the end`);
this.name = `${name}CursorSelectionInvalidRangeError`;
}
}
class TypewriterCursorSelectionOutOfBoundsError extends Error {
constructor(name) {
super(`${common$1} cursor selection ${name} is out of bounds`);
this.name = `${name}InvalidCursorSelectionOutOfBoundsError`;
}
}
class TypewriterActionUnknownCursorError extends Error {
constructor() {
super(`${common$1} action uses an unknown cursor`);
this.name = `${name}ActionUnknownCursorError`;
}
}
class Typewriter {
constructor(config = {}, subscriber) {
this.cursors = [];
this._originalCursors = [];
this.actions = [];
this.lastPerformedAction = null;
this.text = '';
this._originalText = '';
this.blinkAfter = 250;
this.isPlaying = false;
this._stopped = false;
this.isFinished = false;
this.repeat = false;
this.repeatDelay = 0;
this._repeated = 0;
this.hasBeenStoppedBefore = false;
this._index = 0;
this._animationTimeoutId = null;
this._tickStarted = new Date();
this._pauseStarted = null;
this._history = new _History();
this.history = this._history._events;
this._observer = new _Observer();
licenseChecker._checkLicense();
if (subscriber) {
this.subscribe(subscriber);
}
this.initialize(config);
}
initialize(config) {
this._clearAnimation();
this.cursors.forEach((c) => {
c._clearBlink();
});
this.actions.length = 0;
this.cursors.length = 0;
this._history._events.length = 0;
this._history._setKeepHistoryFor(config.keepHistoryFor);
this.text = config.text !== undefined ? config.text : '';
this._originalText = this.text;
const textLength = Array.from(this.text).length;
this._originalCursors.length = 0;
if (config.cursors) {
config.cursors.forEach((cursor) => {
const position = cursor.position;
if (position < 0 || position > textLength) {
throw new TypewriterCursorOutOfBoundsError();
}
const selection = cursor.selection;
if (selection) {
const { start, end } = selection;
if (position !== start && position !== end) {
throw new TypewriterCursorNotAtSelectionEdgeError();
}
if (start < 0 || start > textLength) {
throw new TypewriterCursorSelectionOutOfBoundsError(_START);
}
if (end < 0 || end > textLength) {
throw new TypewriterCursorSelectionOutOfBoundsError(_END);
}
if (start >= end) {
throw new TypewriterCursorSelectionInvalidRangeError();
}
}
this._originalCursors.push({
position: cursor.position,
data: cursor.data,
selection: selection
? {
start: selection.start,
end: selection.end,
}
: undefined,
});
this.cursors.push(new TypewriterCursor(this, cursor.position, cursor.data ? cursor.data : undefined, selection));
});
}
else {
this.cursors.push(new TypewriterCursor(this, textLength, undefined, undefined));
this._originalCursors.push({ data: undefined, position: textLength });
}
if (config.actions) {
for (let i = 0; i < config.actions.length; i++) {
const action = config.actions[i];
if (action.delay <= 0) {
throw new TypewriterDelayError();
}
if (this.cursors[action.cursor] === undefined) {
throw new TypewriterActionUnknownCursorError();
}
this.actions.push(action);
}
}
this._index = 0;
this.isPlaying =
(config.autoPlay === true || config.autoPlay === undefined) &&
this.actions.length > 0;
this.isFinished = false;
this.blinkAfter = config.blinkAfter !== undefined ? config.blinkAfter : 250;
if (this.blinkAfter <= 0) {
throw new TypewriterBlinkAfterError();
}
this._repeated = 0;
this.repeat = config.repeat !== undefined ? config.repeat : false;
if (typeof this.repeat === 'number' && this.repeat <= 0) {
throw new TypewriterRepeatError();
}
this.repeatDelay =
config.repeatDelay !== undefined ? config.repeatDelay : 0;
if (this.repeatDelay < 0) {
throw new TypewriterRepeatDelayError();
}
this.hasBeenStoppedBefore = false;
this._pauseStarted = null;
if (this.isPlaying) {
this._tick();
}
const event = {
type: 'INITIALIZED',
time: new Date(),
};
this._inform(event);
}
subscribe(subscriber) {
return this._observer._subscribe(subscriber);
}
unsubscribe(subscriber) {
this._observer._unsubscribe(subscriber);
}
unsubscribeAll() {
this._observer._clear();
}
play() {
if (this.isFinished || this._stopped) {
this._init();
this._stopped = false;
this.hasBeenStoppedBefore = false;
this._resetTandC();
}
else if (this.isPlaying || this.actions.length === 0) {
return;
}
this.isPlaying = true;
this._tick();
const event = {
type: 'PLAYING',
time: new Date(),
};
this._inform(event);
}
pause() {
if (!this.isPlaying) {
return;
}
this._clearAnimation();
this.isPlaying = false;
this._pauseStarted = new Date();
this.cursors.forEach((c) => c._startBlink());
const event = {
type: 'PAUSED',
time: new Date(),
};
this._inform(event);
}
stop() {
if (this.isFinished || (!this.isPlaying && !this._pauseStarted)) {
return;
}
this._clearAnimation();
this.isPlaying = false;
this.hasBeenStoppedBefore = true;
this._stopped = true;
this._init();
const event = {
type: 'STOPPED',
time: new Date(),
};
this._inform(event);
}
_init() {
this.isFinished = false;
this._index = 0;
this._pauseStarted = null;
this._repeated = 0;
this.cursors.forEach((c) => (c.isBlinking = true));
}
_tick() {
const action = this.actions[this._index];
const cursor = this.cursors[action.cursor];
let delay = action.delay;
if (this._pauseStarted) {
delay -= this._pauseStarted.getTime() - this._tickStarted.getTime();
this._pauseStarted = null;
}
this._tickStarted = new Date();
this._animationTimeoutId = window.setTimeout(() => {
var _a, _b;
const textArray = Array.from(this.text);
cursor.isBlinking = false;
cursor._startBlink();
let noOp = false;
if (action.type !== 'mouse') {
if (action.text === '⎚') {
if (this.text === '') {
noOp = true;
}
else {
this.text = '';
this.cursors.forEach((c) => {
c.position = 0;
c.selection = undefined;
});
}
}
else if (action.text === '←') {
noOp = this._actionLorR(cursor, -1, ((_a = cursor.selection) === null || _a === void 0 ? void 0 : _a.start) || 0, 0);
}
else if (action.text === '→') {
noOp = this._actionLorR(cursor, 1, ((_b = cursor.selection) === null || _b === void 0 ? void 0 : _b.end) || 0, textArray.length);
}
else if (action.text === '⇧←') {
noOp = this._actionSLorR(cursor, -1, _START, 0);
}
else if (action.text === '⇧→') {
noOp = this._actionSLorR(cursor, 1, _END, textArray.length);
}
else if (action.text === '⌫') {
const removed = {
start: -1,
end: -1,
no: -1,
};
if (cursor.selection) {
const start = cursor.selection.start;
const end = cursor.selection.end;
const no = end - start;
textArray.splice(cursor.selection.start, no);
this.text = textArray.join('');
removed.start = start;
removed.end = end;
removed.no = no;
}
else {
const position = cursor.position;
if (position !== 0) {
textArray.splice(position - 1, 1);
this.text = textArray.join('');
removed.start = position - 1;
removed.end = position;
removed.no = 1;
}
else {
noOp = true;
}
}
cursor.selection = undefined;
if (!noOp) {
this.cursors.forEach((c) => {
const hasOverlap = this._overlap(c.selection, removed) > 0;
if (c.position > removed.start) {
if (c.selection &&
hasOverlap &&
removed.start < c.selection.start &&
c.position < removed.end) {
c.position = removed.start;
}
else {
c.position -= removed.no;
}
}
const selection = c.selection;
if (selection) {
if (hasOverlap) {
const overlap = this._overlap(selection, removed);
if (selection.start <= removed.start) {
selection.end -= overlap;
}
else {
selection.start -= overlap;
selection.end -= removed.no;
}
if (selection.start === selection.end) {
c.selection = undefined;
}
}
else if (removed.start <= selection.start &&
removed.end <= selection.start) {
selection.start -= removed.no;
selection.end -= removed.no;
}
}
});
}
}
else {
const text = Array.from(action.text);
if (cursor.selection) {
const start = cursor.selection.start;
const end = cursor.selection.end;
const no = end - start;
textArray.splice(cursor.selection.start, no);
cursor.position = start;
const removed = {
start,
end,
no,
};
textArray.splice(cursor.position, 0, ...text);
this.text = textArray.join('');
this.cursors.forEach((c) => {
if (cursor === c) {
return;
}
const removedNo = removed.no - text.length;
const selection = c.selection;
if (selection) {
if (selection.start >= removed.start &&
selection.end <= removed.end) {
c.selection = undefined;
c.position = removed.start;
}
else {
const hasOverlap = this._overlap(selection, removed) > 0;
if (hasOverlap) {
const isPosStart = selection.start === c.position;
const overlap = this._overlap(selection, removed);
if (selection.start > removed.start) {
selection.start -= removed.no - overlap;
selection.start = Math.max(0, selection.start);
}
if (selection.end === removed.end) {
selection.end -= removed.no;
}
else if (selection.end === removed.end - 1) {
selection.end -= removed.no - 1;
}
else if (selection.end !== removed.start) {
selection.end -= removed.no - text.length;
}
c.position = isPosStart ? selection.start : selection.end;
}
else if (removed.start <= selection.start &&
removed.end <= selection.start) {
const isPosStart = selection.start === c.position;
const leftMost = Math.min(selection.start, selection.end);
if (removed.end === leftMost) {
selection.start = removed.start;
}
else {
selection.start -= removedNo;
}
selection.end -= removedNo;
selection.start = Math.max(0, selection.start);
c.position = isPosStart ? selection.start : selection.end;
}
}
}
else {
if (c.position >= removed.start && c.position <= removed.end) {
c.position = removed.start;
}
else if (c.position > removed.end) {
c.position -= removedNo;
}
}
});
cursor.position += text.length;
}
else {
textArray.splice(cursor.position, 0, ...text);
this.text = textArray.join('');
this.cursors.forEach((c) => {
if (cursor === c) {
return;
}
const selection = c.selection;
if (selection) {
if (cursor.position < selection.start) {
selection.start += text.length;
selection.end += text.length;
}
else if (cursor.position < selection.end) {
selection.end += text.length;
}
}
if (cursor.position < c.position) {
c.position += text.length;
}
});
cursor.position += text.length;
}
cursor.selection = undefined;
}
}
else {
const position = Math.min(textArray.length, Math.max(0, action.position));
if (cursor.position === position &&
this._same(cursor.selection, action.selection)) {
noOp = true;
}
else {
cursor.position = position;
if (action.selection) {
cursor.selection = {
start: action.selection.start,
end: action.selection.end,
};
}
else {
cursor.selection = undefined;
}
}
}
this._index += 1;
if (this._index >= this.actions.length) {
if (this.repeat === false || this.repeat === this._repeated + 1) {
this.isFinished = true;
this.isPlaying = false;
const event = {
type: 'FINISHED',
action,
time: new Date(),
cursor,
};
this.lastPerformedAction = action;
this._inform(event);
}
else {
this._repeated += 1;
this._change(noOp, action, cursor);
this._animationTimeoutId = window.setTimeout(() => {
this._index = 0;
this._resetTandC();
this.cursors.forEach((c) => {
c._clearBlink();
c.isBlinking = true;
});
const event = {
type: 'REPEATING',
time: new Date(),
cursor,
};
this._inform(event);
this._tick();
}, this.repeatDelay);
}
}
else {
this._change(noOp, action, cursor);
this._tick();
}
}, delay);
}
_clearAnimation() {
if (this._animationTimeoutId) {
window.clearTimeout(this._animationTimeoutId);
this._animationTimeoutId = null;
return;
}
}
_resetTandC() {
this.text = this._originalText;
this._originalCursors.forEach((copy, index) => {
const cursor = this.cursors[index];
cursor.data = copy.data ? copy.data : undefined;
cursor.position = copy.position;
const selection = copy.selection;
if (selection) {
cursor.selection = {
start: selection.start,
end: selection.end,
};
}
else {
cursor.selection = undefined;
}
});
}
_overlap(s, r) {
if (!s) {
return 0;
}
return Math.min(s.end, r.end) - Math.max(s.start, r.start);
}
_same(a, b) {
if (a === b) {
return true;
}
if (a && b) {
return a.start === b.start && a.end === b.end;
}
else {
return false;
}
}
_actionLorR(cursor, mod, select, stop) {
if (cursor.position === stop) {
if (cursor.selection === undefined) {
return true;
}
}
else {
if (cursor.selection) {
cursor.position = select;
}
else {
cursor.position += mod;
}
}
cursor.selection = undefined;
return false;
}
_actionSLorR(cursor, mod, which, stop) {
if (cursor.position === stop) {
return true;
}
else {
cursor.position += mod;
const selection = cursor.selection;
if (selection) {
selection[which] += mod;
}
else {
const selection = { start: -1, end: -1 };
selection[which === _START ? _END : _START] = cursor.position - mod;
selection[which] = cursor.position;
cursor.selection = selection;
}
}
return false;
}
_change(noOp, action, cursor) {
if (noOp) {
return;
}
const event = {
type: 'CHANGED',
action,
time: new Date(),
cursor,
};
this.lastPerformedAction = action;
this._inform(event);
}
_inform(event) {
this._history._push(event);
this._observer._inform(this, event);
}
*[Symbol.iterator]() {
const text = Array.from(this.text);
const cursorMap = {};
this.cursors.forEach((c) => {
const pos = c.position;
if (cursorMap[pos]) {
cursorMap[pos].push(c);
}
else {
cursorMap[pos] = [c];
}
});
for (let i = 0; i < text.length; i++) {
const cursors = cursorMap[i];
yield {
position: i,
cursors: cursors ? cursors : [],
character: text[i],
selected: this.cursors.filter((c) => c.selection && i >= c.selection.start && i < c.selection.end),
};
}
const finalCursors = cursorMap[text.length];
if (finalCursors) {
yield {
position: text.length,
character: '',
cursors: finalCursors,
selected: [],
};
}
}
}
const _START = 'start';
const _END = 'end';
function createTypewriterSubscriber(config) {
return (typewriter, event) => {
_callSubscriber('createTypewriterSubscriber', event, typewriter, config);
};
}
const typewriterActionTypeBackspace = '⌫';
function typewriterFromSentences(config, subscriber) {
const delay = config.delay === undefined ? 50 : config.delay;
const sentenceDelay = config.sentenceDelay === undefined ? 2000 : config.sentenceDelay;
const actions = [];
let text = config.text ? Array.from(config.text) : [];
let firstSentence = true;
for (let sentence of config.sentences) {
const sentenceArray = Array.from(sentence);
let charsInCommonFromStart = 0;
for (let i = 0; i < text.length; i++) {
const fromChar = text[i];
const toChar = sentenceArray[i];
if (toChar === fromChar) {
charsInCommonFromStart += 1;
}
else {
break;
}
}
const backspaces = text.length - charsInCommonFromStart;
text = text.slice(0, text.length - backspaces);
for (let i = 0; i < backspaces; i++) {
const actualDelay = !firstSentence && i === 0 ? sentenceDelay : delay;
actions.push({
type: _KEYBOARD,
text: typewriterActionTypeBackspace,
delay: actualDelay,
cursor: 0,
});
}
const missingChars = text.length > 0
? sentenceArray.slice(charsInCommonFromStart)
: sentenceArray;
for (const missingChar of missingChars) {
actions.push({
type: _KEYBOARD,
text: missingChar,
delay,
cursor: 0,
});
}
text = text.concat(missingChars);
firstSentence = false;
}
return new Typewriter(Object.assign(Object.assign({ repeatDelay: sentenceDelay }, config), { actions }), subscriber);
}
const _KEYBOARD = 'keyboard';
const DATE_GALLERY_MODES = [
'day',
'week',
'month',
'month-six-weeks',
'month-pad-to-week',
'year',
];
class DateGalleryDate {
constructor(dateGallery, date, events, isPadding, isSelected) {
this.canBeSelected = true;
this.dateGallery = dateGallery;
this.date = date;
this.events = events;
this.isPadding = isPadding;
this.isSelected = isSelected;
this.isToday = dateGallery._sameDay(new Date(), date);
this.hasEvents = events.length > 0;
this.hasEventsWithOverlap = this.events.some(e => e.isOverlapping);
if (dateGallery._canSelect) {
this.canBeSelected = dateGallery._canSelect(this);
}
}
select() {
this.dateGallery.selectDate(this.date);
}
deselect() {
this.dateGallery.deselectDate(this.date);
}
toggle() {
this.dateGallery.toggleDateSelection(this.date);
}
}
function _hasOverlap(a, b) {
const earlier = a.startDate < b.startDate ? a : b;
const later = earlier === a ? b : a;
const laterStart = later.startDate.getTime();
const earlierStart = earlier.startDate.getTime();
const earlierEnd = earlier.endDate.getTime();
return laterStart >= earlierStart && laterStart < earlierEnd;
}
class DateGalleryEvent {
constructor(dateGallery, data, startDate, endDate) {
this.overlappingEvents = [];
this.isOverlapping = false;
this.spansMultipleDays = false;
this.dateGallery = dateGallery;
this.data = data;
this.startDate = startDate;
this.endDate = endDate;
}
_recalculate() {
this.overlappingEvents.length = 0;
this.dateGallery.events.forEach((other) => {
if (other === this) {
return;
}
if (_hasOverlap(this, other)) {
this.overlappingEvents.push(other);
}
});
this.overlappingEvents.sort((a, b) => {
return a.startDate.getTime() - b.startDate.getTime();
});
this.spansMultipleDays = !this.dateGallery._sameDay(this.startDate, this.endDate);
this.isOverlapping = this.overlappingEvents.length > 0;
}
remove() {
this.dateGallery.removeEvent(this);
}
move(range) {
this.dateGallery.moveEvent(this, range);
}
changeData(data) {
this.dateGallery.changeEventData(this, data);
}
}
const common = `uiloos > DateGallery >`;
class DateGalleryEventInvalidRangeError extends Error {
constructor() {
super(`${common} invalid range, an events startDate lies after its endDate`);
this.name = 'DateGalleryEventInvalidRangeError';
}
}
class DateGalleryEventNotFoundError extends Error {
constructor(method) {
super(`${common} ${method} > "DateGalleryEvent" not found in events array`);
this.name = 'DateGalleryEventNotFoundError';
}
}
class DateGalleryFirstDayOfWeekError extends Error {
constructor() {
super(`${common} invalid firstDayOfWeek`);
this.name = 'DateGalleryFirstDayOfWeekError';
}
}
class DateGalleryInvalidDateError extends Error {
constructor(method, dateName) {
super(`${common} ${method} > "${dateName}" is an or contains an invalid date`);
this.name = 'DateGalleryInvalidDateError';
}
}
class DateGalleryModeError extends Error {
constructor(mode) {
super(`${common} unknown mode: "${mode}" provided`);
this.name = 'DateGalleryModeError';
}
}
class DateGalleryNumberOfFramesError extends Error {
constructor() {
super(`${common} numberOfFrames cannot be negative or zero`);
this.name = 'DateGalleryNumberOfFramesError';
}
}
class DateGallerySelectionLimitReachedError extends Error {
constructor(method) {
super(`${common} ${method} > selection limit reached`);
this.name = 'DateGallerySelectionLimitReachedError';
}
}
class DateGallery {
constructor(config = {}, subscriber) {
this._isInitializing = false;
this.isUTC = false;
this.frames = [];
this.firstFrame = {
dates: [],
events: [],
anchorDate: new Date(),
};
this.numberOfFrames = 1;
this.maxSelectionLimit = false;
this.maxSelectionLimitBehavior = 'circular';
this.selectedDates = [];
this._canSelect = undefined;
this.events = [];
this.mode = 'month-six-weeks';
this.firstDayOfWeek = 0;
this._anchorDate = new Date();
this._history = new _History();
this.history = this._history._events;
this._observer = new _Observer();
licenseChecker._checkLicense();
if (subscriber) {
this.subscribe(subscriber);
}
this._doInitialize(config, 'constructor');
}
subscribe(subscriber) {
return this._observer._subscribe(subscriber);
}
unsubscribe(subscriber) {
this._observer._unsubscribe(subscriber);
}
unsubscribeAll() {
this._observer._clear();
}
initialize(config) {
this._doInitialize(config, 'initialize');
}
_doInitialize(config, method) {
this._isInitializing = true;
this.isUTC = config.isUTC !== undefined ? config.isUTC : false;
this.mode = config.mode ? config.mode : 'month-six-weeks';
this._checkMode(this.mode);
this.firstDayOfWeek = config.firstDayOfWeek ? config.firstDayOfWeek : 0;
if (this.firstDayOfWeek < 0 || this.firstDayOfWeek > 6) {
throw new DateGalleryFirstDayOfWeekError();
}
this.numberOfFrames =
config.numberOfFrames !== undefined ? config.numberOfFrames : 1;
if (this.numberOfFrames <= 0) {
throw new DateGalleryNumberOfFramesError();
}
this.maxSelectionLimit =
config.maxSelectionLimit !== undefined ? config.maxSelectionLimit : false;
this.maxSelectionLimitBehavior =
config.maxSelectionLimitBehavior !== undefined
? config.maxSelectionLimitBehavior
: 'circular';
this._anchorDate = config.initialDate
? this._toDate(config.initialDate, method, 'initialDate')
: new Date();
this._toMidnight(this._anchorDate);
this._dragAnchor();
this.events.length = 0;
this.selectedDates.length = 0;
this._canSelect = config.canSelect;
if (config.selectedDates) {
config.selectedDates.forEach((s) => {
this.selectDate(this._toDate(s, method, 'selectedDates'));
});
}
if (config.events) {
config.events.forEach((config) => {
this._doAddEvent(config, method);
});
this.events.forEach((e) => {
e._recalculate();
});
}
this._buildFrames();
this._history._events.length = 0;
this._history._setKeepHistoryFor(config.keepHistoryFor);
this._isInitializing = false;
const event = {
type: 'INITIALIZED',
time: new Date(),
};
this._inform(event);
}
changeConfig(config) {
if (config.initialDate === undefined &&
config.mode === undefined &&
config.numberOfFrames === undefined) {
return;
}
let changed = false;
let drag = false;
const method = 'changeConfig';
if (config.mode !== undefined) {
this._checkMode(config.mode);
if (this.mode !== config.mode) {
this.mode = config.mode;
changed = true;
drag = true;
}
}
if (config.initialDate !== undefined) {
const date = this._toDate(config.initialDate, method, 'initialDate');
this._toMidnight(date);
if (!this._sameDay(date, this._anchorDate)) {
this._anchorDate = date;
changed = true;
drag = true;
}
}
if (config.numberOfFrames !== undefined) {
if (config.numberOfFrames <= 0) {
throw new DateGalleryNumberOfFramesError();
}
if (this.numberOfFrames !== config.numberOfFrames) {
this.numberOfFrames = config.numberOfFrames;
changed = true;
}
}
if (changed) {
if (drag) {
this._dragAnchor();
}
this._buildFrames();
const event = {
type: 'CONFIG_CHANGED',
mode: this.mode,
anchorDate: new Date(this._anchorDate),
numberOfFrames: this.numberOfFrames,
frames: this.frames,
time: new Date(),
};
this._inform(event);
}
}
today() {
this.changeConfig({
initialDate: new Date(),
});
}
_buildFrames(inform = false) {
this.frames.length = 0;
const anchorAtStart = this._anchorDate;
for (let i = 0; i < this.numberOfFrames; i++) {
if (i !== 0) {
this._moveFrame(1);
}
const frame = {
dates: [],
events: [],
anchorDate: new Date(this._anchorDate),
};
const anchor = new Date(this._anchorDate);
if (this.mode === 'day') {
frame.dates.push(this._makeDate(anchor));
}
else if (this.mode === 'week') {
this._addNoDates(anchor, 7, frame);
}
else if (this.mode === 'year') {
const year = this._getFullYear(anchor);
const isLeapYear = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
this._addNoDates(anchor, isLeapYear ? 366 : 365, frame);
}
else if (this.mode === 'month') {
const anchorMonth = this._getMonth(anchor);
this._addMonth(anchor, anchorMonth, frame);
}
else if (this.mode === 'month-pad-to-week') {
const date = this._firstDayOfWeek(anchor);
const anchorMonth = this._getMonth(anchor);
while (this._getMonth(date) !== anchorMonth) {
this._pushDay(date, frame);
}
this._addMonth(date, anchorMonth, frame);
while (this._getDay(date) !== this.firstDayOfWeek) {
this._pushDay(date, frame);
}
}
else if (this.mode === 'month-six-weeks') {
const date = this._firstDayOfWeek(anchor);
this._addNoDates(date, 42, frame);
}
this.frames.push(frame);
const startDate = new Date(frame.dates[0].date);
const endDate = new Date(frame.dates[frame.dates.length - 1].date);
this._toMidnight(startDate);
this._moveDateBy(endDate, 1);
this._toMidnight(endDate);
this.events.forEach((event) => {
if (_hasOverlap({ startDate, endDate }, event)) {
frame.events.push(event);
}
});
}
this._anchorDate = anchorAtStart;
this.firstFrame = this.frames[0];
if (inform) {
const event = {
type: 'FRAME_CHANGED',
frames: this.frames,
time: new Date(),
};
this._inform(event);
}
}
next() {
this._moveFrame(this.numberOfFrames);
this._buildFrames(true);
}
previous() {
this._moveFrame(-this.numberOfFrames);
this._buildFrames(true);
}
_moveFrame(mod) {
const date = new Date(this._anchorDate);
if (this.mode === 'day') {
this._moveDateBy(date, 1 * mod);
}
else if (this.mode === 'week') {
this._moveDateBy(date, 7 * mod);
}
else if (this.mode === 'year') {
if (this.isUTC) {
date.setUTCFullYear(date.getUTCFullYear() + 1 * mod);
}
else {
date.setFullYear(date.getFullYear() + 1 * mod);
}
}
else {
if (this.isUTC) {
date.setUTCMonth(date.getUTCMonth() + 1 * mod);
}
else {
date.setMonth(date.getMonth() + 1 * mod);
}
}
this._anchorDate = date;
}
selectDate(date) {
const method = 'selectDate';
const _date = this._toDate(date, method, 'date');
const [index] = this._indexOfDate(_date, method);
if (index === -1) {
this._doSelectDate(_date, method);
}
}
_doSelectDate(date, method) {
const deselectedDates = [];
const midnight = this._pushSelectDate(date, method, deselectedDates);
if (!midnight) {
return;
}
this._buildFrames();
let deselectedDate = deselectedDates[0];
if (!deselectedDate) {
deselectedDate = null;
}
const event = {
type: 'DATE_SELECTED',
date: new Date(midnight),
deselectedDate,
time: new Date(),
};
this._inform(event);
}
_pushSelectDate(date, method, deselectedDates) {
const midnight = this._toDate(date, method, 'date');
this._toMidnight(midnight);
if (this._canSelect && !this._canSelect(this._makeDate(midnight))) {
return null;
}
const limitReached = this.maxSelectionLimit === false
? false
: this.maxSelectionLimit === this.selectedDates.length;
if (limitReached) {
if (this.maxSelectionLimitBehavior === 'error') {
throw new DateGallerySelectionLimitReachedError(method);
}
else if (this.maxSelectionLimitBehavior === 'ignore') {
return null;
}
else {
const deselected = this.selectedDates.shift();
if (deselected) {
deselectedDates.push(deselected);
}
}
}
this.selectedDates.push(midnight);
return midnight;
}
deselectDate(date) {
const [index, _date] = this._indexOfDate(date, 'deselectDate');
if (index === -1) {
return;
}
this._doDeselectDate(index, _date);
}
_doDeselectDate(index, date) {
this.selectedDates.splice(index, 1);
this._buildFrames();
const event = {
type: 'DATE_DESELECTED',
date,
time: new Date(),
};
this._inform(event);
}
toggleDateSelection(date) {
const [index, _date] = this._indexOfDate(date, 'toggleDateSelection');
if (index === -1) {
this._doSelectDate(_date, 'toggleDateSelection');
}
else {
this._doDeselectDate(index, _date);
}
}
_indexOfDate(date, method) {
const _date = this._toDate(date, method, 'date');
const index = this.selectedDates.findIndex((s) => {
return this._sameDay(s, _date);
});
return [index, _date];
}
deselectAll() {
if (this.selectedDates.length === 0) {
return;
}
const dates = [...this.selectedDates];
this.selectedDates.length = 0;
this._buildFrames();
const e = {
type: 'DATE_DESELECTED_MULTIPLE',
dates,
time: new Date(),
};
this._inform(e);
}
selectRange(a, b) {
const method = 'selectRange';
const aDate = this._toDate(a, method, 'a');
const bDate = this._toDate(b, method, 'b');
const startDate = bDate.getTime() > aDate.getTime() ? aDate : bDate;
const endDate = aDate === startDate ? bDate : aDate;
this._toMidnight(startDate);
this._moveDateBy(endDate, 1);
this._toMidnight(endDate);
const date = new Date(startDate);
const oldSelected = [...this.selectedDates];
const selectedCollector = [];
const deselectedCollector = [];
let error = null;
try {
while (!this._sameDay(date, endDate)) {
const index = this.selectedDates.findIndex((s) => {
return this._sameDay(s, date);
});
if (index === -1) {
const midnight = this._pushSelectDate(date, method, deselectedCollector);
if (midnight) {
selectedCollector.push(midnight);
}
}
this._moveDateBy(date, 1);
}
}
catch (e) {
if (e instanceof DateGallerySelectionLimitReachedError) {
error = e;
}
}
const reportedSelectedDates = selectedCollector.filter((selectedDate) => !deselectedCollector.includes(selectedDate));
if (reportedSelectedDates.length === 0) {
if (error) {
throw error;
}
return;
}
const deselectedDates = oldSelected.filter((oldSelect) => !this.selectedDates.some((selectedDate) => this._sameDay(oldSelect, selectedDate)));
this._buildFrames();
const event = {
type: 'DATE_SELECTED_MULTIPLE',
dates: reportedSelectedDates.map((d) => new Date(d)),
deselectedDates: deselectedDates.map((d) => new Date(d)),
time: new Date(),
};
this._inform(event);
if (error) {
throw error;
}
}
addEvent(event) {
const addedEvent = this._doAddEvent(event, 'addEvent');
this.events.forEach((e) => {
e._recalculate();
});
this._buildFrames();
const e = {
type: 'EVENT_ADDED',
event: addedEvent,
time: new Date(),
};
this._inform(e);
return addedEvent;
}
_doAddEvent(config, method) {
const startDate = this._toDate(config.startDate, method, 'event.startDate');
const endDate = this._toDate(config.endDate, method, 'event.endDate');
if (startDate.getTime() > endDate.getTime()) {
throw new DateGalleryEventInvalidRangeError();
}
const event = new DateGalleryEvent(this, config.data, startDate, endDate);
this.events.push(event);
this.events.sort((a, b) => {
return a.startDate.getTime() - b.startDate.getTime();
});
return event;
}
removeEvent(event) {
const index = this.events.indexOf(event);
if (index === -1) {
return event;
}
this.events.splice(index, 1);
this.events.forEach((e) => {
e._recalculate();
});
this._buildFrames();
const e = {
type: 'EVENT_REMOVED',
event,
time: new Date(),
};
this._inform(e);
return event;
}
moveEvent(event, range) {
const startDate = this._toDate(range.startDate, 'moveEvent', 'range.startDate');
const endDate = this._toDate(range.endDate, 'moveEvent', 'range.endDate');
if (startDate.getTime() > endDate.getTime()) {
throw new DateGalleryEventInvalidRangeError();
}
if (startDate.getTime() === event.startDate.getTime() &&
endDate.getTime() === event.endDate.getTime()) {
return;
}
const index = this.events.indexOf(event);
if (index === -1) {
throw new DateGalleryEventNotFoundError('moveEvent');
}
event.startDate = startDate;
event.endDate = endDate;
this.events.sort((a, b) => {
return a.startDate.getTime() - b.startDate.getTime();
});
this.events.forEach((e) => {
e._recalculate();
});
this._buildFrames();
const e = {
type: 'EVENT_MOVED',
event,
time: new Date(),
};
this._inform(e);
}
changeEventData(event, data) {
const index = this.events.indexOf(event);
if (index === -1) {
throw new DateGalleryEventNotFoundError('changeEventData');
}
event.data = data;
const e = {
type: 'EVENT_DATA_CHANGED',
event,
data,
time: new Date(),
};
this._inform(e);
}
_dragAnchor() {
if (this.mode === 'year') {
if (this.isUTC) {
this._anchorDate.setUTCDate(1);
this._anchorDate.setUTCMonth(0);
}
else {
this._anchorDate.setDate(1);
this._anchorDate.setMonth(0);
}
}
else if (this.mode === 'week') {
this._anchorDate = this._firstDayOfWeek(this._anchorDate);
}
else if (this.mode.startsWith('month')) {
if (this.isUTC) {
this._anchorDate.setUTCDate(1);
}
else {
this._anchorDate.setDate(1);
}
}
}
_inform(event) {
if (this._isInitializing) {
return;
}
this._history._push(event);
this._observer._inform(this, event);
}
_toDate(date, method, dateName) {
if (date instanceof Date) {
this._checkDate(date, method, dateName);
}
const result = new Date(date);
this._checkDate(result, method, dateName);
return result;
}
_checkDate(date, method, dateName) {
const isValid = Object.prototype.toString.call(date) === '[object Date]' &&
!isNaN(date.valueOf());
if (!isValid) {
throw new DateGalleryInvalidDateError(method, dateName);
}
}
_firstDayOfWeek(date) {
const copy = new Date(date);
while (this._getDay(copy) !== this.firstDayOfWeek) {
this._moveDateBy(copy, -1);
}
return copy;
}
_addNoDates(date, amount, frame) {
for (let i = 0; i < amount; i++) {
this._pushDay(date, frame);
}
}
_addMonth(date, month, frame) {
while (this._getMonth(date) === month) {
this._pushDay(date, frame);
}
}
_pushDay(date, frame) {
frame.dates.push(this._makeDate(date));
this._moveDateBy(date, 1);
}
_makeDate(date) {
const _date = new Date(date);
this._toMidnight(_date);
let isPadding = false;
if (this.mode === 'month-pad-to-week' || this.mode === 'month-six-weeks') {
const anchorMonth = this._getMonth(this._anchorDate);
isPadding = this._getMonth(_date) !== anchorMonth;
}
return new DateGalleryDate(this, _date, this.events.filter((event) => {
const time = _date.getTime();
const startDate = new Date(event.startDate);
const start = this._toMidnight(startDate);
const endDate = new Date(event.endDate);
this._moveDateBy(endDate, 1);
const end = this._toMidnight(endDate);
return time >= start && time < end;
}), isPadding, this.selectedDates.some((selected) => {
return this._sameDay(selected, _date);
}));
}
isSameDay(a, b) {
const method = 'isSameDay';
return this._sameDay(this._toDate(a, method, 'a'), this._toDate(b, method, 'b'));
}
_sameDay(a, b) {
return (this._getFullYear(a) === this._getFullYear(b) &&
this._getMonth(a) === this._getMonth(b) &&
this._getDate(a) === this._getDate(b));
}
_getFullYear(date) {
return this.isUTC ? date.getUTCFullYear() : date.getFullYear();
}
_getMonth(date) {
return this.isUTC ? date.getUTCMonth() : date.getMonth();
}
_getDate(date) {
return this.isUTC ? date.getUTCDate() : date.getDate();
}
_getDay(date) {
return this.isUTC ? date.getUTCDay() : date.getDay();
}
_checkMode(mode) {
if (!DATE_GALLERY_MODES.includes(mode)) {
throw new DateGalleryModeError(mode);
}
}
_toMidnight(date) {
if (this.isUTC) {
return date.setUTCHours(0, 0, 0, 0);
}
else {
return date.setHours(0, 0, 0, 0);
}
}
_moveDateBy(date, mod) {
if (this.isUTC) {
date.setUTCDate(date.getUTCDate() + mod);
}
else {
date.setDate(date.getDate() + mod);
}
}
}
function createDateGallerySubscriber(config) {
return (activeList, event) => {
_callSubscriber('createDateGallerySubscriber', event, activeList, config);
};
}
export { ActiveList, ActiveListActivationLimitReachedError, ActiveListAutoPlayDurationError, ActiveListContent, ActiveListCooldownDurationError, ActiveListIndexOutOfBoundsError, ActiveListItemNotFoundError, DATE_GALLERY_MODES, DateGallery, DateGalleryDate, DateGalleryEvent, DateGalleryEventInvalidRangeError, DateGalleryEventNotFoundError, DateGalleryFirstDayOfWeekError, DateGalleryInvalidDateError, DateGalleryModeError, DateGalleryNumberOfFramesError, DateGallerySelectionLimitReachedError, Typewriter, TypewriterActionUnknownCursorError, TypewriterBlinkAfterError, TypewriterCursor, TypewriterCursorNotAtSelectionEdgeError, TypewriterCursorOutOfBoundsError, TypewriterCursorSelectionInvalidRangeError, TypewriterCursorSelectionOutOfBoundsError, TypewriterDelayError, TypewriterRepeatDelayError, TypewriterRepeatError, ViewChannel, ViewChannelAutoDismissDurationError, ViewChannelIndexOutOfBoundsError, ViewChannelView, ViewChannelViewNotFoundError, _LicenseChecker, createActiveListSubscriber, createDateGallerySubscriber, createTypewriterSubscriber, createViewChannelSubscriber, licenseChecker, typewriterFromSentences };
//# sourceMappingURL=index.js.map