init
This commit is contained in:
commit
44f31f8b9f
402 changed files with 47865 additions and 0 deletions
7
plugins/README.md
Normal file
7
plugins/README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
# PLUGINS
|
||||
|
||||
**This directory is not required, you can delete it if you don't want to use it.**
|
||||
|
||||
This directory contains Javascript plugins that you want to run before mounting the root Vue.js application.
|
||||
|
||||
More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/plugins).
|
4
plugins/clipboard.js
Normal file
4
plugins/clipboard.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import Vue from 'vue'
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
|
||||
Vue.use(VueClipboard)
|
25
plugins/detectIPFS.js
Normal file
25
plugins/detectIPFS.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* eslint-disable no-console */
|
||||
export default ({ store, isHMR, app }, inject) => {
|
||||
inject('isLoadedFromIPFS', main)
|
||||
}
|
||||
function main() {
|
||||
const domainWhiteList = [
|
||||
'tornado.cash',
|
||||
'localhost:3000',
|
||||
'stage.tornado.cash',
|
||||
'tornadocash.eth',
|
||||
'tornadocash.eth.link',
|
||||
'tornadocash.eth.limo',
|
||||
'app.tornado.cash',
|
||||
'donotshare.tornado.cash'
|
||||
]
|
||||
|
||||
if (window.location.host.includes('tornadocash.netlify.app')) {
|
||||
return false
|
||||
} else if (!domainWhiteList.includes(window.location.host)) {
|
||||
console.warn('The page has been loaded from ipfs.io. LocalStorage is disabled')
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
173
plugins/i18n.js
Normal file
173
plugins/i18n.js
Normal file
|
@ -0,0 +1,173 @@
|
|||
import Vue from 'vue'
|
||||
import VueI18n from 'vue-i18n'
|
||||
import messages from '../langs/index'
|
||||
import { LOCALES_NAMES } from '@/constants'
|
||||
|
||||
Vue.use(VueI18n)
|
||||
|
||||
let lang = 'en'
|
||||
|
||||
if (process.browser) {
|
||||
const locale = localStorage.getItem('lang') || navigator.language.substr(0, 2).toLowerCase()
|
||||
lang = !messages[locale] ? 'en' : locale
|
||||
}
|
||||
|
||||
const dateTimeFormats = {
|
||||
en: {
|
||||
long: {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
weekday: 'long',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: true
|
||||
}
|
||||
},
|
||||
es: {
|
||||
long: {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
}
|
||||
},
|
||||
fr: {
|
||||
long: {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
}
|
||||
},
|
||||
ru: {
|
||||
long: {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
}
|
||||
},
|
||||
tr: {
|
||||
long: {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
}
|
||||
},
|
||||
uk: {
|
||||
long: {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric'
|
||||
}
|
||||
},
|
||||
zh: {
|
||||
long: {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
weekday: 'long',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const numberFormats = {
|
||||
en: {
|
||||
compact: {
|
||||
notation: 'compact'
|
||||
}
|
||||
},
|
||||
es: {
|
||||
compact: {
|
||||
notation: 'compact'
|
||||
}
|
||||
},
|
||||
fr: {
|
||||
compact: {
|
||||
notation: 'compact'
|
||||
}
|
||||
},
|
||||
ru: {
|
||||
compact: {
|
||||
notation: 'compact'
|
||||
}
|
||||
},
|
||||
tr: {
|
||||
compact: {
|
||||
notation: 'compact'
|
||||
}
|
||||
},
|
||||
uk: {
|
||||
compact: {
|
||||
notation: 'compact'
|
||||
}
|
||||
},
|
||||
zh: {
|
||||
compact: {
|
||||
notation: 'compact'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function slavicPluralization(choice, choicesLength) {
|
||||
/**
|
||||
* @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
|
||||
* @param choicesLength {number} an overall amount of available choices
|
||||
* @returns a final choice index to select plural word by
|
||||
*/
|
||||
|
||||
if (choice === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const teen = choice > 10 && choice < 20
|
||||
const endsWithOne = choice % 10 === 1
|
||||
|
||||
if (choicesLength < 4) {
|
||||
return !teen && endsWithOne ? 1 : 2
|
||||
}
|
||||
if (!teen && endsWithOne) {
|
||||
return 1
|
||||
}
|
||||
if (!teen && choice % 10 >= 2 && choice % 10 <= 4) {
|
||||
return 2
|
||||
}
|
||||
|
||||
return choicesLength < 4 ? 2 : 3
|
||||
}
|
||||
|
||||
const pluralizationRules = {
|
||||
ru: slavicPluralization,
|
||||
uk: slavicPluralization
|
||||
}
|
||||
|
||||
// Create VueI18n instance with options
|
||||
export default ({ app, route, store }) => {
|
||||
app.i18n = new VueI18n({
|
||||
locale: lang,
|
||||
fallbackLocale: 'en',
|
||||
messages,
|
||||
silentFallbackWarn: true,
|
||||
dateTimeFormats,
|
||||
numberFormats,
|
||||
pluralizationRules
|
||||
})
|
||||
|
||||
if (lang === 'zh') {
|
||||
lang += '-cn'
|
||||
}
|
||||
|
||||
app.$moment.locale(lang)
|
||||
app.$numbro.setLanguage(LOCALES_NAMES[lang])
|
||||
}
|
283
plugins/idb.js
Normal file
283
plugins/idb.js
Normal file
|
@ -0,0 +1,283 @@
|
|||
import { openDB, deleteDB } from 'idb'
|
||||
|
||||
import networkConfig from '@/networkConfig'
|
||||
import { INDEX_DB_ERROR, NETWORKS } from '@/constants'
|
||||
|
||||
// TODO method for migration, remove indexed
|
||||
class IndexedDB {
|
||||
constructor({ stores, dbName }) {
|
||||
this.dbExists = false
|
||||
this.isBlocked = false
|
||||
|
||||
this.options = {
|
||||
upgrade(db) {
|
||||
Object.values(db.objectStoreNames).forEach((value) => {
|
||||
db.deleteObjectStore(value)
|
||||
})
|
||||
|
||||
stores.forEach(({ name, keyPath, indexes }) => {
|
||||
const store = db.createObjectStore(name, {
|
||||
keyPath,
|
||||
autoIncrement: true
|
||||
})
|
||||
|
||||
if (Array.isArray(indexes)) {
|
||||
indexes.forEach(({ name, unique = false }) => {
|
||||
store.createIndex(name, name, { unique })
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.dbName = dbName
|
||||
}
|
||||
|
||||
async initDB() {
|
||||
try {
|
||||
if (this.dbExists) {
|
||||
return
|
||||
}
|
||||
|
||||
this.db = await openDB(this.dbName, 31, this.options) // version (optional): Schema version, or undefined to open the current version.
|
||||
this.onEventHandler()
|
||||
|
||||
this.dbExists = true
|
||||
} catch (err) {
|
||||
// need for private mode firefox browser
|
||||
if (err.message.includes(INDEX_DB_ERROR)) {
|
||||
this.isBlocked = true
|
||||
return
|
||||
}
|
||||
|
||||
if (err.message.includes('less than the existing version')) {
|
||||
await this._removeExist()
|
||||
}
|
||||
|
||||
console.error(`Method initDB has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
onEventHandler() {
|
||||
this.db.addEventListener('onupgradeneeded', async () => {
|
||||
await this._removeExist()
|
||||
})
|
||||
}
|
||||
|
||||
async _removeExist() {
|
||||
await deleteDB(this.dbName)
|
||||
this.dbExists = false
|
||||
|
||||
await this.initDB()
|
||||
}
|
||||
|
||||
async getFromIndex(params) {
|
||||
if (this.isBlocked) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
return await this._getFromIndex(params)
|
||||
} catch (err) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
async _getFromIndex({ storeName, indexName, key }) {
|
||||
try {
|
||||
const value = await this.db.getFromIndex(storeName, indexName, key)
|
||||
return value
|
||||
} catch (err) {
|
||||
throw new Error(`Method getFromIndex has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async getAllFromIndex(params) {
|
||||
if (this.isBlocked) {
|
||||
return []
|
||||
}
|
||||
|
||||
try {
|
||||
return await this._getAllFromIndex(params)
|
||||
} catch (err) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async _getAllFromIndex({ storeName, indexName, key, count }) {
|
||||
try {
|
||||
const value = await this.db.getAllFromIndex(storeName, indexName, key, count)
|
||||
return value
|
||||
} catch (err) {
|
||||
throw new Error(`Method getAllFromIndex has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async getItem({ storeName, key }) {
|
||||
try {
|
||||
const store = this.db.transaction(storeName).objectStore(storeName)
|
||||
|
||||
const value = await store.get(key)
|
||||
return value
|
||||
} catch (err) {
|
||||
throw new Error(`Method getItem has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async addItem({ storeName, data, key = '' }) {
|
||||
try {
|
||||
const tx = this.db.transaction(storeName, 'readwrite')
|
||||
const isExist = await tx.objectStore(storeName).get(key)
|
||||
|
||||
if (!isExist) {
|
||||
await tx.objectStore(storeName).add(data)
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(`Method addItem has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async putItem({ storeName, data }) {
|
||||
try {
|
||||
const tx = this.db.transaction(storeName, 'readwrite')
|
||||
await tx.objectStore(storeName).put(data)
|
||||
} catch (err) {
|
||||
throw new Error(`Method putItem has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async getAll({ storeName }) {
|
||||
try {
|
||||
const tx = this.db.transaction(storeName, 'readonly')
|
||||
const store = tx.objectStore(storeName)
|
||||
|
||||
const data = await store.getAll()
|
||||
return data
|
||||
} catch (err) {
|
||||
throw new Error(`Method getAll has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async clearStore({ storeName, mode = 'readwrite' }) {
|
||||
try {
|
||||
const tx = this.db.transaction(storeName, mode)
|
||||
|
||||
await tx.objectStore(storeName).clear()
|
||||
} catch (err) {
|
||||
throw new Error(`Method clearStore has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async createTransactions({ storeName, data, mode = 'readwrite' }) {
|
||||
try {
|
||||
const tx = this.db.transaction(storeName, mode)
|
||||
|
||||
await tx.objectStore(storeName).add(data)
|
||||
await tx.done
|
||||
} catch (err) {
|
||||
throw new Error(`Method createTransactions has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
createMultipleTransactions({ storeName, data, index, mode = 'readwrite' }) {
|
||||
try {
|
||||
const tx = this.db.transaction(storeName, mode)
|
||||
|
||||
data.map((item) => {
|
||||
if (item) {
|
||||
tx.store.put({ ...item, ...index })
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
throw new Error(`Method createMultipleTransactions has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default async (ctx, inject) => {
|
||||
const DEPOSIT_INDEXES = [
|
||||
{ name: 'instance', unique: false },
|
||||
{ name: 'transactionHash', unique: false },
|
||||
{ name: 'commitment', unique: true }
|
||||
]
|
||||
const WITHDRAWAL_INDEXES = [
|
||||
{ name: 'instance', unique: false },
|
||||
{ name: 'nullifierHash', unique: true } // keys on which the index is created
|
||||
]
|
||||
const LAST_EVENT_INDEXES = [{ name: 'name', unique: false }]
|
||||
|
||||
// TODO: generate from config
|
||||
const defaultState = [
|
||||
{
|
||||
name: 'encrypted_events',
|
||||
keyPath: 'transactionHash'
|
||||
},
|
||||
{
|
||||
name: 'withdrawals',
|
||||
keyPath: 'transactionHash',
|
||||
indexes: WITHDRAWAL_INDEXES
|
||||
},
|
||||
{
|
||||
name: 'lastEvents',
|
||||
keyPath: 'name',
|
||||
indexes: LAST_EVENT_INDEXES
|
||||
}
|
||||
]
|
||||
|
||||
const stores = [
|
||||
{
|
||||
name: 'register_events',
|
||||
keyPath: 'ensName'
|
||||
}
|
||||
]
|
||||
|
||||
NETWORKS.forEach((netId) => {
|
||||
defaultState.map((item) => {
|
||||
stores.push({
|
||||
...item,
|
||||
name: `${item.name}_${netId}`
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Object.keys(networkConfig).forEach((key) => {
|
||||
const { tokens, nativeCurrency } = networkConfig[key]
|
||||
|
||||
const netId = key.replace('netId', '')
|
||||
|
||||
Object.keys(tokens).forEach((token) => {
|
||||
Object.keys(tokens[token].instanceAddress).forEach((amount) => {
|
||||
if (nativeCurrency === token) {
|
||||
// ToDo make good)
|
||||
stores.push({
|
||||
name: `stringify_bloom_${token}_${amount}_${netId}`,
|
||||
keyPath: 'hashBloom'
|
||||
})
|
||||
}
|
||||
|
||||
stores.push({
|
||||
name: `deposits_${token}_${amount}_${netId}`,
|
||||
keyPath: 'leafIndex', // the key by which it refers to the object must be in all instances of the storage
|
||||
indexes: DEPOSIT_INDEXES
|
||||
})
|
||||
|
||||
stores.push({
|
||||
name: `stringify_tree_${token}_${amount}_${netId}`,
|
||||
keyPath: 'hashTree'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const options = {
|
||||
stores,
|
||||
dbName: 'tornado_cash'
|
||||
}
|
||||
|
||||
const instance = new IndexedDB(options)
|
||||
|
||||
await instance.initDB()
|
||||
|
||||
ctx.$indexedDB = instance
|
||||
inject('indexedDB', instance)
|
||||
}
|
17
plugins/ipfs.js
Normal file
17
plugins/ipfs.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* eslint-disable camelcase, no-undef */
|
||||
export default (context, inject) => {
|
||||
const ipfsPathRegExp = /^(\/(?:ipfs|ipns)\/[^/]+)/
|
||||
const ipfsPathPrefix = (window.location.pathname.match(ipfsPathRegExp) || [])[1] || ''
|
||||
|
||||
console.log('plugin __webpack_public_path__', __webpack_public_path__)
|
||||
|
||||
if (ipfsPathPrefix) {
|
||||
__webpack_public_path__ = ipfsPathPrefix + '/_nuxt/'
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
context.app.router.history.base = ipfsPathPrefix || window.location.host
|
||||
}
|
||||
}
|
||||
|
||||
console.log('plugin __webpack_public_path__', __webpack_public_path__)
|
||||
}
|
36
plugins/localStorage.js
Normal file
36
plugins/localStorage.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* eslint-disable no-console */
|
||||
// ~/plugins/localStorage.js
|
||||
import createPersistedState from 'vuex-persistedstate'
|
||||
|
||||
import { isStorageAvailable } from '@/utils'
|
||||
|
||||
const { OLD_STORE_NAME, STORE_NAME = 'tornadoClassicV2' } = process.env
|
||||
|
||||
function migrate() {
|
||||
if (isStorageAvailable('localStorage') && OLD_STORE_NAME !== STORE_NAME) {
|
||||
const oldStore = localStorage[OLD_STORE_NAME]
|
||||
if (oldStore) {
|
||||
localStorage.setItem(STORE_NAME, oldStore)
|
||||
localStorage.removeItem(OLD_STORE_NAME)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ({ store, isHMR }) => {
|
||||
if (isHMR) {
|
||||
return
|
||||
}
|
||||
|
||||
const paths = ['metamask.netId', 'application.selectedStatistic', 'application.selectedInstance']
|
||||
|
||||
if (!store.$isLoadedFromIPFS()) {
|
||||
paths.push('txHashKeeper', 'settings', 'account', 'relayer.jobs', 'encryptedNote.ui')
|
||||
}
|
||||
|
||||
migrate()
|
||||
|
||||
createPersistedState({
|
||||
key: STORE_NAME,
|
||||
paths
|
||||
})(store)
|
||||
}
|
5
plugins/numbro/languages/index.js
Normal file
5
plugins/numbro/languages/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import ru from './ru'
|
||||
import uk from './uk'
|
||||
import zh from './zh'
|
||||
|
||||
export const locales = [ru, uk, zh]
|
53
plugins/numbro/languages/ru.js
Normal file
53
plugins/numbro/languages/ru.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
module.exports = {
|
||||
languageTag: 'ru-RU',
|
||||
delimiters: {
|
||||
thousands: ' ',
|
||||
decimal: ','
|
||||
},
|
||||
abbreviations: {
|
||||
thousand: 'k',
|
||||
million: 'm',
|
||||
billion: 'b',
|
||||
trillion: 't'
|
||||
},
|
||||
ordinal() {
|
||||
// not ideal, but since in Russian it can taken on
|
||||
// different forms (masculine, feminine, neuter)
|
||||
// this is all we can do
|
||||
return '.'
|
||||
},
|
||||
currency: {
|
||||
symbol: 'руб.',
|
||||
position: 'postfix',
|
||||
code: 'RUB'
|
||||
},
|
||||
currencyFormat: {
|
||||
thousandSeparated: true,
|
||||
totalLength: 4,
|
||||
spaceSeparated: true,
|
||||
average: true
|
||||
},
|
||||
formats: {
|
||||
fourDigits: {
|
||||
totalLength: 4,
|
||||
spaceSeparated: true,
|
||||
average: true
|
||||
},
|
||||
fullWithTwoDecimals: {
|
||||
output: 'currency',
|
||||
mantissa: 2,
|
||||
spaceSeparated: true,
|
||||
thousandSeparated: true
|
||||
},
|
||||
fullWithTwoDecimalsNoCurrency: {
|
||||
mantissa: 2,
|
||||
thousandSeparated: true
|
||||
},
|
||||
fullWithNoDecimals: {
|
||||
output: 'currency',
|
||||
spaceSeparated: true,
|
||||
thousandSeparated: true,
|
||||
mantissa: 0
|
||||
}
|
||||
}
|
||||
}
|
53
plugins/numbro/languages/uk.js
Normal file
53
plugins/numbro/languages/uk.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
module.exports = {
|
||||
languageTag: 'uk-UA',
|
||||
delimiters: {
|
||||
thousands: ' ',
|
||||
decimal: ','
|
||||
},
|
||||
abbreviations: {
|
||||
thousand: 'k',
|
||||
million: 'm',
|
||||
billion: 'b',
|
||||
trillion: 't'
|
||||
},
|
||||
ordinal: () => {
|
||||
// not ideal, but since in Ukrainian it can taken on
|
||||
// different forms (masculine, feminine, neuter)
|
||||
// this is all we can do
|
||||
return ''
|
||||
},
|
||||
currency: {
|
||||
symbol: '\u20B4',
|
||||
position: 'postfix',
|
||||
code: 'UAH'
|
||||
},
|
||||
currencyFormat: {
|
||||
thousandSeparated: true,
|
||||
totalLength: 4,
|
||||
spaceSeparated: true,
|
||||
average: true
|
||||
},
|
||||
formats: {
|
||||
fourDigits: {
|
||||
totalLength: 4,
|
||||
spaceSeparated: true,
|
||||
average: true
|
||||
},
|
||||
fullWithTwoDecimals: {
|
||||
output: 'currency',
|
||||
mantissa: 2,
|
||||
spaceSeparated: true,
|
||||
thousandSeparated: true
|
||||
},
|
||||
fullWithTwoDecimalsNoCurrency: {
|
||||
mantissa: 2,
|
||||
thousandSeparated: true
|
||||
},
|
||||
fullWithNoDecimals: {
|
||||
output: 'currency',
|
||||
spaceSeparated: true,
|
||||
thousandSeparated: true,
|
||||
mantissa: 0
|
||||
}
|
||||
}
|
||||
}
|
47
plugins/numbro/languages/zh.js
Normal file
47
plugins/numbro/languages/zh.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
module.exports = {
|
||||
languageTag: 'zh-CN',
|
||||
delimiters: {
|
||||
thousands: ',',
|
||||
decimal: '.'
|
||||
},
|
||||
abbreviations: {
|
||||
thousand: '千',
|
||||
million: '百万',
|
||||
billion: '十亿',
|
||||
trillion: '兆'
|
||||
},
|
||||
ordinal() {
|
||||
return '.'
|
||||
},
|
||||
currency: {
|
||||
symbol: '¥',
|
||||
position: 'prefix',
|
||||
code: 'CNY'
|
||||
},
|
||||
currencyFormat: {
|
||||
thousandSeparated: true,
|
||||
totalLength: 4,
|
||||
spaceSeparated: true,
|
||||
average: true
|
||||
},
|
||||
formats: {
|
||||
fourDigits: {
|
||||
totalLength: 4,
|
||||
spaceSeparated: true,
|
||||
average: true
|
||||
},
|
||||
fullWithTwoDecimals: {
|
||||
thousandSeparated: true,
|
||||
mantissa: 2
|
||||
},
|
||||
fullWithTwoDecimalsNoCurrency: {
|
||||
mantissa: 2,
|
||||
thousandSeparated: true
|
||||
},
|
||||
fullWithNoDecimals: {
|
||||
output: 'currency',
|
||||
thousandSeparated: true,
|
||||
mantissa: 0
|
||||
}
|
||||
}
|
||||
}
|
10
plugins/numbro/numbro.js
Normal file
10
plugins/numbro/numbro.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import numbro from 'numbro'
|
||||
import { locales } from './languages'
|
||||
|
||||
export default (ctx, inject) => {
|
||||
locales.forEach((lang) => {
|
||||
numbro.registerLanguage(lang)
|
||||
})
|
||||
ctx.$numbro = numbro
|
||||
inject('numbro', numbro)
|
||||
}
|
36
plugins/preventMultitabs.js
Normal file
36
plugins/preventMultitabs.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* eslint-disable no-console */
|
||||
export default ({ store, isHMR, app }, inject) => {
|
||||
inject('preventMultitabs', main)
|
||||
}
|
||||
function main(store) {
|
||||
const id = Date.now()
|
||||
window.id = id
|
||||
window.localStorage.setItem('firstTab', id)
|
||||
|
||||
const onLocalStorageEvent = function(e) {
|
||||
// the second tab will write its id to this key. The first one will notice it
|
||||
if (e.key === 'firstTab') {
|
||||
const newID = Date.now()
|
||||
console.log('Another tab detected. Setting the new page id', newID)
|
||||
setTimeout(() => {
|
||||
window.localStorage.secondTab = newID // this is going to be a message for the second tab
|
||||
}, 200)
|
||||
}
|
||||
|
||||
// the second tab proccesses the message
|
||||
if (e.key === 'secondTab' && window.id.toString() === window.localStorage.firstTab) {
|
||||
console.log('There is another tab that already opened. We will close this one')
|
||||
window.multipleTabsDetected = true
|
||||
window.onbeforeunload = null
|
||||
window.alert(
|
||||
'Multiple tabs opened. Your page will be closed. Please only use single instance of https://tornado.cash'
|
||||
)
|
||||
window.location = 'https://twitter.com/tornadocash'
|
||||
}
|
||||
}
|
||||
|
||||
// this event will only trigger when a window other than itself makes changes to local storage.
|
||||
setTimeout(() => {
|
||||
window.addEventListener('storage', onLocalStorageEvent, false)
|
||||
}, 100)
|
||||
}
|
76
plugins/sessionStorage.js
Normal file
76
plugins/sessionStorage.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
import { soliditySha3 } from 'web3-utils'
|
||||
|
||||
let isSessionStorageEnabled = null
|
||||
|
||||
try {
|
||||
window.sessionStorage.setItem('test', 'test')
|
||||
window.sessionStorage.removeItem('test')
|
||||
isSessionStorageEnabled = true
|
||||
} catch (e) {
|
||||
isSessionStorageEnabled = false
|
||||
}
|
||||
|
||||
const setItem = (key, value) => {
|
||||
if (isSessionStorageEnabled) {
|
||||
window.sessionStorage.setItem(
|
||||
soliditySha3(key),
|
||||
JSON.stringify({
|
||||
data: value,
|
||||
timeStamp: Date.now()
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const getItem = (key) => {
|
||||
if (isSessionStorageEnabled) {
|
||||
const value = window.sessionStorage.getItem(soliditySha3(key))
|
||||
|
||||
try {
|
||||
return JSON.parse(String(value))
|
||||
} catch (err) {
|
||||
return value
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
const removeItem = (key) => {
|
||||
if (isSessionStorageEnabled) {
|
||||
return window.sessionStorage.removeItem(soliditySha3(key))
|
||||
}
|
||||
}
|
||||
|
||||
const clear = () => {
|
||||
if (isSessionStorageEnabled) {
|
||||
window.sessionStorage.clear()
|
||||
}
|
||||
}
|
||||
|
||||
const subscribe = (key, originalListener) => {
|
||||
const listener = (event) => {
|
||||
if (event.storageArea === window.sessionStorage && event.key === key) {
|
||||
originalListener(event.newValue, event.oldValue)
|
||||
}
|
||||
}
|
||||
window.addEventListener('storage', listener, false)
|
||||
return listener
|
||||
}
|
||||
|
||||
const unsubscribe = (listener) => {
|
||||
window.removeEventListener('storage', listener, false)
|
||||
}
|
||||
|
||||
export default (ctx, inject) => {
|
||||
const sessionStorage = {
|
||||
setItem,
|
||||
getItem,
|
||||
removeItem,
|
||||
clear,
|
||||
subscribe,
|
||||
unsubscribe
|
||||
}
|
||||
|
||||
ctx.$sessionStorage = sessionStorage
|
||||
inject('sessionStorage', sessionStorage)
|
||||
}
|
4
plugins/vidle.js
Normal file
4
plugins/vidle.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import Vue from 'vue'
|
||||
import Vidle from 'v-idle'
|
||||
|
||||
Vue.use(Vidle)
|
Loading…
Add table
Add a link
Reference in a new issue