HackMD/public/js/history.js
Literallie 5b83deb043
Load js-url lib using legacy-loader
Doesn't use eval, plus no window object access
2017-10-22 00:03:45 +02:00

330 lines
8.7 KiB
JavaScript

/* eslint-env browser, jquery */
/* global serverurl, Cookies, moment */
import store from 'store'
import S from 'string'
import {
checkIfAuth
} from './lib/common/login'
import {
urlpath
} from './lib/config'
var jsUrl = require('js-url')
window.migrateHistoryFromTempCallback = null
migrateHistoryFromTemp()
function migrateHistoryFromTemp () {
if (jsUrl('#tempid')) {
$.get(`${serverurl}/temp`, {
tempid: jsUrl('#tempid')
})
.done(data => {
if (data && data.temp) {
getStorageHistory(olddata => {
if (!olddata || olddata.length === 0) {
saveHistoryToStorage(JSON.parse(data.temp))
}
})
}
})
.always(() => {
let hash = location.hash.split('#')[1]
hash = hash.split('&')
for (let i = 0; i < hash.length; i++) {
if (hash[i].indexOf('tempid') === 0) {
hash.splice(i, 1)
i--
}
}
hash = hash.join('&')
location.hash = hash
if (window.migrateHistoryFromTempCallback) { window.migrateHistoryFromTempCallback() }
})
}
}
export function saveHistory (notehistory) {
checkIfAuth(
() => {
saveHistoryToServer(notehistory)
},
() => {
saveHistoryToStorage(notehistory)
}
)
}
function saveHistoryToStorage (notehistory) {
if (store.enabled) { store.set('notehistory', JSON.stringify(notehistory)) } else { saveHistoryToCookie(notehistory) }
}
function saveHistoryToCookie (notehistory) {
Cookies.set('notehistory', notehistory, {
expires: 365
})
}
function saveHistoryToServer (notehistory) {
$.post(`${serverurl}/history`, {
history: JSON.stringify(notehistory)
})
}
export function saveStorageHistoryToServer (callback) {
const data = store.get('notehistory')
if (data) {
$.post(`${serverurl}/history`, {
history: data
})
.done(data => {
callback(data)
})
}
}
export function clearDuplicatedHistory (notehistory) {
const newnotehistory = []
for (let i = 0; i < notehistory.length; i++) {
let found = false
for (let j = 0; j < newnotehistory.length; j++) {
const id = notehistory[i].id.replace(/=+$/, '')
const newId = newnotehistory[j].id.replace(/=+$/, '')
if (id === newId || notehistory[i].id === newnotehistory[j].id || !notehistory[i].id || !newnotehistory[j].id) {
const time = (typeof notehistory[i].time === 'number' ? moment(notehistory[i].time) : moment(notehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'))
const newTime = (typeof newnotehistory[i].time === 'number' ? moment(newnotehistory[i].time) : moment(newnotehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'))
if (time >= newTime) {
newnotehistory[j] = notehistory[i]
}
found = true
break
}
}
if (!found) { newnotehistory.push(notehistory[i]) }
}
return newnotehistory
}
function addHistory (id, text, time, tags, pinned, notehistory) {
// only add when note id exists
if (id) {
notehistory.push({
id,
text,
time,
tags,
pinned
})
}
return notehistory
}
export function removeHistory (id, notehistory) {
for (let i = 0; i < notehistory.length; i++) {
if (notehistory[i].id === id) {
notehistory.splice(i, 1)
i -= 1
}
}
return notehistory
}
// used for inner
export function writeHistory (title, tags) {
checkIfAuth(
() => {
// no need to do this anymore, this will count from server-side
// writeHistoryToServer(title, tags);
},
() => {
writeHistoryToStorage(title, tags)
}
)
}
function writeHistoryToCookie (title, tags) {
var notehistory
try {
notehistory = Cookies.getJSON('notehistory')
} catch (err) {
notehistory = []
}
if (!notehistory) { notehistory = [] }
const newnotehistory = generateHistory(title, tags, notehistory)
saveHistoryToCookie(newnotehistory)
}
function writeHistoryToStorage (title, tags) {
if (store.enabled) {
let data = store.get('notehistory')
var notehistory
if (data) {
if (typeof data === 'string') { data = JSON.parse(data) }
notehistory = data
} else {
notehistory = []
}
if (!notehistory) { notehistory = [] }
const newnotehistory = generateHistory(title, tags, notehistory)
saveHistoryToStorage(newnotehistory)
} else {
writeHistoryToCookie(title, tags)
}
}
if (!Array.isArray) {
Array.isArray = arg => Object.prototype.toString.call(arg) === '[object Array]'
}
function renderHistory (title, tags) {
// console.debug(tags);
const id = urlpath ? location.pathname.slice(urlpath.length + 1, location.pathname.length).split('/')[1] : location.pathname.split('/')[1]
return {
id,
text: title,
time: moment().valueOf(),
tags
}
}
function generateHistory (title, tags, notehistory) {
const info = renderHistory(title, tags)
// keep any pinned data
let pinned = false
for (let i = 0; i < notehistory.length; i++) {
if (notehistory[i].id === info.id && notehistory[i].pinned) {
pinned = true
break
}
}
notehistory = removeHistory(info.id, notehistory)
notehistory = addHistory(info.id, info.text, info.time, info.tags, pinned, notehistory)
notehistory = clearDuplicatedHistory(notehistory)
return notehistory
}
// used for outer
export function getHistory (callback) {
checkIfAuth(
() => {
getServerHistory(callback)
},
() => {
getStorageHistory(callback)
}
)
}
function getServerHistory (callback) {
$.get(`${serverurl}/history`)
.done(data => {
if (data.history) {
callback(data.history)
}
})
.fail((xhr, status, error) => {
console.error(xhr.responseText)
})
}
function getCookieHistory (callback) {
callback(Cookies.getJSON('notehistory'))
}
export function getStorageHistory (callback) {
if (store.enabled) {
let data = store.get('notehistory')
if (data) {
if (typeof data === 'string') { data = JSON.parse(data) }
callback(data)
} else { getCookieHistory(callback) }
} else {
getCookieHistory(callback)
}
}
export function parseHistory (list, callback) {
checkIfAuth(
() => {
parseServerToHistory(list, callback)
},
() => {
parseStorageToHistory(list, callback)
}
)
}
export function parseServerToHistory (list, callback) {
$.get(`${serverurl}/history`)
.done(data => {
if (data.history) {
parseToHistory(list, data.history, callback)
}
})
.fail((xhr, status, error) => {
console.error(xhr.responseText)
})
}
function parseCookieToHistory (list, callback) {
const notehistory = Cookies.getJSON('notehistory')
parseToHistory(list, notehistory, callback)
}
export function parseStorageToHistory (list, callback) {
if (store.enabled) {
let data = store.get('notehistory')
if (data) {
if (typeof data === 'string') { data = JSON.parse(data) }
parseToHistory(list, data, callback)
} else { parseCookieToHistory(list, callback) }
} else {
parseCookieToHistory(list, callback)
}
}
function parseToHistory (list, notehistory, callback) {
if (!callback) return
else if (!list || !notehistory) callback(list, notehistory)
else if (notehistory && notehistory.length > 0) {
for (let i = 0; i < notehistory.length; i++) {
// parse time to timestamp and fromNow
const timestamp = (typeof notehistory[i].time === 'number' ? moment(notehistory[i].time) : moment(notehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'))
notehistory[i].timestamp = timestamp.valueOf()
notehistory[i].fromNow = timestamp.fromNow()
notehistory[i].time = timestamp.format('llll')
// prevent XSS
notehistory[i].text = S(notehistory[i].text).escapeHTML().s
notehistory[i].tags = (notehistory[i].tags && notehistory[i].tags.length > 0) ? S(notehistory[i].tags).escapeHTML().s.split(',') : []
// add to list
if (notehistory[i].id && list.get('id', notehistory[i].id).length === 0) { list.add(notehistory[i]) }
}
}
callback(list, notehistory)
}
export function postHistoryToServer (noteId, data, callback) {
$.post(`${serverurl}/history/${noteId}`, data)
.done(result => callback(null, result))
.fail((xhr, status, error) => {
console.error(xhr.responseText)
return callback(error, null)
})
}
export function deleteServerHistory (noteId, callback) {
$.ajax({
url: `${serverurl}/history${noteId ? '/' + noteId : ''}`,
type: 'DELETE'
})
.done(result => callback(null, result))
.fail((xhr, status, error) => {
console.error(xhr.responseText)
return callback(error, null)
})
}