diff --git a/frontend/common/common.js b/frontend/common/common.js index eda809c3ee..16e31aa221 100644 --- a/frontend/common/common.js +++ b/frontend/common/common.js @@ -22,8 +22,6 @@ // Doing otherwise defeats the purpose of this file and could lead to bugs and conflicts! // You may *add* behavior, but never modify or remove it. -export { default as Vue } from 'vue' -export { default as L } from './translations.js' export * from './translations.js' export * from './errors.js' export * as Errors from './errors.js' diff --git a/frontend/common/translations.js b/frontend/common/translations.js index 67a559ecce..1872c2447f 100644 --- a/frontend/common/translations.js +++ b/frontend/common/translations.js @@ -2,30 +2,12 @@ // since this file is loaded by common.js, we avoid circular imports and directly import import sbp from '@sbp/sbp' -import Vue from 'vue' -import dompurify from 'dompurify' -import { defaultConfig as defaultDompurifyConfig } from './vSafeHtml.js' import template from './stringTemplate.js' -Vue.prototype.L = L -Vue.prototype.LTags = LTags - const defaultLanguage = 'en-US' const defaultLanguageCode = 'en' const defaultTranslationTable: { [string]: string } = {} -/** - * Allow 'href' and 'target' attributes to avoid breaking our hyperlinks, - * but keep sanitizing their values. - * See https://github.com/cure53/DOMPurify#can-i-configure-dompurify - */ -const dompurifyConfig = { - ...defaultDompurifyConfig, - ALLOWED_ATTR: ['class', 'href', 'rel', 'target'], - ALLOWED_TAGS: ['a', 'b', 'br', 'button', 'em', 'i', 'p', 'small', 'span', 'strong', 'sub', 'sup', 'u'], - RETURN_DOM_FRAGMENT: false -} - let currentLanguage = defaultLanguage let currentLanguageCode = defaultLanguage.split('-')[0] let currentTranslationTable = defaultTranslationTable @@ -40,7 +22,7 @@ let currentTranslationTable = defaultTranslationTable * * @see https://tools.ietf.org/rfc/bcp/bcp47.txt */ -sbp('sbp/selectors/register', { +export default (sbp('sbp/selectors/register', { 'translations/init': async function init (language: string): Promise { // A language code is usually the first part of a language tag. const [languageCode] = language.toLowerCase().split('-') @@ -69,7 +51,7 @@ sbp('sbp/selectors/register', { console.error(error) } } -}) +}): string[]) /* Examples: @@ -122,19 +104,22 @@ export function LTags (...tags: string[]): {|br_: string|} { return o } -export default function L ( +export function L ( key: string, args: Array<*> | Object | void ): string { return template(currentTranslationTable[key] || key, args) // Avoid inopportune linebreaks before certain punctuations. - .replace(/\s(?=[;:?!])/g, ' ') + // '\u00a0' is a non-breaking space + // The character is used instead of ` ` or ` ` for conciseness + // and compatibility. + .replace(/\s(?=[;:?!])/g, '\u00a0') } export function LError (error: Error, toGithub?: boolean): {|reportError: any|} { let url = 'https://github.com/okTurtles/group-income/issues' if (!toGithub && sbp('state/vuex/state').loggedIn) { - const baseRoute = document.location.origin + sbp('controller/router').options.base + const baseRoute = sbp('controller/router').options.base url = `${baseRoute}?modal=UserSettingsModal&tab=application-logs&errorMsg=${encodeURIComponent(error.message)}` } return { @@ -145,49 +130,3 @@ export function LError (error: Error, toGithub?: boolean): {|reportError: any|} }) } } - -function sanitize (inputString) { - return dompurify.sanitize(inputString, dompurifyConfig) -} - -Vue.component('i18n', { - functional: true, - props: { - args: [Object, Array], - tag: { - type: String, - default: 'span' - }, - compile: Boolean - }, - render: function (h, context) { - const text = context.children[0].text - const translation = L(text, context.props.args || {}) - if (!translation) { - console.warn('The following i18n text was not translated correctly:', text) - return h(context.props.tag, context.data, text) - } - // Prevent reverse tabnabbing by including `rel="noopener noreferrer"` when rendering as an outbound hyperlink. - if (context.props.tag === 'a' && context.data.attrs.target === '_blank') { - context.data.attrs.rel = 'noopener noreferrer' - } - if (context.props.compile) { - const result = Vue.compile('' + sanitize(translation) + '') - // console.log('TRANSLATED RENDERED TEXT:', context, result.render.toString()) - return result.render.call({ - _c: (tag, ...args) => { - if (tag === 'wrap') { - return h(context.props.tag, context.data, ...args) - } else { - return h(tag, ...args) - } - }, - _v: x => x - }) - } else { - if (!context.data.domProps) context.data.domProps = {} - context.data.domProps.innerHTML = sanitize(translation) - return h(context.props.tag, context.data) - } - } -}) diff --git a/frontend/controller/app/identity.js b/frontend/controller/app/identity.js index 5ee9314d57..c662d80194 100644 --- a/frontend/controller/app/identity.js +++ b/frontend/controller/app/identity.js @@ -1,9 +1,9 @@ 'use strict' -import * as Common from '@common/common.js' import { GIErrorUIRuntimeError, L, LError, LTags } from '@common/common.js' import { cloneDeep } from '@model/contracts/shared/giLodash.js' import sbp from '@sbp/sbp' +import Vue from 'vue' import { LOGIN, LOGIN_COMPLETE, LOGIN_ERROR } from '~/frontend/utils/events.js' import { Secret } from '~/shared/domains/chelonia/Secret.js' import { boxKeyPair, buildRegisterSaltRequest, computeCAndHc, decryptContractSalt, hash, hashPassword, randomNonce } from '~/shared/zkpp.js' @@ -11,8 +11,6 @@ import { boxKeyPair, buildRegisterSaltRequest, computeCAndHc, decryptContractSal import { CURVE25519XSALSA20POLY1305, EDWARDS25519SHA512BATCH, deriveKeyFromPassword, serializeKey } from '../../../shared/domains/chelonia/crypto.js' import { handleFetchResult } from '../utils/misc.js' -const { Vue } = Common - const loadState = async (identityContractID: string, password: ?string) => { if (password) { const stateKeyEncryptionKeyFn = (stateEncryptionKeyId, salt) => { diff --git a/frontend/controller/router.js b/frontend/controller/router.js index 0f2c1ca894..fd87d23877 100644 --- a/frontend/controller/router.js +++ b/frontend/controller/router.js @@ -1,12 +1,13 @@ 'use strict' import sbp from '@sbp/sbp' -import { Vue, L } from '@common/common.js' +import { L } from '@common/common.js' import Router from 'vue-router' import store from '~/frontend/model/state.js' import Home from '@pages/Home.vue' import Join from '@pages/Join.vue' import { lazyPage } from '@utils/lazyLoadedView.js' +import Vue from 'vue' /* * Lazy load all the pages that are not necessary at initial loading of the app. diff --git a/frontend/main.js b/frontend/main.js index b54c7b28d3..32793e9541 100644 --- a/frontend/main.js +++ b/frontend/main.js @@ -1,7 +1,7 @@ 'use strict' // import SBP stuff before anything else so that domains register themselves before called -import * as Common from '@common/common.js' +import { L, LError } from '@common/common.js' import '@model/captureLogs.js' import '@sbp/okturtles.data' import '@sbp/okturtles.eventqueue' @@ -31,10 +31,12 @@ import Modal from './views/components/modal/Modal.vue' import BackgroundSounds from './views/components/sounds/Background.vue' import Navigation from './views/containers/navigation/Navigation.vue' import './views/utils/avatar.js' +import './views/utils/i18n.js' import './views/utils/ui.js' import './views/utils/vError.js' import './views/utils/vFocus.js' // import './views/utils/vSafeHtml.js' // this gets imported by translations, which is part of common.js +import Vue from 'vue' import notificationsMixin from './model/notifications/mainNotificationsMixin.js' import './model/notifications/periodicNotifications.js' import setupChelonia from './setupChelonia.js' @@ -43,8 +45,6 @@ import './utils/touchInteractions.js' import { showNavMixin } from './views/utils/misc.js' import './views/utils/vStyle.js' -const { Vue, L, LError } = Common - console.info('GI_VERSION:', process.env.GI_VERSION) console.info('CONTRACTS_VERSION:', process.env.CONTRACTS_VERSION) console.info('LIGHTWEIGHT_CLIENT:', process.env.LIGHTWEIGHT_CLIENT) diff --git a/frontend/model/chatroom/vuexModule.js b/frontend/model/chatroom/vuexModule.js index 90c1da2d86..79a6c011c1 100644 --- a/frontend/model/chatroom/vuexModule.js +++ b/frontend/model/chatroom/vuexModule.js @@ -1,9 +1,10 @@ 'use strict' import sbp from '@sbp/sbp' -import { Vue } from '@common/common.js' import { merge, cloneDeep, union } from '@model/contracts/shared/giLodash.js' import { MESSAGE_NOTIFY_SETTINGS, CHATROOM_PRIVACY_LEVEL } from '@model/contracts/shared/constants.js' +import Vue from 'vue' + const defaultState = { currentChatRoomIDs: {}, // { [groupId]: currentChatRoomId } pendingChatRoomIDs: {}, // { [groupId]: currentChatRoomId } diff --git a/frontend/model/contracts/shared/voting/proposals.js b/frontend/model/contracts/shared/voting/proposals.js index 860e6dc828..1a6674a7cb 100644 --- a/frontend/model/contracts/shared/voting/proposals.js +++ b/frontend/model/contracts/shared/voting/proposals.js @@ -1,7 +1,6 @@ 'use strict' import sbp from '@sbp/sbp' -import { Vue } from '@common/common.js' import { objectOf, literalOf, unionOf, number } from '~/frontend/model/contracts/misc/flowTyper.js' import { DAYS_MILLIS } from '../time.js' import rules, { ruleType, VOTE_AGAINST, VOTE_FOR, RULE_PERCENTAGE, RULE_DISAGREEMENT } from './rules.js' @@ -27,7 +26,7 @@ export function notifyAndArchiveProposal ({ state, proposalHash, proposal, contr meta: Object, height: number }) { - Vue.delete(state.proposals, proposalHash) + delete state.proposals[proposalHash] // NOTE: we can not make notification for the proposal closal // in the /proposalVote/sideEffect diff --git a/frontend/model/notifications/periodicNotifications.js b/frontend/model/notifications/periodicNotifications.js index b702acdb24..623b36f5a2 100644 --- a/frontend/model/notifications/periodicNotifications.js +++ b/frontend/model/notifications/periodicNotifications.js @@ -1,9 +1,9 @@ 'use strict' import sbp from '@sbp/sbp' -import { Vue } from '@common/common.js' +import Vue from 'vue' // $FlowFixMe -import { objectOf, string, isFunction } from '@model/contracts/misc/flowTyper.js' +import { isFunction, objectOf, string } from '@model/contracts/misc/flowTyper.js' import { MINS_MILLIS } from '@model/contracts/shared/time.js' export const PERIODIC_NOTIFICATION_TYPE = { diff --git a/frontend/model/notifications/vuexModule.js b/frontend/model/notifications/vuexModule.js index 6f9e411776..069812dde4 100644 --- a/frontend/model/notifications/vuexModule.js +++ b/frontend/model/notifications/vuexModule.js @@ -1,6 +1,6 @@ 'use strict' -import { Vue } from '@common/common.js' +import Vue from 'vue' import { cloneDeep } from '~/frontend/model/contracts/shared/giLodash.js' import * as keys from './mutationKeys.js' import './selectors.js' diff --git a/frontend/model/state.js b/frontend/model/state.js index d3891cbbf0..46eac4097c 100644 --- a/frontend/model/state.js +++ b/frontend/model/state.js @@ -4,9 +4,10 @@ // state) per: http://vuex.vuejs.org/en/intro.html import sbp from '@sbp/sbp' -import { Vue, L } from '@common/common.js' +import { L } from '@common/common.js' import { EVENT_HANDLED, CONTRACT_REGISTERED } from '~/shared/domains/chelonia/events.js' import { LOGOUT } from '~/frontend/utils/events.js' +import Vue from 'vue' import Vuex from 'vuex' import { PROFILE_STATUS, INVITE_INITIAL_CREATOR } from '@model/contracts/shared/constants.js' import { PAYMENT_NOT_RECEIVED } from '@model/contracts/shared/payments/index.js' diff --git a/frontend/utils/lazyLoadedView.js b/frontend/utils/lazyLoadedView.js index 72f6618931..3c79c3a9f0 100644 --- a/frontend/utils/lazyLoadedView.js +++ b/frontend/utils/lazyLoadedView.js @@ -1,4 +1,4 @@ -import { Vue } from '@common/common.js' +import Vue from 'vue' import ErrorModal from '@views/containers/loading-error/ErrorModal.vue' import ErrorPage from '@views/containers/loading-error/ErrorPage.vue' import LoadingModal from '@views/containers/loading-error/LoadingModal.vue' diff --git a/frontend/utils/touchInteractions.js b/frontend/utils/touchInteractions.js index 6db84c50ca..955f765a26 100644 --- a/frontend/utils/touchInteractions.js +++ b/frontend/utils/touchInteractions.js @@ -1,4 +1,4 @@ -import { Vue } from '@common/common.js' +import Vue from 'vue' if ('ontouchstart' in window || 'msMaxTouchPoints' in navigator) { import('vue2-touch-events').then(Vue2TouchEvents => Vue.use(Vue2TouchEvents.default)) diff --git a/frontend/views/containers/chatroom/ChatMain.vue b/frontend/views/containers/chatroom/ChatMain.vue index 7ed221ffe0..20c647daf7 100644 --- a/frontend/views/containers/chatroom/ChatMain.vue +++ b/frontend/views/containers/chatroom/ChatMain.vue @@ -122,8 +122,9 @@