Update eslint cofig

This commit is contained in:
Manuel Bouza 2019-06-26 09:27:31 +02:00
parent fd04d6bf6c
commit 8b2e21c3cf
14 changed files with 115 additions and 151 deletions

View File

@ -22,6 +22,11 @@
}, },
"sourceType": "module" "sourceType": "module"
}, },
"settings": {
"react": {
"version": "detect"
}
},
"rules": { "rules": {
"strict": 0, "strict": 0,
"semi": ["error", "never"], "semi": ["error", "never"],

View File

@ -3,19 +3,15 @@ import { formatDate } from "utils"
const baseURL = subdomain => { const baseURL = subdomain => {
if (process.env.NODE_ENV === "production") { if (process.env.NODE_ENV === "production") {
return `https://${encodeURIComponent( return `https://${encodeURIComponent(subdomain)}.mocoapp.com/api/browser_extensions`
subdomain
)}.mocoapp.com/api/browser_extensions`
} else { } else {
return `http://${encodeURIComponent( return `http://${encodeURIComponent(subdomain)}.mocoapp.localhost:3001/api/browser_extensions`
subdomain
)}.mocoapp.localhost:3001/api/browser_extensions`
} }
} }
export default class Client { export default class Client {
#client; #client
#apiKey; #apiKey
constructor({ subdomain, apiKey, version }) { constructor({ subdomain, apiKey, version }) {
this.#apiKey = apiKey this.#apiKey = apiKey
@ -25,9 +21,9 @@ export default class Client {
headers: { headers: {
common: { common: {
"x-api-key": apiKey, "x-api-key": apiKey,
"x-extension-version": version "x-extension-version": version,
} },
} },
}) })
} }
@ -35,29 +31,29 @@ export default class Client {
this.#client.post("session", { this.#client.post("session", {
api_key: this.#apiKey, api_key: this.#apiKey,
remote_service: service?.name, remote_service: service?.name,
remote_id: service?.id remote_id: service?.id,
}); })
projects = () => this.#client.get("projects"); projects = () => this.#client.get("projects")
schedules = (fromDate, toDate) => schedules = (fromDate, toDate) =>
this.#client.get("schedules", { this.#client.get("schedules", {
params: { date: `${formatDate(fromDate)}:${formatDate(toDate)}` } params: { date: `${formatDate(fromDate)}:${formatDate(toDate)}` },
}); })
activities = (fromDate, toDate) => activities = (fromDate, toDate) =>
this.#client.get("activities", { this.#client.get("activities", {
params: { date: `${formatDate(fromDate)}:${formatDate(toDate)}` } params: { date: `${formatDate(fromDate)}:${formatDate(toDate)}` },
}); })
bookedHours = service => { bookedHours = service => {
if (!service) { if (!service) {
return Promise.resolve({ data: { hours: 0 } }) return Promise.resolve({ data: { hours: 0 } })
} }
return this.#client.get("activities/tags", { return this.#client.get("activities/tags", {
params: { selection: [service.id], remote_service: service.name } params: { selection: [service.id], remote_service: service.name },
}) })
}; }
createActivity = activity => this.#client.post("activities", { activity }); createActivity = activity => this.#client.post("activities", { activity })
} }

View File

@ -10,15 +10,11 @@ const Day = ({ date, hours, absence, active, onClick }) => {
return ( return (
<div <div
className={cn( className={cn("moco-bx-calendar__day", `moco-bx-calendar__day--week-day-${getDay(date)}`, {
"moco-bx-calendar__day", "moco-bx-calendar__day--active": active,
`moco-bx-calendar__day--week-day-${getDay(date)}`, "moco-bx-calendar__day--filled": hours > 0,
{ "moco-bx-calendar__day--absence": absence,
"moco-bx-calendar__day--active": active, })}
"moco-bx-calendar__day--filled": hours > 0,
"moco-bx-calendar__day--absence": absence
}
)}
onClick={handleClick} onClick={handleClick}
> >
<span className="moco-bx-calendar__day-of-week"> <span className="moco-bx-calendar__day-of-week">
@ -34,7 +30,7 @@ Day.propTypes = {
hours: PropTypes.number.isRequired, hours: PropTypes.number.isRequired,
absence: PropTypes.object, absence: PropTypes.object,
active: PropTypes.bool.isRequired, active: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired onClick: PropTypes.func.isRequired,
} }
export default Day export default Day

View File

@ -35,9 +35,9 @@ Hours.propTypes = {
hours: PropTypes.number.isRequired, hours: PropTypes.number.isRequired,
absence: PropTypes.shape({ absence: PropTypes.shape({
assignment_code: PropTypes.string, assignment_code: PropTypes.string,
assignment_color: PropTypes.string assignment_color: PropTypes.string,
}), }),
active: PropTypes.bool.isRequired active: PropTypes.bool.isRequired,
} }
export default Hours export default Hours

View File

@ -5,22 +5,14 @@ import { formatDate } from "utils"
import { eachDay } from "date-fns" import { eachDay } from "date-fns"
import { pathEq } from "lodash/fp" import { pathEq } from "lodash/fp"
const findAbsence = (date, schedules) => const findAbsence = (date, schedules) => schedules.find(pathEq("date", formatDate(date)))
schedules.find(pathEq("date", formatDate(date)))
const hoursAtDate = (date, activities) => const hoursAtDate = (date, activities) =>
activities activities
.filter(pathEq("date", formatDate(date))) .filter(pathEq("date", formatDate(date)))
.reduce((acc, activity) => acc + activity.hours, 0) .reduce((acc, activity) => acc + activity.hours, 0)
const Calendar = ({ const Calendar = ({ fromDate, toDate, selectedDate, activities, schedules, onChange }) => (
fromDate,
toDate,
selectedDate,
activities,
schedules,
onChange
}) => (
<div className="moco-bx-calendar"> <div className="moco-bx-calendar">
{eachDay(fromDate, toDate).map(date => ( {eachDay(fromDate, toDate).map(date => (
<Day <Day
@ -44,17 +36,17 @@ Calendar.propTypes = {
id: PropTypes.number.isRequired, id: PropTypes.number.isRequired,
date: PropTypes.string.isRequired, date: PropTypes.string.isRequired,
hours: PropTypes.number.isRequired, hours: PropTypes.number.isRequired,
timer_started_at: PropTypes.string timer_started_at: PropTypes.string,
}).isRequired }).isRequired,
), ),
schedules: PropTypes.arrayOf( schedules: PropTypes.arrayOf(
PropTypes.shape({ PropTypes.shape({
date: PropTypes.string, date: PropTypes.string,
assignment_code: PropTypes.string, assignment_code: PropTypes.string,
assignment_color: PropTypes.string assignment_color: PropTypes.string,
}) }),
).isRequired, ).isRequired,
onChange: PropTypes.func.isRequired onChange: PropTypes.func.isRequired,
} }
export default Calendar export default Calendar

View File

@ -15,7 +15,7 @@ const UnknownError = ({ message = "Unbekannter Fehler" }) => (
) )
UnknownError.propTypes = { UnknownError.propTypes = {
message: PropTypes.string message: PropTypes.string,
} }
export default UnknownError export default UnknownError

View File

@ -7,10 +7,7 @@ const UpgradeRequiredError = () => (
<div className="moco-bx-error-container"> <div className="moco-bx-error-container">
<img className="moco-bx-logo" src={logo} alt="MOCO logo" /> <img className="moco-bx-logo" src={logo} alt="MOCO logo" />
<h1>Upgrade erforderlich</h1> <h1>Upgrade erforderlich</h1>
<p> <p>Die installierte MOCO Browser-Erweiterung ist veraltet &mdash; bitte aktualisieren.</p>
Die installierte MOCO Browser-Erweiterung ist veraltet &mdash; bitte
aktualisieren.
</p>
{isChrome() ? ( {isChrome() ? (
<button <button
className="moco-bx-btn" className="moco-bx-btn"
@ -22,11 +19,7 @@ const UpgradeRequiredError = () => (
<> <>
<br /> <br />
<p>Unter folgender URL:</p> <p>Unter folgender URL:</p>
<img <img className="firefox-addons" src={firefoxAddons} alt="about:addons" />
className="firefox-addons"
src={firefoxAddons}
alt="about:addons"
/>
</> </>
)} )}
</div> </div>

View File

@ -8,24 +8,24 @@ class Form extends Component {
changeset: PropTypes.shape({ changeset: PropTypes.shape({
project: PropTypes.object, project: PropTypes.object,
task: PropTypes.object, task: PropTypes.object,
hours: PropTypes.string hours: PropTypes.string,
}).isRequired, }).isRequired,
errors: PropTypes.object, errors: PropTypes.object,
projects: PropTypes.array.isRequired, projects: PropTypes.array.isRequired,
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired onSubmit: PropTypes.func.isRequired,
}; }
static defaultProps = { static defaultProps = {
inline: true inline: true,
}; }
isValid = () => { isValid = () => {
const { changeset } = this.props const { changeset } = this.props
return ["assignment_id", "task_id", "hours", "description"] return ["assignment_id", "task_id", "hours", "description"]
.map(prop => changeset[prop]) .map(prop => changeset[prop])
.every(Boolean) .every(Boolean)
}; }
handleTextareaKeyDown = event => { handleTextareaKeyDown = event => {
const { onSubmit } = this.props const { onSubmit } = this.props
@ -34,7 +34,7 @@ class Form extends Component {
event.preventDefault() event.preventDefault()
this.isValid() && onSubmit(event) this.isValid() && onSubmit(event)
} }
}; }
render() { render() {
const { projects, changeset, errors, onChange, onSubmit } = this.props const { projects, changeset, errors, onChange, onSubmit } = this.props
@ -44,7 +44,7 @@ class Form extends Component {
<form onSubmit={onSubmit}> <form onSubmit={onSubmit}>
<div <div
className={cn("form-group", { className={cn("form-group", {
"has-error": errors.assignment_id || errors.task_id "has-error": errors.assignment_id || errors.task_id,
})} })}
> >
<Select <Select
@ -69,9 +69,7 @@ class Form extends Component {
{errors.assignment_id ? ( {errors.assignment_id ? (
<div className="form-error">{errors.assignment_id.join("; ")}</div> <div className="form-error">{errors.assignment_id.join("; ")}</div>
) : null} ) : null}
{errors.task_id ? ( {errors.task_id ? <div className="form-error">{errors.task_id.join("; ")}</div> : null}
<div className="form-error">{errors.task_id.join("; ")}</div>
) : null}
</div> </div>
<div className={cn("form-group", { "has-error": errors.hours })}> <div className={cn("form-group", { "has-error": errors.hours })}>
<input <input
@ -83,9 +81,7 @@ class Form extends Component {
autoComplete="off" autoComplete="off"
autoFocus autoFocus
/> />
{errors.hours ? ( {errors.hours ? <div className="form-error">{errors.hours.join("; ")}</div> : null}
<div className="form-error">{errors.hours.join("; ")}</div>
) : null}
</div> </div>
<div className={cn("form-group", { "has-error": errors.description })}> <div className={cn("form-group", { "has-error": errors.description })}>
<textarea <textarea

View File

@ -6,10 +6,10 @@ import ApiClient from "api/Client"
@observer @observer
class Options extends Component { class Options extends Component {
@observable subdomain = ""; @observable subdomain = ""
@observable apiKey = ""; @observable apiKey = ""
@observable errorMessage = null; @observable errorMessage = null
@observable isSuccess = false; @observable isSuccess = false
componentDidMount() { componentDidMount() {
getSettings(false).then(({ subdomain, apiKey }) => { getSettings(false).then(({ subdomain, apiKey }) => {
@ -20,7 +20,7 @@ class Options extends Component {
onChange = event => { onChange = event => {
this[event.target.name] = event.target.value.trim() this[event.target.name] = event.target.value.trim()
}; }
handleSubmit = _event => { handleSubmit = _event => {
this.isSuccess = false this.isSuccess = false
@ -30,7 +30,7 @@ class Options extends Component {
const apiClient = new ApiClient({ const apiClient = new ApiClient({
subdomain: this.subdomain, subdomain: this.subdomain,
apiKey: this.apiKey, apiKey: this.apiKey,
version version,
}) })
apiClient apiClient
.login() .login()
@ -39,32 +39,27 @@ class Options extends Component {
this.closeWindow() this.closeWindow()
}) })
.catch(error => { .catch(error => {
this.errorMessage = this.errorMessage = error.response?.data?.message || "Anmeldung fehlgeschlagen"
error.response?.data?.message || "Anmeldung fehlgeschlagen"
}) })
}) })
}; }
handleInputKeyDown = event => { handleInputKeyDown = event => {
if (event.key === "Enter") { if (event.key === "Enter") {
this.handleSubmit() this.handleSubmit()
} }
}; }
closeWindow = () => { closeWindow = () => {
isChrome() && window.close() isChrome() && window.close()
}; }
render() { render() {
return ( return (
<div className="moco-bx-options"> <div className="moco-bx-options">
<h2 style={{ textAlign: "center" }}>Einstellungen</h2> <h2 style={{ textAlign: "center" }}>Einstellungen</h2>
{this.errorMessage && ( {this.errorMessage && <div className="text-danger">{this.errorMessage}</div>}
<div className="text-danger">{this.errorMessage}</div> {this.isSuccess && <div className="text-success">Anmeldung erfolgreich</div>}
)}
{this.isSuccess && (
<div className="text-success">Anmeldung erfolgreich</div>
)}
<div className="form-group"> <div className="form-group">
<label>Internetadresse</label> <label>Internetadresse</label>
<div className="input-group"> <div className="input-group">
@ -88,8 +83,7 @@ class Options extends Component {
onChange={this.onChange} onChange={this.onChange}
/> />
<p className="text-muted"> <p className="text-muted">
Den API-Schlüssel findest du in deinem Profil unter Den API-Schlüssel findest du in deinem Profil unter &quot;Integrationen&quot;.
&quot;Integrationen&quot;.
</p> </p>
</div> </div>
<button className="moco-bx-btn" onClick={this.handleSubmit}> <button className="moco-bx-btn" onClick={this.handleSubmit}>

View File

@ -1,12 +1,7 @@
import React, { Component } from "react" import React, { Component } from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import queryString from "query-string" import queryString from "query-string"
import { import { ERROR_UNKNOWN, ERROR_UNAUTHORIZED, ERROR_UPGRADE_REQUIRED, serializeProps } from "utils"
ERROR_UNKNOWN,
ERROR_UNAUTHORIZED,
ERROR_UPGRADE_REQUIRED,
serializeProps
} from "utils"
import { isChrome } from "utils/browser" import { isChrome } from "utils/browser"
function getStyles(errorType) { function getStyles(errorType) {
@ -21,7 +16,7 @@ function getStyles(errorType) {
: "461px" : "461px"
: errorType === ERROR_UNKNOWN : errorType === ERROR_UNKNOWN
? "550px" ? "550px"
: "558px" : "558px",
} }
} }
@ -29,14 +24,14 @@ class Popup extends Component {
static propTypes = { static propTypes = {
service: PropTypes.object, service: PropTypes.object,
errorType: PropTypes.string, errorType: PropTypes.string,
onRequestClose: PropTypes.func.isRequired onRequestClose: PropTypes.func.isRequired,
}; }
handleRequestClose = event => { handleRequestClose = event => {
if (event.target.classList.contains("moco-bx-popup")) { if (event.target.classList.contains("moco-bx-popup")) {
this.props.onRequestClose() this.props.onRequestClose()
} }
}; }
componentDidMount() { componentDidMount() {
// Document might lose focus when clicking the browser action. // Document might lose focus when clicking the browser action.
@ -64,7 +59,7 @@ class Popup extends Component {
"fromDate", "fromDate",
"toDate", "toDate",
"errorType", "errorType",
"errorMessage" "errorMessage",
])(this.props) ])(this.props)
const styles = getStyles(this.props.errorType) const styles = getStyles(this.props.errorType)
@ -73,9 +68,7 @@ class Popup extends Component {
<div className="moco-bx-popup" onClick={this.handleRequestClose}> <div className="moco-bx-popup" onClick={this.handleRequestClose}>
<div className="moco-bx-popup-content" style={styles}> <div className="moco-bx-popup-content" style={styles}>
<iframe <iframe
src={chrome.extension.getURL( src={chrome.extension.getURL(`popup.html?${queryString.stringify(serializedProps)}`)}
`popup.html?${queryString.stringify(serializedProps)}`
)}
width={styles.width} width={styles.width}
height={styles.height} height={styles.height}
/> />

View File

@ -1,14 +1,14 @@
import React from 'react' import React from "react"
import PropTypes from 'prop-types' import PropTypes from "prop-types"
const Spinner = ({ style }) => ( const Spinner = ({ style }) => (
<div className='moco-bx-spinner__container' style={style}> <div className="moco-bx-spinner__container" style={style}>
<div className='moco-bx-spinner' role='status' /> <div className="moco-bx-spinner" role="status" />
</div> </div>
) )
Spinner.propTypes = { Spinner.propTypes = {
style: PropTypes.object style: PropTypes.object,
} }
export default Spinner export default Spinner

View File

@ -1,20 +1,21 @@
import React from 'react' import React from "react"
import PropTypes from 'prop-types' import PropTypes from "prop-types"
import logoUrl from "images/logo.png" import logoUrl from "images/logo.png"
const Header = ({ subdomain }) => ( const Header = ({ subdomain }) => (
<div className="moco-bx-logo__container"> <div className="moco-bx-logo__container">
<a href={`https://${subdomain}.mocoapp.com/activities`} target="_blank" rel="noopener noreferrer"> <a
<img href={`https://${subdomain}.mocoapp.com/activities`}
className="moco-bx-logo" target="_blank"
src={chrome.extension.getURL(logoUrl)} rel="noopener noreferrer"
/> >
<img className="moco-bx-logo" src={chrome.extension.getURL(logoUrl)} />
</a> </a>
</div> </div>
) )
Header.propTypes = { Header.propTypes = {
subdomain: PropTypes.string subdomain: PropTypes.string,
} }
export default Header export default Header

View File

@ -1,5 +1,5 @@
export default class TimeInputParser { export default class TimeInputParser {
#input; #input
constructor(input) { constructor(input) {
this.#input = input.toLowerCase().replace(/[\s()]/g, "") this.#input = input.toLowerCase().replace(/[\s()]/g, "")
@ -25,11 +25,11 @@ export default class TimeInputParser {
const calculated = hours * 3600 + minutes * 60 const calculated = hours * 3600 + minutes * 60
return isNegative ? -calculated : calculated return isNegative ? -calculated : calculated
}; }
#parseDecimal = () => { #parseDecimal = () => {
return this.#input.replace(/[.,]/g, ".") return this.#input.replace(/[.,]/g, ".")
}; }
#parseTimeAsSeconds = () => { #parseTimeAsSeconds = () => {
const match = this.#isTime() const match = this.#isTime()
@ -39,12 +39,12 @@ export default class TimeInputParser {
const minutes = parseInt(match[3]) const minutes = parseInt(match[3])
return this.#calculateFromHoursAndMinutes(hours, minutes, isNegative) return this.#calculateFromHoursAndMinutes(hours, minutes, isNegative)
}; }
#parseMinutesAsSeconds = () => { #parseMinutesAsSeconds = () => {
const minutes = parseInt(this.#isMinutes()[1]) const minutes = parseInt(this.#isMinutes()[1])
return minutes * 60 return minutes * 60
}; }
#parseRange = () => { #parseRange = () => {
const match = this.#isRange() const match = this.#isRange()
@ -54,7 +54,7 @@ export default class TimeInputParser {
const to_hours = parseInt(match[3]) const to_hours = parseInt(match[3])
const to_minutes = parseInt(match[4]) const to_minutes = parseInt(match[4])
return (to_hours - from_hours) * 3600 + (to_minutes - from_minutes) * 60 return (to_hours - from_hours) * 3600 + (to_minutes - from_minutes) * 60
}; }
#parseHoursAndMinutes = () => { #parseHoursAndMinutes = () => {
const match = this.#isHoursAndMinutes() const match = this.#isHoursAndMinutes()
@ -64,28 +64,26 @@ export default class TimeInputParser {
const minutes = parseInt(match[3]) const minutes = parseInt(match[3])
return this.#calculateFromHoursAndMinutes(hours, minutes, isNegative) return this.#calculateFromHoursAndMinutes(hours, minutes, isNegative)
}; }
#isDecimal = () => { #isDecimal = () => {
return this.#input.match(/^([-]?[0-9]{0,2})[.,]{1}([0-9]{1,2})$/) return this.#input.match(/^([-]?[0-9]{0,2})[.,]{1}([0-9]{1,2})$/)
}; }
#isTime = () => { #isTime = () => {
return this.#input.match(/^([-]?)([0-9]{1,2}):([0-9]{2})$/) return this.#input.match(/^([-]?)([0-9]{1,2}):([0-9]{2})$/)
}; }
#isMinutes = () => { #isMinutes = () => {
return this.#input.match(/^([-]?[0-9]{1,3})(m|mins?)$/) return this.#input.match(/^([-]?[0-9]{1,3})(m|mins?)$/)
}; }
#isRange = () => { #isRange = () => {
return this.#input.match( return this.#input.match(/^([0-9]{1,2})[:.]{0,1}([0-9]{2})-([0-9]{1,2})[:.]{0,1}([0-9]{2})$/)
/^([0-9]{1,2})[:.]{0,1}([0-9]{2})-([0-9]{1,2})[:.]{0,1}([0-9]{2})$/ }
)
};
#isHoursAndMinutes = () => { #isHoursAndMinutes = () => {
// 1h 14m(in) // 1h 14m(in)
return this.#input.match(/^([-]?)([0-9]{1,2})h([0-9]{1,2})(m|mins?)$/) return this.#input.match(/^([-]?)([0-9]{1,2})h([0-9]{1,2})(m|mins?)$/)
}; }
} }

View File

@ -1,14 +1,14 @@
export class BackgroundMessenger { export class BackgroundMessenger {
#ports = new Map(); #ports = new Map()
#handlers = new Map(); #handlers = new Map()
#onceHandlers = new Map(); #onceHandlers = new Map()
#handler = action => { #handler = action => {
const handler = this.#handlers.get(action.type) const handler = this.#handlers.get(action.type)
if (handler) { if (handler) {
handler(action) handler(action)
} }
}; }
#onceHandler = action => { #onceHandler = action => {
const handler = this.#onceHandlers.get(action.type) const handler = this.#onceHandlers.get(action.type)
@ -16,7 +16,7 @@ export class BackgroundMessenger {
if (handler) { if (handler) {
handler(action) handler(action)
} }
}; }
#registerPort = (tabId, port) => { #registerPort = (tabId, port) => {
this.#ports.set(tabId, port) this.#ports.set(tabId, port)
@ -25,14 +25,14 @@ export class BackgroundMessenger {
port.onDisconnect.addListener(() => { port.onDisconnect.addListener(() => {
this.#unregisterPort(tabId, port) this.#unregisterPort(tabId, port)
}) })
}; }
#unregisterPort = (tabId, port) => { #unregisterPort = (tabId, port) => {
port.onMessage.removeListener(this.#handler) port.onMessage.removeListener(this.#handler)
port.onMessage.removeListener(this.#onceHandler) port.onMessage.removeListener(this.#onceHandler)
port.disconnect() port.disconnect()
this.#ports.delete(tabId) this.#ports.delete(tabId)
}; }
connectTab = tab => { connectTab = tab => {
const currentPort = this.#ports.get(tab.id) const currentPort = this.#ports.get(tab.id)
@ -40,41 +40,41 @@ export class BackgroundMessenger {
const port = chrome.tabs.connect(tab.id) const port = chrome.tabs.connect(tab.id)
this.#registerPort(tab.id, port) this.#registerPort(tab.id, port)
} }
}; }
disconnectTab = tabId => { disconnectTab = tabId => {
const port = this.#ports.get(tabId) const port = this.#ports.get(tabId)
if (port) { if (port) {
this.#unregisterPort(tabId, port) this.#unregisterPort(tabId, port)
} }
}; }
postMessage = (tab, action) => { postMessage = (tab, action) => {
const port = this.#ports.get(tab.id) const port = this.#ports.get(tab.id)
if (port) { if (port) {
port.postMessage(action) port.postMessage(action)
} }
}; }
once = (type, handler) => { once = (type, handler) => {
this.#onceHandlers.set(type, handler) this.#onceHandlers.set(type, handler)
}; }
on = (type, handler) => { on = (type, handler) => {
this.#handlers.set(type, handler) this.#handlers.set(type, handler)
}; }
} }
export class ContentMessenger { export class ContentMessenger {
#port; #port
#handlers = new Map(); #handlers = new Map()
#handler = action => { #handler = action => {
const handler = this.#handlers.get(action.type) const handler = this.#handlers.get(action.type)
if (handler) { if (handler) {
handler(action) handler(action)
} }
}; }
constructor(port) { constructor(port) {
this.#port = port this.#port = port
@ -85,15 +85,15 @@ export class ContentMessenger {
if (this.#port) { if (this.#port) {
this.#port.postMessage(action) this.#port.postMessage(action)
} }
}; }
on = (type, handler) => { on = (type, handler) => {
this.#handlers.set(type, handler) this.#handlers.set(type, handler)
}; }
stop = () => { stop = () => {
this.#port.onMessage.removeListener(this.#handler) this.#port.onMessage.removeListener(this.#handler)
this.#port = null this.#port = null
this.#handlers.clear() this.#handlers.clear()
}; }
} }