marktext/src/main/preference.js
Ran Luo a41f751f2f update or notice file changed on disk (#796)
* update or notice file changed on disk

* update changelog

* fix some typo and optimize some codes
2019-03-26 13:40:51 +01:00

167 lines
4.8 KiB
JavaScript

import fs from 'fs'
import path from 'path'
import { ipcMain, BrowserWindow } from 'electron'
import { isOsx } from './config'
import appWindow from './window'
import { getPath, hasSameKeys, log, ensureDir } from './utils'
class Preference {
constructor () {
const FILE_NAME = 'preference.md'
const staticPath = path.join(__static, FILE_NAME)
const userDataPath = path.join(getPath('userData'), FILE_NAME)
this.cache = null
this.staticPath = staticPath
this.userDataPath = userDataPath
this.init()
}
init () {
const { userDataPath, staticPath } = this
const defaultSettings = this.loadJson(staticPath)
let userSetting = null
// Try to load settings or write default settings if file doesn't exists.
if (!fs.existsSync(userDataPath) || !this.loadJson(userDataPath)) {
ensureDir(getPath('userData'))
const content = fs.readFileSync(staticPath, 'utf-8')
fs.writeFileSync(userDataPath, content, 'utf-8')
userSetting = this.loadJson(userDataPath)
this.validateSettings(userSetting)
} else {
userSetting = this.loadJson(userDataPath)
this.validateSettings(userSetting)
// Update outdated settings
const requiresUpdate = !hasSameKeys(defaultSettings, userSetting)
if (requiresUpdate) {
// remove outdated settings
for (const key in userSetting) {
if (userSetting.hasOwnProperty(key) && !defaultSettings.hasOwnProperty(key)) {
delete userSetting[key]
}
}
// add new setting options
for (const key in defaultSettings) {
if (defaultSettings.hasOwnProperty(key) && !userSetting.hasOwnProperty(key)) {
userSetting[key] = defaultSettings[key]
}
}
this.writeJson(userSetting, false)
.catch(log)
}
}
if (!userSetting) {
console.error('ERROR: Cannot load settings.')
userSetting = defaultSettings
this.validateSettings(userSetting)
}
this.cache = userSetting
}
getAll () {
return this.cache
}
setItem (key, value) {
const preUserSetting = this.getAll()
const newUserSetting = this.cache = Object.assign({}, preUserSetting, { [key]: value })
return this.writeJson(newUserSetting)
}
loadJson (filePath) {
const JSON_REG = /```json(.+)```/g
try {
const content = fs.readFileSync(filePath, 'utf-8')
const userSetting = JSON_REG.exec(content.replace(/(?:\r\n|\n)/g, ''))[1]
return JSON.parse(userSetting)
} catch (err) {
log(err)
return null
}
}
writeJson (json, async = true) {
const { userDataPath } = this
return new Promise((resolve, reject) => {
const content = fs.readFileSync(userDataPath, 'utf-8')
const tokens = content.split('```')
const newContent = tokens[0] +
'```json\n' +
JSON.stringify(json, null, 2) +
'\n```' +
tokens[2]
if (async) {
fs.writeFile(userDataPath, newContent, 'utf-8', err => {
if (err) reject(err)
else resolve(json)
})
} else {
fs.writeFileSync(userDataPath, newContent, 'utf-8')
resolve(json)
}
})
}
/**
* workaround for issue #265
* expects: settings != null
* @param {Object} settings preferences object
*/
validateSettings (settings) {
if (!settings) {
log('Broken settings detected: invalid settings object.')
return
}
let brokenSettings = false
if (!settings.theme || (settings.theme && !/^(dark|light)$/.test(settings.theme))) {
brokenSettings = true
settings.theme = 'light'
}
if (!settings.bulletListMarker ||
(settings.bulletListMarker && !/^(\+|-|\*)$/.test(settings.bulletListMarker))) {
brokenSettings = true
settings.bulletListMarker = '-'
}
if (!settings.titleBarStyle || !/^(native|csd|custom)$/.test(settings.titleBarStyle)) {
settings.titleBarStyle = 'csd'
}
if (brokenSettings) {
log('Broken settings detected; fallback to default value(s).')
}
// Currently no CSD is available on Linux and Windows (GH#690)
const titleBarStyle = settings.titleBarStyle.toLowerCase()
if (!isOsx && titleBarStyle === 'csd') {
settings.titleBarStyle = 'custom'
}
}
}
const preference = new Preference()
ipcMain.on('AGANI::ask-for-user-preference', e => {
const win = BrowserWindow.fromWebContents(e.sender)
win.webContents.send('AGANI::user-preference', preference.getAll())
})
ipcMain.on('AGANI::set-user-preference', (e, pre) => {
Object.keys(pre).map(key => {
preference.setItem(key, pre[key])
.then(() => {
for (const { win } of appWindow.windows.values()) {
win.webContents.send('AGANI::user-preference', { [key]: pre[key] })
}
})
.catch(log)
})
})
export default preference