'use strict'; const markdown = require('./markdown.js'); const uri = require('./uri.js'); const settings = require('../models/settings.js'); function decamelize(str, sep) { sep = sep === undefined ? '-' : sep; return str .replace(/([a-z\d])([A-Z])/g, '$1' + sep + '$2') .replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + sep + '$2') .toLowerCase(); } function *range(start = 0, end = null, step = 1) { if (end === null) { end = start; start = 0; } for (let i = start; i < end; i += step) { yield i; } } function _formatUnits(number, base, suffixes, callback) { if (!number && number !== 0) { return NaN; } number *= 1.0; let suffix = suffixes.shift(); while (number >= base && suffixes.length > 0) { suffix = suffixes.shift(); number /= base; } if (callback === undefined) { callback = (number, suffix) => { return suffix ? number.toFixed(1) + suffix : number; }; } return callback(number, suffix); } function formatFileSize(fileSize) { return _formatUnits( fileSize, 1024, ['B', 'K', 'M', 'G'], (number, suffix) => { const decimalPlaces = number < 20 && suffix !== 'B' ? 1 : 0; return number.toFixed(decimalPlaces) + suffix; }); } function formatRelativeTime(timeString) { if (!timeString) { return 'never'; } const then = Date.parse(timeString); const now = Date.now(); const difference = Math.abs(now - then) / 1000.0; const future = now < then; const descriptions = [ [60, 'a few seconds', null], [60 * 2, 'a minute', null], [60 * 60, '% minutes', 60], [60 * 60 * 2, 'an hour', null], [60 * 60 * 24, '% hours', 60 * 60], [60 * 60 * 24 * 2, 'a day', null], [60 * 60 * 24 * 30.42, '% days', 60 * 60 * 24], [60 * 60 * 24 * 30.42 * 2, 'a month', null], [60 * 60 * 24 * 30.42 * 12, '% months', 60 * 60 * 24 * 30.42], [60 * 60 * 24 * 30.42 * 12 * 2, 'a year', null], [8640000000000000 /* max*/, '% years', 60 * 60 * 24 * 30.42 * 12], ]; let text = null; for (let kv of descriptions) { const multiplier = kv[0]; const template = kv[1]; const divider = kv[2]; if (difference < multiplier) { text = template.replace(/%/, Math.round(difference / divider)); break; } } if (text === 'a day') { return future ? 'tomorrow' : 'yesterday'; } return future ? 'in ' + text : text + ' ago'; } function formatMarkdown(text) { return markdown.formatMarkdown(text); } function formatInlineMarkdown(text) { return markdown.formatInlineMarkdown(text); } function splitByWhitespace(str) { return str.split(/\s+/).filter(s => s); } function unindent(callSite, ...args) { function format(str) { let size = -1; return str.replace(/\n(\s+)/g, (m, m1) => { if (size < 0) { size = m1.replace(/\t/g, ' ').length; } return '\n' + m1.slice(Math.min(m1.length, size)); }); } if (typeof callSite === 'string') { return format(callSite); } if (typeof callSite === 'function') { return (...args) => format(callSite(...args)); } let output = callSite .slice(0, args.length + 1) .map((text, i) => (i === 0 ? '' : args[i - 1]) + text) .join(''); return format(output); } function enableExitConfirmation() { window.onbeforeunload = e => { return 'Are you sure you want to leave? ' + 'Data you have entered may not be saved.'; }; } function disableExitConfirmation() { window.onbeforeunload = null; } function confirmPageExit() { if (!window.onbeforeunload) { return true; } if (window.confirm(window.onbeforeunload())) { disableExitConfirmation(); return true; } } function makeCssName(text, suffix) { return suffix + '-' + text.replace(/[^a-z0-9]/g, '_'); } function escapeHtml(unsafe) { return unsafe.toString() .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function arraysDiffer(source1, source2, orderImportant) { source1 = [...source1]; source2 = [...source2]; if (orderImportant === true) { if (source1.length !== source2.length) { return true; } for (let i = 0; i < source1.length; i++) { if (source1[i] !== source2[i]) { return true; } } return false; } return ( source1.filter(value => !source2.includes(value)).length > 0 || source2.filter(value => !source1.includes(value)).length > 0); } function escapeSearchTerm(text) { return text.replace(/([a-z_-]):/g, '$1\\:'); } function dataURItoBlob(dataURI) { const chunks = dataURI.split(','); const byteString = chunks[0].indexOf('base64') >= 0 ? window.atob(chunks[1]) : unescape(chunks[1]); const mimeString = chunks[0].split(':')[1].split(';')[0]; const data = new Uint8Array(byteString.length); for (let i = 0; i < byteString.length; i++) { data[i] = byteString.charCodeAt(i); } return new Blob([data], {type: mimeString}); } function getPrettyTagName(tag) { if (settings.get().tagUnderscoresAsSpaces) { return tag.replace(/_/g, " "); } return tag; } module.exports = { range: range, formatRelativeTime: formatRelativeTime, formatFileSize: formatFileSize, formatMarkdown: formatMarkdown, formatInlineMarkdown: formatInlineMarkdown, unindent: unindent, enableExitConfirmation: enableExitConfirmation, disableExitConfirmation: disableExitConfirmation, confirmPageExit: confirmPageExit, escapeHtml: escapeHtml, makeCssName: makeCssName, splitByWhitespace: splitByWhitespace, arraysDiffer: arraysDiffer, decamelize: decamelize, escapeSearchTerm: escapeSearchTerm, dataURItoBlob: dataURItoBlob, getPrettyTagName: getPrettyTagName, };