@js-toolkit/web-utils 1.53.0 → 1.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,4 +3,7 @@ declare global {
3
3
  userLanguage: string;
4
4
  }
5
5
  }
6
- export declare function getBrowserLanguage(): string | undefined;
6
+ /**
7
+ * @param includeRegion subtag separated by `-`.
8
+ */
9
+ export declare function getBrowserLanguage(includeRegion?: boolean): string;
@@ -1 +1 @@
1
- export function getBrowserLanguage(){if("undefined"!=typeof window&&"navigator"in window){return(navigator.languages&&navigator.languages.length>0?navigator.languages[0]:navigator.language||navigator.userLanguage).split("-")[0]}}
1
+ export function getBrowserLanguage(a=!1){const g=navigator.languages&&navigator.languages.length>0?navigator.languages[0]:navigator.language||navigator.userLanguage;return a?g:g.split("-")[0]}
@@ -1 +1 @@
1
- import{v4 as uuid}from"uuid";import{IFRAME_CLIENT_READY,IFRAME_HOST_READY,IFRAME_PING,isPingMessage,isTargetReadyMessage}from"./messages";import{getOriginFromMessage}from"./getOriginFromMessage";import{isWindowProxy}from"./utils";export function getAutoConnectClient({data:e,target:s=window.parent,isReady:o=(()=>!0),onConnect:a,logger:t=console,messagesTypes:i}){const n={Ping:(null==i?void 0:i.Ping)||IFRAME_PING,TargetReady:(null==i?void 0:i.TargetReady)||IFRAME_HOST_READY,SelfReady:(null==i?void 0:i.SelfReady)||IFRAME_CLIENT_READY},r=uuid();let g;const d=(e,s,o)=>{window!==e&&(isWindowProxy(e)?(e.postMessage(s,o),t.debug(`Post message to parent window (origin=${o}):`,s)):(e.postMessage(s),t.debug("Post message to parent MessageEventSource:",s)))},u=i=>{if(!i.source||i.source!==s)return;if(!isPingMessage(i.data,n)&&!isTargetReadyMessage(i.data,n))return;t.debug(`Receive message from parent window (origin=${i.origin}):`,i.data);const u=getOriginFromMessage(i);if(isPingMessage(i.data,n))((e,s,a)=>{o()&&d(e,{uid:r,type:n.SelfReady,data:s},a)})(i.source,e,u);else{m();const{data:e}=i.data;[g]=i.ports,a(e,u,g),t.debug("Iframe connected.")}},m=()=>{window.removeEventListener("message",u)};return window.addEventListener("message",u),{ready:(e="*")=>{d(s,{uid:r,type:n.Ping},e)},destroy:()=>{m(),g&&(g.close(),g.onmessage=null,g.onmessageerror=null)}}}
1
+ import{v4 as uuid}from"uuid";import{IFRAME_CLIENT_READY,IFRAME_HOST_READY,IFRAME_PING,isPingMessage,isTargetReadyMessage}from"./messages";import{getOriginFromMessage}from"./getOriginFromMessage";import{isWindowProxy}from"./utils";export function getAutoConnectClient({data:e,target:s=window.parent,isReady:o=()=>!0,onConnect:a,logger:t=console,messagesTypes:i}){const n={Ping:(null==i?void 0:i.Ping)||IFRAME_PING,TargetReady:(null==i?void 0:i.TargetReady)||IFRAME_HOST_READY,SelfReady:(null==i?void 0:i.SelfReady)||IFRAME_CLIENT_READY},r=uuid();let g;const d=(e,s,o)=>{window!==e&&(isWindowProxy(e)?(e.postMessage(s,o),t.debug(`Post message to parent window (origin=${o}):`,s)):(e.postMessage(s),t.debug("Post message to parent MessageEventSource:",s)))},u=i=>{if(!i.source||i.source!==s)return;if(!isPingMessage(i.data,n)&&!isTargetReadyMessage(i.data,n))return;t.debug(`Receive message from parent window (origin=${i.origin}):`,i.data);const u=getOriginFromMessage(i);if(isPingMessage(i.data,n))((e,s,a)=>{o()&&d(e,{uid:r,type:n.SelfReady,data:s},a)})(i.source,e,u);else{m();const{data:e}=i.data;[g]=i.ports,a(e,u,g),t.debug("Iframe connected.")}},m=()=>{window.removeEventListener("message",u)};return window.addEventListener("message",u),{ready:(e="*")=>{d(s,{uid:r,type:n.Ping},e)},destroy:()=>{m(),g&&(g.close(),g.onmessage=null,g.onmessageerror=null)}}}
@@ -1,10 +1,16 @@
1
1
  import { type MessagesTypes } from './messages';
2
2
  import { type Target } from './utils';
3
3
  export { getClientMessages, getHostMessages } from './messages';
4
+ interface StartOptions {
5
+ readonly append?: boolean;
6
+ }
4
7
  interface AutoConnector {
5
8
  /** If function passed the connector waits until DOM ready. */
6
- readonly start: (targets: ArrayLike<Target> | (() => ArrayLike<Target>)) => void;
9
+ readonly start: (targets: ArrayLike<Target> | (() => ArrayLike<Target>), options?: StartOptions) => void;
10
+ /** Stops a receiving new connections. */
7
11
  readonly stop: VoidFunction;
12
+ readonly isStarted: () => boolean;
13
+ readonly close: (targets: ArrayLike<Target>) => void;
8
14
  readonly destroy: VoidFunction;
9
15
  }
10
16
  interface TargetInfo {
@@ -1 +1 @@
1
- import{v4 as uuid}from"uuid";import{onDOMReady}from"../onDOMReady";import{isPingMessage,isTargetReadyMessage}from"./messages";import{findTarget,isWindowProxy}from"./utils";import{getOriginFromMessage}from"./getOriginFromMessage";export{getClientMessages,getHostMessages}from"./messages";export function getAutoConnector({id:e,label:t,strictTargets:o=!0,messagesTypes:n,channel:s,logger:i=console,onSendData:a,onConnect:r}){const d=e||uuid(),g=t||d,u=new Map,c="open"===s?new Map:void 0;let l,f;const m=(e,t,o,n,s)=>{window!==t&&(isWindowProxy(t)?(t.postMessage(e,o,s),i.debug(`${g}: Post message to iframe (uid=${n},origin=${o}):`,e)):(t.postMessage(e,s&&{transfer:s}),i.debug(`${g}: Post message to MessageEventSource (uid=${n}):`,e)))},p=(e,t,o)=>{m({uid:d,type:n.Ping},e,t,o)},v=e=>{var t,f,v,w;if(!e.source||e.source===window)return;if(!isPingMessage(e.data,n)&&!isTargetReadyMessage(e.data,n))return;if(e.data.uid===d)return;const M=e.source,h=e.data.uid;if(i.debug(`${g}: Receive message from iframe (uid=${h},origin=${e.origin}):`,e.data),o&&l){if(!findTarget(M,l))return void i.warn(`${g}: Could not find target (uid=${h}) by message.source.`)}const y=getOriginFromMessage(e);if(isPingMessage(e.data,n)&&!(null===(t=u.get(h))||void 0===t?void 0:t.Ping))return u.set(h,Object.assign(Object.assign({},u.get(h)),{Ping:!0})),void p(M,y,h);let $=!1;if((null===(f=u.get(h))||void 0===f?void 0:f.Ping)&&!(null===(v=u.get(h))||void 0===v?void 0:v.SelfReady)){u.set(h,Object.assign(Object.assign({},u.get(h)),{SelfReady:!0}));const e=c?(()=>{var e;const t=null!==(e=c.get(h))&&void 0!==e?e:new MessageChannel;return c.set(h,t),t.port2})():void 0;((e,t,o,s,i)=>{m({uid:d,type:n.SelfReady,data:e},t,o,s,i?[i]:void 0)})(a?a({target:M,origin:y}):void 0,M,y,h,e),$=!1}if(isTargetReadyMessage(e.data,n)&&(null===(w=u.get(h))||void 0===w?void 0:w.SelfReady)){u.delete(h);const t=(()=>{var t;if("open"===s){const e=null===(t=null==c?void 0:c.get(h))||void 0===t?void 0:t.port1;if(!e)throw new Error("Something went wrong: MessageChannel is not created despite the fact that the `channel` option is `open`.");return e}if("use"===s){const t=e.ports[0];if(!t)throw new Error("MessagePort is not received despite the fact that the `channel` option is `use`. The `channel` option of connector on another side must be equals `open`.");return t}})(),{data:o}=e.data,n=()=>{i.debug(`${g}: Iframe connection established (${d} + ${h}).`),r({data:o,target:M,origin:y},t)};$?setTimeout(n,0):n()}},w=()=>{f&&(f(),f=void 0)};return{start:e=>{if(f)return void i.warn(`${g}: Already started. You should first call \`stop\`.`);const t=()=>{l=(()=>{const t="function"==typeof e?e():e;return t.length>0?t:void 0})(),window.addEventListener("message",v);const t=null!=l?l:[];for(let e=0;e<t.length;e+=1){const o=t[e],n=o instanceof HTMLIFrameElement?o.contentWindow:o;n&&n!==window&&p(n,"*","")}},o="function"==typeof e?onDOMReady(t):t();f=()=>{o&&o(),window.removeEventListener("message",v),l=void 0}},stop:w,destroy:()=>{w(),u.clear(),c&&(c.forEach((e=>{e.port1.close(),e.port2.close()})),c.clear())}}}
1
+ import{v4 as uuid}from"uuid";import{onDOMReady}from"../onDOMReady";import{isPingMessage,isTargetReadyMessage}from"./messages";import{isWindowProxy,readTargets}from"./utils";import{getOriginFromMessage}from"./getOriginFromMessage";export{getClientMessages,getHostMessages}from"./messages";export function getAutoConnector({id:e,label:t,strictTargets:o=!0,messagesTypes:s,channel:n,logger:i=console,onSendData:a,onConnect:r}){const d=e||uuid(),g=t||d,u=new Map,l="open"===n?new Map:void 0;let c,f;const p=(e,t,o,s,n)=>{if(window!==t)if(isWindowProxy(t)){t.postMessage(e,o,n);const a=t===window.parent?"iframe parent":"iframe";i.debug(`${g}: Post message to ${a} (uid=${s},self.uid=${d},origin=${o}):`,e)}else t.postMessage(e,n&&{transfer:n}),i.debug(`${g}: Post message to MessageEventSource (uid=${s},self.uid=${d}):`,e)},v=(e,t,o)=>{p({uid:d,type:s.Ping},e,t,o)},m=e=>{var t,f,m,w;if(!e.source||e.source===window)return;if(!isPingMessage(e.data,s)&&!isTargetReadyMessage(e.data,s))return;if(e.data.uid===d)return;const h=e.source,M=e.data.uid;if(i.debug(`${g}: Receive message from iframe (uid=${M},self.uid=${d},origin=${e.origin}):`,e.data),o&&c&&!c.has(h))return void i.warn(`${g}: Could not find target (uid=${M},self.uid=${d}) by message.source.`);const y=getOriginFromMessage(e);if(isPingMessage(e.data,s)&&!(null===(t=u.get(M))||void 0===t?void 0:t.Ping))return u.set(M,Object.assign(Object.assign({},u.get(M)),{Ping:!0})),void v(h,y,M);let $=!1;if((null===(f=u.get(M))||void 0===f?void 0:f.Ping)&&!(null===(m=u.get(M))||void 0===m?void 0:m.SelfReady)){u.set(M,Object.assign(Object.assign({},u.get(M)),{SelfReady:!0}));const e={target:h,origin:y},t=l?(()=>{var t,o;const s=null!==(o=null===(t=l.get(M))||void 0===t?void 0:t[0])&&void 0!==o?o:new MessageChannel;return l.set(M,[s,e]),s.port2})():void 0;((e,t,o,n,i)=>{p({uid:d,type:s.SelfReady,data:e},t,o,n,i?[i]:void 0)})(a?a(e):void 0,h,y,M,t),$=!1}if(isTargetReadyMessage(e.data,s)&&(null===(w=u.get(M))||void 0===w?void 0:w.SelfReady)){u.delete(M),null==c||c.delete(h);const t=(()=>{var t;if("open"===n){const e=null===(t=null==l?void 0:l.get(M))||void 0===t?void 0:t[0].port1;if(!e)throw new Error("Something went wrong: MessageChannel is not created despite the fact that the `channel` option is `open`.");return e}if("use"===n){const t=e.ports[0];if(!t)throw new Error("MessagePort is not received despite the fact that the `channel` option is `use`. The `channel` option of connector on another side must be equals `open`.");return t}})(),{data:o}=e.data,s=()=>{i.debug(`${g}: Connection established (self.uid=${d} + uid=${M}).`),r({data:o,target:h,origin:y},t)};$?setTimeout(s,0):s()}},w=()=>{f&&(f(),f=void 0)};return{start:(e,t={})=>{if(f&&!t.append)return void i.warn(`${g}: Already started. You should first call \`stop\`.`);if(t.append){const e=c;w(),c=e}const o=()=>{const o=(()=>{const t="function"==typeof e?e():e;return t.length>0?t:void 0})(),s=o&&readTargets(o);if(!s)return;const n=new Set(s);t.append?(c||(c=new Set),n.forEach((e=>c.add(e)))):c=n,window.addEventListener("message",m);(t.append?n:c).forEach((e=>{e!==window&&v(e,"*","")}))},s="function"==typeof e?onDOMReady(o):o();f=()=>{s&&s(),window.removeEventListener("message",m),c=void 0}},stop:w,isStarted:()=>!!f,close:e=>{const t=e instanceof Set?e:new Set(readTargets(e));if(0!==t.size&&(l&&l.forEach((([e,o],s)=>{t.has(o.target)&&(e.port1.close(),e.port2.close(),l.delete(s))})),c)){const e=c;t.forEach((t=>e.delete(t)))}},destroy:()=>{w(),u.clear(),l&&(l.forEach((([e])=>{e.port1.close(),e.port2.close()})),l.clear())}}}
package/iframe/utils.d.ts CHANGED
@@ -2,3 +2,4 @@ export type Target = HTMLIFrameElement | Window;
2
2
  export declare function selectFrames(): HTMLCollectionOf<HTMLIFrameElement>;
3
3
  export declare function findTarget<T extends Target>(source: Window, targets: ArrayLike<T>): T | undefined;
4
4
  export declare function isWindowProxy(target: MessageEventSource): target is Window;
5
+ export declare function readTargets(list: ArrayLike<Target>): Window[];
package/iframe/utils.js CHANGED
@@ -1 +1 @@
1
- export function selectFrames(){return document.getElementsByTagName("iframe")}export function findTarget(e,n){for(let t=0;t<n.length;t+=1){const o=n[t];if((o instanceof HTMLIFrameElement?o.contentWindow:o)===e)return o}}export function isWindowProxy(e){return!(void 0!==window.MessagePort&&e instanceof MessagePort||void 0!==window.ServiceWorker&&e instanceof ServiceWorker)}
1
+ export function selectFrames(){return document.getElementsByTagName("iframe")}export function findTarget(e,n){for(let t=0;t<n.length;t+=1){const o=n[t];if((o instanceof HTMLIFrameElement?o.contentWindow:o)===e)return o}}export function isWindowProxy(e){return!(void 0!==window.MessagePort&&e instanceof MessagePort||void 0!==window.ServiceWorker&&e instanceof ServiceWorker)}export function readTargets(e){const n=new Array;for(let t=0;t<e.length;t+=1){const o=e[t],r=o instanceof HTMLIFrameElement?o.contentWindow:o;r&&n.push(r)}return n}
@@ -24,21 +24,25 @@ export declare class TextTracksController extends EventEmitter<TextTracksControl
24
24
  private nextTextTrack;
25
25
  get Events(): typeof TextTracksController.Events;
26
26
  constructor(options?: TextTracksController.Options | undefined);
27
+ setOptions(options: Partial<TextTracksController.Options>): void;
27
28
  isAttached(): boolean;
28
29
  getMediaElement(): HTMLMediaElement;
29
30
  detach(): void;
30
31
  attach(media: HTMLMediaElement): void;
32
+ getTextTracks(): readonly TextTrackInfo[];
31
33
  setTextTracks(textTrackList: readonly TextTrackItem[]): void;
32
34
  getActiveTextTrack(): TextTrackInfo | undefined;
33
- setActiveTextTrack(tt: ActivateTextTrackInfo | undefined): void;
35
+ setActiveTextTrack(tt: ActivateTextTrackInfo | undefined): boolean;
34
36
  destroy(): void;
35
37
  }
36
38
  export declare namespace TextTracksController {
37
39
  interface Options {
38
- /** Default `true`. */
40
+ /** Defaults to `false`. */
39
41
  readonly emitNativeEvents?: boolean | undefined;
40
- /** Default `true`. */
42
+ /** Defaults to `true`. */
41
43
  readonly hideActiveTrack?: boolean | undefined;
44
+ /** */
45
+ readonly preferCueRowLength?: number | undefined;
42
46
  }
43
47
  enum Events {
44
48
  TextTrackListChanged = "TrackListChanged",
@@ -1 +1 @@
1
- import{EventEmitter}from"eventemitter3";import{EventListeners}from"../../EventListeners";import{MediaNotAttachedError}from"../MediaNotAttachedError";import{parseTextTracks,setActiveTextTrack,addTextTracks,isIOSFullscreen,splitRows,buildCueId}from"./utils";function dispatchNativeEvent(t,e,i){t.dispatchEvent(new CustomEvent(e,{detail:i}))}export class TextTracksController extends EventEmitter{get Events(){return TextTracksController.Events}constructor(t){var e,i;super(),this.eventListeners=new EventListeners,this.addedTracks=[],this.textTrackList=[],this.options=Object.assign(Object.assign({},t),{emitNativeEvents:null===(e=null==t?void 0:t.emitNativeEvents)||void 0===e||e,hideActiveTrack:null===(i=null==t?void 0:t.hideActiveTrack)||void 0===i||i})}isAttached(){return!!this.media}getMediaElement(){if(!this.media)throw new MediaNotAttachedError;return this.media}detach(){this.eventListeners.removeAllListeners(),this.media=void 0,this.addedTracks=[],this.textTrackList=[],this.textTrack=void 0,this.nextTextTrack=void 0}attach(t){this.detach(),this.media=t;const{textTracks:e}=t;let i=!1;const s=(()=>{const e=[];return i=>{var s;const{activeCues:n}=i.target;if(!n)return;let a=e.length!==n.length;const r=new Array(n.length);for(let t=0;t<r.length;t+=1){const i=n[t];i.id=i.id||buildCueId(i,t),r[t]=i,r[t].rows=splitRows(i.text),a||(null===(s=e[t])||void 0===s?void 0:s.id)===i.id||(a=!0),e[t]=i}e.length>r.length&&e.splice(r.length-e.length),a&&(this.emit(this.Events.TextTrackCueChanged,{textTrack:i.target,cues:r}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttrackcuechange",{textTrack:i.target,cues:r}))}})(),n=()=>{var e;this.textTrackList=parseTextTracks(t),this.emit(this.Events.TextTrackListChanged,{textTracks:this.textTrackList}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttracklistchange",{textTracks:this.textTrackList}),setActiveTextTrack(t,null!==(e=this.textTrack)&&void 0!==e?e:this.nextTextTrack,this.options.hideActiveTrack||isIOSFullscreen(t))},a=t=>{i||n(),this.eventListeners.scope(t).on("cuechange",s)},r=t=>{n(),this.eventListeners.scope(t).off("cuechange",s)};if(this.eventListeners.scope(e).on("change",(()=>{var e,i,s;const{textTracks:n}=t,{nextTextTrack:a}=this;let r=-1;for(let e=0;e<n.length;e+=1){const i=n[e];if(i.language===(null==a?void 0:a.language)&&i.kind===(null==a?void 0:a.kind)||isIOSFullscreen(t)||(i.mode="disabled"),"disabled"!==i.mode&&r>=0&&(i.mode="disabled"),"disabled"!==i.mode){if(r=e,!i.native&&!isIOSFullscreen(t)){const t=this.options.hideActiveTrack?"hidden":"showing";i.mode!==t&&(i.mode=t)}i.native&&i.language===(null==a?void 0:a.language)&&i.kind===a.kind&&(i.mode="showing")}}const c=n[r]&&(null!==(e=this.textTrackList[r])&&void 0!==e?e:{id:n[r].id,kind:n[r].kind,language:n[r].language,label:n[r].label});(null===(i=this.textTrack)||void 0===i?void 0:i.language)===(null==c?void 0:c.language)&&(null===(s=this.textTrack)||void 0===s?void 0:s.kind)===(null==c?void 0:c.kind)||(this.textTrack=c,this.nextTextTrack=this.textTrack,this.emit(this.Events.CurrentTextTrackChanged,{textTrack:this.textTrack,index:r}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttrackchange",{textTrack:this.textTrack,index:r}))})).on("addtrack",(({track:t})=>t&&a(t))).on("removetrack",(({track:t})=>t&&r(t))),e.length>0){i=!0;try{Array.prototype.forEach.call(e,a),n()}finally{i=!1}}}setTextTracks(t){const e=this.getMediaElement();if(this.eventListeners.scope(e,"@@setTextTracks").removeAllListeners(),this.addedTracks.forEach((t=>t.remove())),0===t.length)return;const i=()=>{addTextTracks(e,t,(t=>this.addedTracks.push(t)))};e.readyState>=e.HAVE_CURRENT_DATA?i():this.eventListeners.scope(e,"@@setTextTracks").once("loadeddata",i)}getActiveTextTrack(){return this.textTrack}setActiveTextTrack(t){const e=this.getMediaElement();this.nextTextTrack=t&&this.textTrackList.find((e=>e.language===t.language&&(!t.kind||e.kind===t.kind))),setActiveTextTrack(e,this.nextTextTrack,this.options.hideActiveTrack||isIOSFullscreen(e))}destroy(){this.detach(),this.removeAllListeners()}}!function(t){let e;!function(t){t.TextTrackListChanged="TrackListChanged",t.CurrentTextTrackChanged="CurrentTextTrackChanged",t.TextTrackCueChanged="TextTrackCueChanged"}(e=t.Events||(t.Events={}))}(TextTracksController||(TextTracksController={}));
1
+ import{EventEmitter}from"eventemitter3";import{EventListeners}from"../../EventListeners";import{MediaNotAttachedError}from"../MediaNotAttachedError";import{parseTextTracks,setActiveTextTrack,addTextTracks,isIOSFullscreen,splitRows,buildCueId}from"./utils";function dispatchNativeEvent(t,e,i){t.dispatchEvent(new CustomEvent(e,{detail:i}))}export class TextTracksController extends EventEmitter{get Events(){return TextTracksController.Events}constructor(t){super(),this.eventListeners=new EventListeners,this.addedTracks=[],this.textTrackList=[],this.options={emitNativeEvents:!1,hideActiveTrack:!0,preferCueRowLength:0},t&&this.setOptions(t)}setOptions(t){var e,i,s;Object.assign(this.options,Object.assign(Object.assign({},t),{emitNativeEvents:null!==(e=t.emitNativeEvents)&&void 0!==e?e:this.options.emitNativeEvents,hideActiveTrack:null!==(i=t.hideActiveTrack)&&void 0!==i?i:this.options.hideActiveTrack,preferCueRowLength:null!==(s=t.preferCueRowLength)&&void 0!==s?s:this.options.preferCueRowLength}))}isAttached(){return!!this.media}getMediaElement(){if(!this.media)throw new MediaNotAttachedError;return this.media}detach(){this.eventListeners.removeAllListeners(),this.media=void 0,this.addedTracks=[],this.textTrackList=[],this.textTrack=void 0,this.nextTextTrack=void 0}attach(t){this.detach();const e=(()=>{const e=[];return i=>{var s;const{activeCues:a}=i.target;if(!a)return;let n=e.length!==a.length;const r=new Array(a.length);for(let t=0;t<r.length;t+=1){const i=a[t];i.id=i.id||buildCueId(i,t),r[t]=i,r[t].rows=splitRows(i.text,this.options.preferCueRowLength),n||(null===(s=e[t])||void 0===s?void 0:s.id)===i.id||(n=!0),e[t]=i}e.length>r.length&&e.splice(r.length-e.length),n&&(this.emit(this.Events.TextTrackCueChanged,{textTrack:i.target,cues:r}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttrackcuechange",{textTrack:i.target,cues:r}))}})(),i=()=>{var e;this.textTrackList=parseTextTracks(t),this.emit(this.Events.TextTrackListChanged,{textTracks:this.textTrackList}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttracklistchange",{textTracks:this.textTrackList}),setActiveTextTrack(t,null!==(e=this.textTrack)&&void 0!==e?e:this.nextTextTrack,this.options.hideActiveTrack&&!isIOSFullscreen(t))};this.media=t,this.textTrackList=parseTextTracks(t);let s=!1;const a=t=>{s||i(),this.eventListeners.scope(t).on("cuechange",e)},n=t=>{i(),this.eventListeners.scope(t).off("cuechange",e)};if(this.eventListeners.scope(this.media.textTracks).on("change",(()=>{var e,i,s;const{textTracks:a}=t,{nextTextTrack:n}=this;let r=-1;for(let e=0;e<a.length;e+=1){const i=a[e];if(i.language===(null==n?void 0:n.language)&&i.kind===(null==n?void 0:n.kind)||isIOSFullscreen(t)||(i.mode="disabled"),"disabled"!==i.mode&&r>=0&&(i.mode="disabled"),"disabled"!==i.mode){if(r=e,!i.native&&!isIOSFullscreen(t)){const t=this.options.hideActiveTrack?"hidden":"showing";i.mode!==t&&(i.mode=t)}i.native&&i.language===(null==n?void 0:n.language)&&i.kind===n.kind&&(i.mode="showing")}}const c=a[r]&&(null!==(e=this.textTrackList[r])&&void 0!==e?e:{id:a[r].id,kind:a[r].kind,language:a[r].language,label:a[r].label});(null===(i=this.textTrack)||void 0===i?void 0:i.language)===(null==c?void 0:c.language)&&(null===(s=this.textTrack)||void 0===s?void 0:s.kind)===(null==c?void 0:c.kind)||(this.textTrack=c,this.nextTextTrack=this.textTrack,this.emit(this.Events.CurrentTextTrackChanged,{textTrack:this.textTrack,index:r}),this.options.emitNativeEvents&&dispatchNativeEvent(t,"texttrackchange",{textTrack:this.textTrack,index:r}))})).on("addtrack",(({track:t})=>t&&a(t))).on("removetrack",(({track:t})=>t&&n(t))),this.media.textTracks.length>0){s=!0;try{Array.prototype.forEach.call(this.media.textTracks,a),i()}finally{s=!1}}}getTextTracks(){return this.textTrackList}setTextTracks(t){const e=this.getMediaElement();if(this.eventListeners.scope(e,"@@setTextTracks").removeAllListeners(),this.addedTracks.forEach((t=>t.remove())),0===t.length)return;const i=()=>{addTextTracks(e,t,(t=>this.addedTracks.push(t))),this.textTrackList=parseTextTracks(e)};e.readyState>=e.HAVE_CURRENT_DATA?i():this.eventListeners.scope(e,"@@setTextTracks").once("loadeddata",i)}getActiveTextTrack(){return this.textTrack}setActiveTextTrack(t){const e=this.getMediaElement();return this.nextTextTrack=t&&this.textTrackList.find((e=>e.language===t.language&&(!t.kind||e.kind===t.kind))),setActiveTextTrack(e,this.nextTextTrack,this.options.hideActiveTrack&&!isIOSFullscreen(e))}destroy(){this.detach(),this.removeAllListeners()}}!function(t){let e;!function(t){t.TextTrackListChanged="TrackListChanged",t.CurrentTextTrackChanged="CurrentTextTrackChanged",t.TextTrackCueChanged="TextTrackCueChanged"}(e=t.Events||(t.Events={}))}(TextTracksController||(TextTracksController={}));
@@ -3,7 +3,7 @@ declare global {
3
3
  customGroupId?: string | undefined;
4
4
  }
5
5
  }
6
- export type TextTrackItem = Readonly<PartialSome<RequiredStrict<Pick<HTMLTrackElement, 'src' | 'default'> & Pick<TextTrack, 'kind' | 'label' | 'language'>>, 'default' | 'kind'>>;
6
+ export type TextTrackItem = Readonly<PartialSome<RequiredStrict<Pick<HTMLTrackElement, 'src'> & Pick<TextTrack, 'kind' | 'label' | 'language'>>, 'kind'>>;
7
7
  export interface TextTrackInfo extends Pick<TextTrackItem, 'kind' | 'language' | 'label'> {
8
8
  readonly id: string;
9
9
  }
@@ -12,8 +12,8 @@ export type ActivateTextTrackInfo = OptionalToUndefined<PartialBut<Pick<TextTrac
12
12
  export declare function fakeDetachTextTracks(media: HTMLMediaElement): void;
13
13
  export declare function parseTextTracks(media: HTMLMediaElement): TextTrackInfo[];
14
14
  export declare function isIOSFullscreen(media: HTMLMediaElement): boolean;
15
- export declare function setActiveTextTrack(media: HTMLMediaElement, tt: ActivateTextTrackInfo | undefined, hideActiveTrack: boolean): void;
15
+ export declare function setActiveTextTrack(media: HTMLMediaElement, tt: ActivateTextTrackInfo | undefined, hideActiveTrack: boolean): boolean;
16
16
  /** Dynamically add text tracks */
17
17
  export declare function addTextTracks(media: HTMLMediaElement, textTrackList: readonly TextTrackItem[], onAdd: (el: HTMLTrackElement) => void): void;
18
18
  export declare function buildCueId(cue: Pick<TextTrackCue, 'startTime'>, index: number): string;
19
- export declare function splitRows(text: string): string[];
19
+ export declare function splitRows(text: string, preferLineLength: number): string[];
@@ -1 +1 @@
1
- import{isIOS}from"../../platform/isIOS";const DETACHED_GROUP_ID="__detached__";export function fakeDetachTextTracks(e){[].forEach.call(e.textTracks,(e=>{const t=e;t.customGroupId&&(t.customGroupId="__detached__")}))}export function parseTextTracks(e){return 0===e.textTracks.length?[]:Array.prototype.filter.call(e.textTracks,(e=>"__detached__"!==e.customGroupId&&!!e.language)).map((({id:e,kind:t,language:n,label:a})=>({id:e,kind:t,language:n,label:null!=a?a:""})))}export function isIOSFullscreen(e){return isIOS()&&!!e.webkitDisplayingFullscreen}export function setActiveTextTrack(e,t,n){const{textTracks:a}=e;if(0===a.length)return;let r=!1;for(let e=0;e<a.length;e+=1){const l=a[e];if(r||l.language!==(null==t?void 0:t.language)||t.kind&&l.kind!==t.kind)l.mode="disabled";else{const e=n?"hidden":"showing";l.mode=e,r=!0}}}export function addTextTracks(e,t,n){const a=Array.prototype.reduce.call(e.textTracks,((e,t)=>(t.language&&(e[t.language]=t),e)),{});t.forEach((t=>{var r;if(!a[t.language]){const a=document.createElement("track");a.src=t.src,a.srclang=t.language,a.label=t.label,a.kind=null!==(r=t.kind)&&void 0!==r?r:"captions",a.default=!1,n(e.appendChild(a))}}))}export function buildCueId(e,t){return`${e.startTime}-${t}`}export function splitRows(e){return e.split(/\r?\n/)}
1
+ import{isIOS}from"../../platform/isIOS";const DETACHED_GROUP_ID="__detached__";export function fakeDetachTextTracks(t){Array.prototype.forEach.call(t.textTracks,(t=>{const e=t;e.customGroupId&&(e.customGroupId="__detached__")}))}export function parseTextTracks(t){return 0===t.textTracks.length?[]:Array.prototype.reduce.call(t.textTracks,((t,{customGroupId:e,id:n,kind:l,language:r,label:a})=>("__detached__"!==e&&r&&t.push({id:n,kind:l,language:r,label:null!=a?a:""}),t)),[])}export function isIOSFullscreen(t){return isIOS()&&!!t.webkitDisplayingFullscreen}export function setActiveTextTrack(t,e,n){const{textTracks:l}=t;if(0===l.length)return!1;let r=!1,a=!1;for(let t=0;t<l.length;t+=1){const i=l[t];if(a||i.language!==(null==e?void 0:e.language)||e.kind&&i.kind!==e.kind)"disabled"!==i.mode&&(i.mode="disabled",r=!0);else{const t=n?"hidden":"showing";i.mode=t,a=!0,r=!0}}return r}export function addTextTracks(t,e,n){const l=Array.prototype.reduce.call(t.textTracks,((t,e)=>(e.language&&(t[e.language]=e),t)),{});e.forEach((e=>{var r;if(!l[e.language]){const l=document.createElement("track");l.src=e.src,l.srclang=e.language,l.label=e.label,l.kind=null!==(r=e.kind)&&void 0!==r?r:"captions",l.default=!1,n(t.appendChild(l))}}))}export function buildCueId(t,e){return`${t.startTime}-${e}`}export function splitRows(t,e){var n;if(e<=0)return t.split(/\r?\n/);const l=[];let r=0,a=r,i="";for(let o=0;o<=t.length;o+=1){const c=t[o];i.length>0&&r<a&&(l[a]=null==c?i.trim():i.trimStart(),i=""),r=a;let s=null!==(n=l[r])&&void 0!==n?n:"";if("\n"===c||"\r\n"===c)i.length>0&&s.length+i.length<=e&&(s+=s.length>0?i:i.trimStart(),i=""),a+=1;else if(" "===c){if(i.length>0){s.length+i.length>e&&s.length>0?(a+=1,s=s.trimEnd()):(s+=0===s.length?i.trimStart():i,i="")}i+=c}else if(null==c&&i.length>0){s.length+i.length>e&&0!==s.length?(r+=1,s=i.trim()):s+=i}else c&&(i+=c);l[r]=s}return l}
@@ -2,11 +2,16 @@ export interface CueSegment {
2
2
  readonly id: string;
3
3
  readonly startTime: number | undefined;
4
4
  readonly tag: keyof typeof TAG_NAME;
5
- readonly node: Element;
5
+ readonly node: HTMLElement;
6
6
  }
7
7
  declare const TAG_NAME: Record<string, string>;
8
- export interface ParseCueTextResult<P extends CueSegment> {
9
- readonly segments: P[];
8
+ export interface ParseCueTextOptions {
9
+ /** Defaults to `0`. */
10
+ readonly preferLength?: number | undefined;
10
11
  }
11
- export declare function parseCueText<P extends CueSegment>(input0: string, map?: (segment: CueSegment) => P): ParseCueTextResult<P>;
12
+ export interface ParseCueTextResult<P> {
13
+ readonly segments: P[][];
14
+ readonly rawText: string[];
15
+ }
16
+ export declare function parseCueText<P = CueSegment>(input0: string, map?: (segment: CueSegment, prevSegment: P | undefined) => P, { preferLength }?: ParseCueTextOptions): ParseCueTextResult<P>;
12
17
  export {};
@@ -1 +1 @@
1
- const ESCAPE={"&amp;":"&","&lt;":"<","&gt;":">","&lrm;":"‎","&rlm;":"‏","&nbsp;":" "},TAG_NAME={c:"span",i:"i",b:"b",u:"u",ruby:"ruby",rt:"rt",lang:"span"},TAG_ANNOTATION={v:"title",lang:"lang"},NEEDS_PARENT={rt:"ruby"};function computeSeconds(e,t,n,o){return 3600*(+e||0)+60*(+t||0)+(+n||0)+(+o||0)/1e3}function parseTimeStamp(e){const t=e.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/);if(!t)return;const[,n,o,r,c]=t;return c?computeSeconds(n,o,r.replace(":",""),c):+n>59?computeSeconds(n,o,"",c):computeSeconds("",n,o,c)}function unescape(e){let t,n=e;for(;t=n.match(/&(amp|lt|gt|lrm|rlm|nbsp);/);)n=n.replace(t[0],(e=>ESCAPE[e]));return n}function nextToken(e){if(!e)return[e,void 0];const t=e.match(/^([^<]*)(<[^>]+>?)?/);if(!t)return[e,void 0];const n=t[1]?t[1]:t[2];return[e.substring(n.length),n]}function shouldAdd(e,t){return!NEEDS_PARENT[t.localName]||NEEDS_PARENT[t.localName]===e.localName}function createHtmlNode(e,t){const n=TAG_NAME[e];if(!n)return;const o=window.document.createElement(n),r=TAG_ANNOTATION[e];return r&&t&&(o[r]=t.trim()),o}export function parseCueText(e,t){let n,o,r=e,c=-1;const s=[],l=[],u=e=>{var o;const r=null!==(o=s.pop())&&void 0!==o?o:"",u=n;if(n=u.parentElement||void 0,null==n){const n={id:e,startTime:c>=0?c:void 0,tag:r,node:u};l.push(t?t(n):n),c=-1}};for(;null!=([r,o]=nextToken(r),o);){const e=String(l.length+1);if("<"===o[0])if("/"===o[1])s.at(-1)===o.substring(2).replace(">","")&&u(e);else{const e=parseTimeStamp(o.substring(1,o.length-1));if(e)c=e;else{const e=o.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/),t=e&&createHtmlNode(e[1],e[3]);!t||n&&!shouldAdd(n,t)||(e[2]&&(t.className=e[2].substring(1).replace("."," ")),s.push(e[1]),null==n||n.appendChild(t),n=t)}}else{if(null==n){const n=createHtmlNode("c","");if(n){n.appendChild(window.document.createTextNode(unescape(o)));const r={id:e,node:n,tag:"c",startTime:void 0};l.push(t?t(r):r)}}n&&n.appendChild(window.document.createTextNode(unescape(o)))}}return{segments:l}}
1
+ import{splitRows}from"./TextTracksController/utils";const ESCAPE={"&amp;":"&","&lt;":"<","&gt;":">","&lrm;":"‎","&rlm;":"‏","&nbsp;":" "},TAG_NAME={c:"span",i:"i",b:"b",u:"u",ruby:"ruby",rt:"rt",lang:"span"},TAG_ANNOTATION={v:"title",lang:"lang"},NEEDS_PARENT={rt:"ruby"};function computeSeconds(e,t,n,o){return 3600*(+e||0)+60*(+t||0)+(+n||0)+(+o||0)/1e3}function parseTimeStamp(e){const t=e.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/);if(!t)return;const[,n,o,l,r]=t;return r?computeSeconds(n,o,l.replace(":",""),r):+n>59?computeSeconds(n,o,"",r):computeSeconds("",n,o,r)}function unescape(e){let t,n=e;for(;t=n.match(/&(amp|lt|gt|lrm|rlm|nbsp);/);)n=n.replace(t[0],(e=>ESCAPE[e]));return n}function nextToken(e){if(!e)return[e,void 0];const t=e.match(/^([^<]*)(<[^>]+>?)?/);if(!t)return[e,void 0];const n=t[1]?t[1]:t[2];return[e.substring(n.length),n]}function shouldAdd(e,t){return!NEEDS_PARENT[t.localName]||NEEDS_PARENT[t.localName]===e.localName}function createHtmlNode(e,t){const n=TAG_NAME[e];if(!n)return;const o=window.document.createElement(n),l=TAG_ANNOTATION[e];return l&&t&&(o[l]=t.trim()),o}export function parseCueText(e,t,{preferLength:n=0}={}){let o,l,r=e,s=-1;const a=[],c=[],u=[],i=e=>{var n,o;0===c.length&&c.push([]),c.at(-1).push(t?t(e,null===(o=null!==(n=c.at(-1))&&void 0!==n?n:c.at(-2))||void 0===o?void 0:o.at(-1)):e)},d=e=>{var t;const n=null!==(t=a.pop())&&void 0!==t?t:"",l=o;if(o=l.parentElement||void 0,null==o){i({id:e,startTime:s>=0?s:void 0,tag:n,node:l})}},p=(e,t)=>{t?u.push(e):u[u.length-1]+=e,t&&c.push([]),null==o?(e=>{const t=createHtmlNode("c","");t.appendChild(window.document.createTextNode(unescape(e)));const n={id:m(),node:t,tag:"c",startTime:s>=0?s:void 0};i(n)})(e):o.appendChild(window.document.createTextNode(unescape(e)))},m=()=>{var e,t;return`${c.length}-${(null!==(t=null===(e=c.at(-1))||void 0===e?void 0:e.length)&&void 0!==t?t:0)+1}`};for(;null!=([r,l]=nextToken(r),l);)if("<"===l[0])if("/"===l[1])a.at(-1)===l.substring(2).replace(">","")&&d(m());else{const e=parseTimeStamp(l.substring(1,l.length-1));if(e)s=e;else{const e=l.match(/^<([^.\s/0-9>]+)(\.[^\s\\>]+)?([^>\\]+)?(\\?)>?$/),t=e&&createHtmlNode(e[1],e[3]);!t||o&&!shouldAdd(o,t)||(e[2]&&(t.className=e[2].substring(1).replace("."," ")),a.push(e[1]),null==o||o.appendChild(t),o=t)}}else if(0===u.length||n>0&&u.at(-1).length+l.length>n){const e=splitRows(l,n);for(let t=0;t<e.length;t+=1)p(e[t],!0)}else p(l,!1);return{segments:c,rawText:u}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@js-toolkit/web-utils",
3
- "version": "1.53.0",
3
+ "version": "1.55.0",
4
4
  "description": "Web utils",
5
5
  "author": "VZH",
6
6
  "license": "MIT",
@@ -17,29 +17,35 @@
17
17
  "minor-publish": "npm run build && npm version minor --force --no-workspaces-update -m 'v%s' && npm run copy:configs && cd ./dist && npm publish --access public && git push --follow-tags"
18
18
  },
19
19
  "optionalDependencies": {
20
- "@js-toolkit/node-utils": "^1.2.0"
20
+ "@js-toolkit/node-utils": "^1.2.1"
21
21
  },
22
22
  "devDependencies": {
23
- "@js-toolkit/configs": "^3.92.0",
24
- "@js-toolkit/utils": "^1.53.1",
25
- "@types/uuid": "^9.0.8",
26
- "@typescript-eslint/eslint-plugin": "^7.10.0",
27
- "@typescript-eslint/parser": "^7.10.0",
23
+ "@eslint/compat": "^1.1.1",
24
+ "@eslint/eslintrc": "^3.1.0",
25
+ "@eslint/js": "^9.7.0",
26
+ "@js-toolkit/configs": "^3.93.1",
27
+ "@js-toolkit/utils": "^1.54.0",
28
+ "@types/eslint": "^9.6.0",
29
+ "@types/eslint__eslintrc": "^2.1.2",
30
+ "@types/eslint__js": "^8.42.3",
31
+ "@types/lodash.throttle": "^4.1.9",
32
+ "@types/uuid": "^10.0.0",
28
33
  "copyfiles": "^2.4.1",
29
- "eslint": "^8.57.0",
30
- "eslint-config-airbnb-base": "^15.0.0",
34
+ "eslint": "^9.7.0",
31
35
  "eslint-config-prettier": "^9.1.0",
32
36
  "eslint-plugin-import": "^2.29.1",
33
- "eslint-plugin-prettier": "^5.1.3",
37
+ "eslint-plugin-prettier": "^5.2.1",
34
38
  "eventemitter3": "^5.0.1",
35
- "prettier": "^3.2.5",
39
+ "lodash.throttle": "^4.1.1",
40
+ "prettier": "^3.3.3",
36
41
  "reconnecting-websocket": "^4.4.0",
37
- "rimraf": "^5.0.7",
38
- "terser": "^5.31.0",
39
- "typescript": "^5.4.5",
40
- "ua-parser-js": "^2.0.0-beta.2",
41
- "uuid": "^9.0.1",
42
- "webpack": "^5.91.0",
42
+ "rimraf": "^6.0.1",
43
+ "terser": "^5.31.3",
44
+ "typescript": "^5.5.4",
45
+ "typescript-eslint": "^7.17.0",
46
+ "ua-parser-js": "^2.0.0-beta.3",
47
+ "uuid": "^10.0.0",
48
+ "webpack": "^5.93.0",
43
49
  "yargs": "^17.7.2"
44
50
  }
45
51
  }
@@ -1,7 +1,8 @@
1
- /// <reference types="ua-parser-js/src/main/ua-parser" />
1
+ /// <reference types="ua-parser-js" preserve="true" />
2
2
  type PlatformInfo = DeepReadonly<OmitStrict<UAParser.IResult, 'withClientHints' | 'withFeatureCheck'>> & {
3
3
  toStringObject(): Record<Keys<ExcludeKeysOfType<UAParser.IResult, AnyFunction>>, string>;
4
4
  };
5
+ export declare function getPlatformInfoSync(): PlatformInfo;
5
6
  export declare function getPlatformInfo(): Promise<PlatformInfo>;
6
7
  export declare function getCachedPlatformInfo(): PlatformInfo | undefined;
7
8
  export {};
@@ -1 +1 @@
1
- import{__awaiter}from"tslib";import{UAParser}from"ua-parser-js";let result,promise;export function getPlatformInfo(){return __awaiter(this,void 0,void 0,(function*(){return null==result&&(promise=null!=promise?promise:Promise.resolve(new UAParser(navigator.userAgent).getResult().withFeatureCheck().withClientHints()),result=Object.assign(Object.assign({},yield promise),{toStringObject(){return Object.getOwnPropertyNames(this).reduce(((t,e)=>{const r=e;return null!=this[r]&&"function"!=typeof this[r]&&(t[r]=this[r].toString()),t}),{})}}),promise=void 0),result}))}export function getCachedPlatformInfo(){return null==result&&(console.warn("PlatformInfo is not ready yet."),getPlatformInfo()),result}
1
+ import{__awaiter}from"tslib";import{UAParser}from"ua-parser-js";let syncResult,asyncResult,promise;function toPlatformInfo(t){return Object.assign(Object.assign({},t),{toStringObject(){return Object.getOwnPropertyNames(this).reduce(((t,e)=>{const n=e;return null!=this[n]&&"function"!=typeof this[n]&&(t[n]=this[n].toString()),t}),{})}})}export function getPlatformInfoSync(){return null==syncResult&&(syncResult=toPlatformInfo(new UAParser(navigator.userAgent).getResult().withFeatureCheck())),syncResult}export function getPlatformInfo(){return __awaiter(this,void 0,void 0,(function*(){return null==asyncResult&&(promise=null!=promise?promise:Promise.resolve(new UAParser(navigator.userAgent).getResult().withFeatureCheck().withClientHints()),asyncResult=toPlatformInfo(yield promise),syncResult=asyncResult,promise=void 0),asyncResult}))}export function getCachedPlatformInfo(){return null==asyncResult&&(console.warn("PlatformInfo is not ready yet."),getPlatformInfo()),asyncResult}
@@ -1,4 +1,4 @@
1
- /// <reference lib="webworker" />
1
+ /// <reference lib="webworker" preserve="true" />
2
2
  export declare function isLocalhost(hostname?: string): boolean;
3
3
  /** Delete all caches that aren't named in `caches`. */
4
4
  export declare function removeUnknownCaches<T extends Record<string, string>>(expectedCaches: T): Promise<unknown>;
@@ -0,0 +1,12 @@
1
+ export interface ViewableTrackerOptions {
2
+ /** Visibility part to detect state as viewable. */
3
+ readonly visiblePart?: boolean | number | undefined;
4
+ readonly scrollThrottle?: number | undefined;
5
+ readonly documentVisibility?: boolean | undefined;
6
+ readonly onChange: (viewable: boolean) => void;
7
+ }
8
+ export interface ViewableTracker {
9
+ readonly check: VoidFunction;
10
+ readonly destroy: VoidFunction;
11
+ }
12
+ export declare function getViewableTracker(element: HTMLElement, { visiblePart: visiblePartOption, scrollThrottle, documentVisibility, onChange, }: ViewableTrackerOptions): ViewableTracker;
@@ -0,0 +1 @@
1
+ import throttleFn from"lodash.throttle";export function getViewableTracker(t,{visiblePart:e=.8,scrollThrottle:i=200,documentVisibility:n=!0,onChange:o}){const r=+e;let s,l=0,c="visible"===document.visibilityState;const a=()=>{if(n&&"visible"!==document.visibilityState)return;const{top:e,bottom:i,height:l}=t.getBoundingClientRect(),c=l*r,a=e+c,d=window.innerHeight>=a&&i>c;s!==d&&(s=d,o(d))},d=()=>{const t="visible"===document.visibilityState;c!==t&&(c=t,t&&r>0?(s=void 0,a()):(r<=0||s!==t)&&o(t))},v=i&&i>0?throttleFn(a,i):()=>{n&&"visible"!==document.visibilityState||(l=window.requestAnimationFrame(a))};r>0&&window.addEventListener("scroll",v,{capture:!1,passive:!0}),n&&document.addEventListener("visibilitychange",d);return{check:()=>{r>0&&a(),n&&d()},destroy:()=>{cancelAnimationFrame(l),window.removeEventListener("scroll",v,{capture:!1}),document.removeEventListener("visibilitychange",d)}}}
@@ -1 +1 @@
1
- import{__rest}from"tslib";import ReconnectingWebSocket,{}from"reconnecting-websocket";import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{delayed}from"@js-toolkit/utils/delayed";import{EventEmitterListener}from"../EventEmitterListener";function getNotConnectedError(){return new Error("The object is not connected yet.")}export class WSController extends DataEventEmitter{get Events(){return WSController.Events}constructor(e,t){super();const n=null!=t?t:{},{logger:s,protocols:o,binaryType:i,idleTimeout:r,halfOpenDetection:c,startClosed:l}=n,a=__rest(n,["logger","protocols","binaryType","idleTimeout","halfOpenDetection","startClosed"]);this.logger=null!=s?s:console,this.ws=new ReconnectingWebSocket(e,o,Object.assign(Object.assign({},a),{startClosed:!0})),null!=i&&(this.ws.binaryType=i),this.listener=new EventEmitterListener(this.ws),r&&r>0&&(this.reconnectOnIdle=delayed((()=>{this.logger.info(`WS connection reconnecting after ${r}ms due to inactivity.`),this.ws.reconnect()}),r)),this.halfOpen=(()=>{if(!c)return;const{pingTimeout:e=12e3,outMessage:t=(()=>JSON.stringify({type:"pong"})),inMessageFilter:n=(e=>e&&"object"==typeof e&&"ping"===e.type)}=c,s=delayed((()=>{this.logger.info(`WS connection reconnecting after ${e}ms due to the probability of a half-open connection.`),this.ws.reconnect()}),e),o=()=>{s(),this.ws.send("function"!=typeof t||t instanceof Blob?t:t())};return{heartbeat:o,cancel:()=>s.cancel(),onMessage:({data:e})=>{n(e)?o():s()}}})(),this.listener.on("open",(()=>{var e;this.reconnectOnIdle&&this.reconnectOnIdle(),null===(e=this.halfOpen)||void 0===e||e.heartbeat(),this.emit(this.Events.Connected)})).on("close",(({code:e})=>{var n,s;null===(n=this.reconnectOnIdle)||void 0===n||n.cancel(),null===(s=this.halfOpen)||void 0===s||s.cancel(),null!=(null==t?void 0:t.maxRetries)&&this.ws.readyState===this.ws.CLOSED&&this.ws.retryCount===t.maxRetries&&this.close(e,`Failed to connect after ${t.maxRetries} attempts.`)})).on("message",(e=>{var t;this.reconnectOnIdle&&this.reconnectOnIdle(),null===(t=this.halfOpen)||void 0===t||t.onMessage(e),this.emit(this.Events.Message,e)})).on("error",(({error:e,message:t})=>{this.emit(this.Events.Error,{error:e,message:t})})),this.halfOpen&&(this.isConnected()||this.ws.readyState===this.ws.CONNECTING)&&this.halfOpen.heartbeat(),l||this.connect()}isConnected(){return this.ws.readyState===this.ws.OPEN}getUrl(){return this.ws.url}connect(){this.ws.reconnect()}send(e){if(!this.ws)throw getNotConnectedError();this.ws.send(e)}close(e,t){const n=!!this.ws;try{this.reconnectOnIdle&&this.reconnectOnIdle.cancel(),this.halfOpen&&this.halfOpen.cancel(),this.ws.close(e,t)}catch(e){this.logger.warn(e)}n&&this.emit(this.Events.Closed,t?{reason:t}:void 0)}destroy(){this.close(),this.listener.removeAllListeners(),this.removeAllListeners()}}!function(e){let t;!function(e){e.Connected="Connected",e.Message="Message",e.Error="Error",e.Closed="Closed"}(t=e.Events||(e.Events={}))}(WSController||(WSController={}));
1
+ import{__rest}from"tslib";import ReconnectingWebSocket,{}from"reconnecting-websocket";import{DataEventEmitter}from"@js-toolkit/utils/DataEventEmitter";import{delayed}from"@js-toolkit/utils/delayed";import{EventEmitterListener}from"../EventEmitterListener";function getNotConnectedError(){return new Error("The object is not connected yet.")}export class WSController extends DataEventEmitter{get Events(){return WSController.Events}constructor(e,t){super();const n=null!=t?t:{},{logger:s,protocols:o,binaryType:i,idleTimeout:r,halfOpenDetection:c,startClosed:l}=n,a=__rest(n,["logger","protocols","binaryType","idleTimeout","halfOpenDetection","startClosed"]);this.logger=null!=s?s:console,this.ws=new ReconnectingWebSocket(e,o,Object.assign(Object.assign({},a),{startClosed:!0})),null!=i&&(this.ws.binaryType=i),this.listener=new EventEmitterListener(this.ws),r&&r>0&&(this.reconnectOnIdle=delayed((()=>{this.logger.info(`WS connection reconnecting after ${r}ms due to inactivity.`),this.ws.reconnect()}),r)),this.halfOpen=(()=>{if(!c)return;const{pingTimeout:e=12e3,outMessage:t=()=>JSON.stringify({type:"pong"}),inMessageFilter:n=e=>e&&"object"==typeof e&&"ping"===e.type}=c,s=delayed((()=>{this.logger.info(`WS connection reconnecting after ${e}ms due to the probability of a half-open connection.`),this.ws.reconnect()}),e),o=()=>{s(),this.ws.send("function"!=typeof t||t instanceof Blob?t:t())};return{heartbeat:o,cancel:()=>s.cancel(),onMessage:({data:e})=>{n(e)?o():s()}}})(),this.listener.on("open",(()=>{var e;this.reconnectOnIdle&&this.reconnectOnIdle(),null===(e=this.halfOpen)||void 0===e||e.heartbeat(),this.emit(this.Events.Connected)})).on("close",(({code:e})=>{var n,s;null===(n=this.reconnectOnIdle)||void 0===n||n.cancel(),null===(s=this.halfOpen)||void 0===s||s.cancel(),null!=(null==t?void 0:t.maxRetries)&&this.ws.readyState===this.ws.CLOSED&&this.ws.retryCount===t.maxRetries&&this.close(e,`Failed to connect after ${t.maxRetries} attempts.`)})).on("message",(e=>{var t;this.reconnectOnIdle&&this.reconnectOnIdle(),null===(t=this.halfOpen)||void 0===t||t.onMessage(e),this.emit(this.Events.Message,e)})).on("error",(({error:e,message:t})=>{this.emit(this.Events.Error,{error:e,message:t})})),this.halfOpen&&(this.isConnected()||this.ws.readyState===this.ws.CONNECTING)&&this.halfOpen.heartbeat(),l||this.connect()}isConnected(){return this.ws.readyState===this.ws.OPEN}getUrl(){return this.ws.url}connect(){this.ws.reconnect()}send(e){if(!this.ws)throw getNotConnectedError();this.ws.send(e)}close(e,t){const n=!!this.ws;try{this.reconnectOnIdle&&this.reconnectOnIdle.cancel(),this.halfOpen&&this.halfOpen.cancel(),this.ws.close(e,t)}catch(e){this.logger.warn(e)}n&&this.emit(this.Events.Closed,t?{reason:t}:void 0)}destroy(){this.close(),this.listener.removeAllListeners(),this.removeAllListeners()}}!function(e){let t;!function(e){e.Connected="Connected",e.Message="Message",e.Error="Error",e.Closed="Closed"}(t=e.Events||(e.Events={}))}(WSController||(WSController={}));