mirror of https://github.com/nextcloud/server
263 lines
6.5 KiB
JavaScript
263 lines
6.5 KiB
JavaScript
/**
|
|
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
|
|
*
|
|
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
|
* @author John Molakvoæ <skjnldsv@protonmail.com>
|
|
*
|
|
* @license GNU AGPL version 3 or any later version
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
import moment from 'moment'
|
|
|
|
import History from './util-history'
|
|
import OC from './index'
|
|
import { formatFileSize as humanFileSize } from '@nextcloud/files'
|
|
|
|
/**
|
|
* @param {any} t -
|
|
*/
|
|
function chunkify(t) {
|
|
// Adapted from http://my.opera.com/GreyWyvern/blog/show.dml/1671288
|
|
const tz = []
|
|
let x = 0
|
|
let y = -1
|
|
let n = 0
|
|
let c
|
|
|
|
while (x < t.length) {
|
|
c = t.charAt(x)
|
|
// only include the dot in strings
|
|
const m = ((!n && c === '.') || (c >= '0' && c <= '9'))
|
|
if (m !== n) {
|
|
// next chunk
|
|
y++
|
|
tz[y] = ''
|
|
n = m
|
|
}
|
|
tz[y] += c
|
|
x++
|
|
}
|
|
return tz
|
|
}
|
|
|
|
/**
|
|
* Utility functions
|
|
*
|
|
* @namespace OC.Util
|
|
*/
|
|
export default {
|
|
|
|
History,
|
|
|
|
/**
|
|
* @deprecated use https://nextcloud.github.io/nextcloud-files/modules/_humanfilesize_.html#formatfilesize
|
|
*/
|
|
humanFileSize,
|
|
|
|
/**
|
|
* Returns a file size in bytes from a humanly readable string
|
|
* Makes 2kB to 2048.
|
|
* Inspired by computerFileSize in helper.php
|
|
*
|
|
* @param {string} string file size in human readable format
|
|
* @return {number} or null if string could not be parsed
|
|
*
|
|
*
|
|
*/
|
|
computerFileSize(string) {
|
|
if (typeof string !== 'string') {
|
|
return null
|
|
}
|
|
|
|
const s = string.toLowerCase().trim()
|
|
let bytes = null
|
|
|
|
const bytesArray = {
|
|
b: 1,
|
|
k: 1024,
|
|
kb: 1024,
|
|
mb: 1024 * 1024,
|
|
m: 1024 * 1024,
|
|
gb: 1024 * 1024 * 1024,
|
|
g: 1024 * 1024 * 1024,
|
|
tb: 1024 * 1024 * 1024 * 1024,
|
|
t: 1024 * 1024 * 1024 * 1024,
|
|
pb: 1024 * 1024 * 1024 * 1024 * 1024,
|
|
p: 1024 * 1024 * 1024 * 1024 * 1024,
|
|
}
|
|
|
|
const matches = s.match(/^[\s+]?([0-9]*)(\.([0-9]+))?( +)?([kmgtp]?b?)$/i)
|
|
if (matches !== null) {
|
|
bytes = parseFloat(s)
|
|
if (!isFinite(bytes)) {
|
|
return null
|
|
}
|
|
} else {
|
|
return null
|
|
}
|
|
if (matches[5]) {
|
|
bytes = bytes * bytesArray[matches[5]]
|
|
}
|
|
|
|
bytes = Math.round(bytes)
|
|
return bytes
|
|
},
|
|
|
|
/**
|
|
* @param {string|number} timestamp timestamp
|
|
* @param {string} format date format, see momentjs docs
|
|
* @return {string} timestamp formatted as requested
|
|
*/
|
|
formatDate(timestamp, format) {
|
|
if (window.TESTING === undefined) {
|
|
console.warn('OC.Util.formatDate is deprecated and will be removed in Nextcloud 21. See @nextcloud/moment')
|
|
}
|
|
format = format || 'LLL'
|
|
return moment(timestamp).format(format)
|
|
},
|
|
|
|
/**
|
|
* @param {string|number} timestamp timestamp
|
|
* @return {string} human readable difference from now
|
|
*/
|
|
relativeModifiedDate(timestamp) {
|
|
if (window.TESTING === undefined) {
|
|
console.warn('OC.Util.relativeModifiedDate is deprecated and will be removed in Nextcloud 21. See @nextcloud/moment')
|
|
}
|
|
const diff = moment().diff(moment(timestamp))
|
|
if (diff >= 0 && diff < 45000) {
|
|
return t('core', 'seconds ago')
|
|
}
|
|
return moment(timestamp).fromNow()
|
|
},
|
|
|
|
/**
|
|
* Returns the width of a generic browser scrollbar
|
|
*
|
|
* @return {number} width of scrollbar
|
|
*/
|
|
getScrollBarWidth() {
|
|
if (this._scrollBarWidth) {
|
|
return this._scrollBarWidth
|
|
}
|
|
|
|
const inner = document.createElement('p')
|
|
inner.style.width = '100%'
|
|
inner.style.height = '200px'
|
|
|
|
const outer = document.createElement('div')
|
|
outer.style.position = 'absolute'
|
|
outer.style.top = '0px'
|
|
outer.style.left = '0px'
|
|
outer.style.visibility = 'hidden'
|
|
outer.style.width = '200px'
|
|
outer.style.height = '150px'
|
|
outer.style.overflow = 'hidden'
|
|
outer.appendChild(inner)
|
|
|
|
document.body.appendChild(outer)
|
|
const w1 = inner.offsetWidth
|
|
outer.style.overflow = 'scroll'
|
|
let w2 = inner.offsetWidth
|
|
if (w1 === w2) {
|
|
w2 = outer.clientWidth
|
|
}
|
|
|
|
document.body.removeChild(outer)
|
|
|
|
this._scrollBarWidth = (w1 - w2)
|
|
|
|
return this._scrollBarWidth
|
|
},
|
|
|
|
/**
|
|
* Remove the time component from a given date
|
|
*
|
|
* @param {Date} date date
|
|
* @return {Date} date with stripped time
|
|
*/
|
|
stripTime(date) {
|
|
// FIXME: likely to break when crossing DST
|
|
// would be better to use a library like momentJS
|
|
return new Date(date.getFullYear(), date.getMonth(), date.getDate())
|
|
},
|
|
|
|
/**
|
|
* Compare two strings to provide a natural sort
|
|
*
|
|
* @param {string} a first string to compare
|
|
* @param {string} b second string to compare
|
|
* @return {number} -1 if b comes before a, 1 if a comes before b
|
|
* or 0 if the strings are identical
|
|
*/
|
|
naturalSortCompare(a, b) {
|
|
let x
|
|
const aa = chunkify(a)
|
|
const bb = chunkify(b)
|
|
|
|
for (x = 0; aa[x] && bb[x]; x++) {
|
|
if (aa[x] !== bb[x]) {
|
|
const aNum = Number(aa[x]); const bNum = Number(bb[x])
|
|
// note: == is correct here
|
|
/* eslint-disable-next-line */
|
|
if (aNum == aa[x] && bNum == bb[x]) {
|
|
return aNum - bNum
|
|
} else {
|
|
// Note: This locale setting isn't supported by all browsers but for the ones
|
|
// that do there will be more consistency between client-server sorting
|
|
return aa[x].localeCompare(bb[x], OC.getLanguage())
|
|
}
|
|
}
|
|
}
|
|
return aa.length - bb.length
|
|
},
|
|
|
|
/**
|
|
* Calls the callback in a given interval until it returns true
|
|
*
|
|
* @param {Function} callback function to call on success
|
|
* @param {number} interval in milliseconds
|
|
*/
|
|
waitFor(callback, interval) {
|
|
const internalCallback = function() {
|
|
if (callback() !== true) {
|
|
setTimeout(internalCallback, interval)
|
|
}
|
|
}
|
|
|
|
internalCallback()
|
|
},
|
|
|
|
/**
|
|
* Checks if a cookie with the given name is present and is set to the provided value.
|
|
*
|
|
* @param {string} name name of the cookie
|
|
* @param {string} value value of the cookie
|
|
* @return {boolean} true if the cookie with the given name has the given value
|
|
*/
|
|
isCookieSetToValue(name, value) {
|
|
const cookies = document.cookie.split(';')
|
|
for (let i = 0; i < cookies.length; i++) {
|
|
const cookie = cookies[i].split('=')
|
|
if (cookie[0].trim() === name && cookie[1].trim() === value) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
},
|
|
}
|