Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lifecycle): create multi-instances at the same time (#660) #663

Merged
merged 1 commit into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 23 additions & 67 deletions ui/packages/artalk/src/artalk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,68 +10,54 @@ import { DefaultPlugins } from './plugins'
import * as Stat from './plugins/stat'
import Api from './api'

/** Global Plugins for all instances */
const GlobalPlugins: ArtalkPlugin[] = [ ...DefaultPlugins ]

/**
* Artalk
*
* @see https://artalk.js.org
*/
export default class Artalk {
private static instance?: Artalk

public static readonly defaults: ArtalkConfig = defaults

public conf!: ArtalkConfig
public ctx!: ContextApi
public $root!: HTMLElement

/** Plugins */
protected static plugins: ArtalkPlugin[] = [ ...DefaultPlugins ]
public static DisabledComponents: string[] = []
protected plugins: ArtalkPlugin[] = [ ...GlobalPlugins ]

constructor(conf: Partial<ArtalkConfig>) {
if (Artalk.instance) Artalk.destroy()

// 初始化基本配置
// Init Config
this.conf = handelCustomConf(conf)
if (this.conf.el instanceof HTMLElement) this.$root = this.conf.el

// 初始化 Context
// Init Context
this.ctx = new ConcreteContext(this.conf, this.$root)

// 内建服务初始化
// Init Services
Object.entries(Services).forEach(([name, initService]) => {
if (Artalk.DisabledComponents.includes(name)) return
const obj = initService(this.ctx)
if (obj) this.ctx.inject(name as any, obj) // auto inject deps to ctx
})

// 插件初始化 (global scope)
Artalk.plugins.forEach(plugin => {
if (typeof plugin === 'function')
plugin(this.ctx)
// Init Plugins
this.plugins.forEach(plugin => {
if (typeof plugin === 'function') plugin(this.ctx)
})

// Trigger inited event
this.ctx.trigger('inited')
}

/** Init Artalk */
public static init(conf: Partial<ArtalkConfig>): Artalk {
if (this.instance) Artalk.destroy()
this.instance = new Artalk(conf)
return this.instance
}

/** Use Plugin (plugin will be called in instance `use` func) */
public use(plugin: ArtalkPlugin) {
Artalk.plugins.push(plugin)
if (typeof plugin === 'function') plugin(this.ctx)
}

/** Update config of Artalk */
public update(conf: Partial<ArtalkConfig>) {
if (!Artalk.instance) throw Error('cannot call `update` function before call `load`')
Artalk.instance.ctx.updateConf(conf)
return Artalk.instance
this.ctx.updateConf(conf)
return this
}

/** Reload comment list of Artalk */
Expand All @@ -81,10 +67,8 @@ export default class Artalk {

/** Destroy instance of Artalk */
public destroy() {
if (!Artalk.instance) throw Error('cannot call `destroy` function before call `load`')
this.ctx.trigger('destroy')
Artalk.instance.$root.remove()
delete Artalk.instance
this.$root.remove()
}

/** Add an event listener */
Expand All @@ -108,48 +92,20 @@ export default class Artalk {
}

// ===========================
// Static methods
// Static Members
// ===========================

/** Use Plugin (static method) */
public static use(plugin: ArtalkPlugin) {
this.plugins.push(plugin)
if (this.instance && typeof plugin === 'function') plugin(this.instance.ctx)
}

/** Update config of Artalk */
public static update(conf: Partial<ArtalkConfig>) {
return this.instance?.update(conf)
}

/** Reload comment list of Artalk */
public static reload() {
this.instance?.reload()
}

/** Destroy instance of Artalk */
public static destroy() {
this.instance?.destroy()
}

/** Add an event listener */
public static on<K extends keyof EventPayloadMap>(name: K, handler: EventHandler<EventPayloadMap[K]>) {
this.instance?.on(name, handler)
}

/** Remove an event listener */
public static off<K extends keyof EventPayloadMap>(name: K, handler: EventHandler<EventPayloadMap[K]>) {
this.instance?.off(name, handler)
}
/** Default Configs */
public static readonly defaults: ArtalkConfig = defaults

/** Trigger an event */
public static trigger<K extends keyof EventPayloadMap>(name: K, payload?: EventPayloadMap[K]) {
this.instance?.trigger(name, payload)
/** Init Artalk */
public static init(conf: Partial<ArtalkConfig>): Artalk {
return new Artalk(conf)
}

/** Set dark mode */
public static setDarkMode(darkMode: boolean) {
this.instance?.setDarkMode(darkMode)
/** Use Plugin for all instances */
public static use(plugin: ArtalkPlugin) {
GlobalPlugins.push(plugin)
}

/** Load count widget */
Expand Down
3 changes: 3 additions & 0 deletions ui/packages/artalk/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export function handelCustomConf(customConf: Partial<ArtalkConfig>): ArtalkConfi
// 合并默认配置
const conf: ArtalkConfig = Utils.mergeDeep(Defaults, customConf)

// TODO the type of el options may HTMLElement, use it directly instead of from mergeDeep
if (customConf.el) conf.el = customConf.el

// 绑定元素
if (typeof conf.el === 'string' && !!conf.el) {
try {
Expand Down
5 changes: 1 addition & 4 deletions ui/packages/artalk/src/plugins/conf-remoter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import type { ArtalkConfig, ArtalkPlugin, ContextApi } from '~/types'
import { handleConfFormServer } from '@/config'
import { showErrorDialog } from '../components/error-dialog'

let confLoaded = false

export const ConfRemoter: ArtalkPlugin = (ctx) => {
ctx.on('inited', () => {
if (!confLoaded) loadConf(ctx)
loadConf(ctx)
})
}

Expand All @@ -26,7 +24,6 @@ function loadConf(ctx: ContextApi) {
ctx.conf.remoteConfModifier && ctx.conf.remoteConfModifier(conf)

ctx.updateConf(conf)
confLoaded = true
}).catch((err) => {
ctx.updateConf({})

Expand Down