2025-05-29 10:12:56 +08:00
|
|
|
|
import axios from 'axios';
|
2025-04-02 16:04:39 +08:00
|
|
|
|
import { mediaUrl, gettext, serviceURL, siteRoot, isPro, fileAuditEnabled, canGenerateShareLink, canGenerateUploadLink, shareLinkPasswordMinLength, username, folderPermEnabled, onlyofficeConverterExtensions, enableSeadoc, enableRepoSnapshotLabel,
|
2025-02-20 20:23:06 +08:00
|
|
|
|
enableResetEncryptedRepoPassword, isEmailConfigured, isSystemStaff,
|
|
|
|
|
enableOnlyoffice, onlyofficeEditFileExtension,
|
|
|
|
|
enableOfficeWebApp, officeWebAppEditFileExtension } from './constants';
|
2019-09-04 14:21:57 +08:00
|
|
|
|
import TextTranslation from './text-translation';
|
2019-12-05 15:45:16 +08:00
|
|
|
|
import React from 'react';
|
|
|
|
|
import toaster from '../components/toast';
|
2019-12-18 16:23:34 +08:00
|
|
|
|
import PermissionDeniedTip from '../components/permission-denied-tip';
|
2023-05-08 17:29:09 +08:00
|
|
|
|
import { compareTwoString } from './compare-two-string';
|
2024-06-29 17:58:27 +08:00
|
|
|
|
import { PRIVATE_FILE_TYPE } from '../constants';
|
2018-10-08 15:33:40 +08:00
|
|
|
|
|
2018-10-09 10:56:59 +08:00
|
|
|
|
export const Utils = {
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
keyCodes: {
|
2023-09-05 20:21:24 +08:00
|
|
|
|
enter: 13,
|
2024-07-18 11:58:42 +08:00
|
|
|
|
esc: 27,
|
2018-10-09 10:56:59 +08:00
|
|
|
|
space: 32,
|
2024-07-18 11:58:42 +08:00
|
|
|
|
tab: 9,
|
|
|
|
|
up: 38,
|
|
|
|
|
down: 40
|
2018-10-09 10:56:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
bytesToSize: function (bytes) {
|
2018-10-09 10:56:59 +08:00
|
|
|
|
if (typeof(bytes) == 'undefined') return ' ';
|
2018-11-22 11:26:00 +08:00
|
|
|
|
|
2024-05-31 10:59:59 +08:00
|
|
|
|
if (bytes < 0) return '--';
|
2024-11-29 17:41:35 +08:00
|
|
|
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
2018-11-22 11:26:00 +08:00
|
|
|
|
|
2018-10-09 10:56:59 +08:00
|
|
|
|
if (bytes === 0) return bytes + ' ' + sizes[0];
|
2018-11-22 11:26:00 +08:00
|
|
|
|
|
2018-10-09 10:56:59 +08:00
|
|
|
|
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1000)), 10);
|
|
|
|
|
if (i === 0) return bytes + ' ' + sizes[i];
|
|
|
|
|
return (bytes / (1000 ** i)).toFixed(1) + ' ' + sizes[i];
|
|
|
|
|
},
|
2018-10-08 15:33:40 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isHiDPI: function () {
|
2018-10-08 15:33:40 +08:00
|
|
|
|
var pixelRatio = window.devicePixelRatio ? window.devicePixelRatio : 1;
|
|
|
|
|
if (pixelRatio > 1) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isDesktop: function () {
|
2019-08-14 15:10:58 +08:00
|
|
|
|
return window.innerWidth >= 768;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isWeChat: function () {
|
2019-10-15 10:16:48 +08:00
|
|
|
|
let ua = window.navigator.userAgent.toLowerCase();
|
|
|
|
|
let isWeChat = ua.match(/MicroMessenger/i) == 'micromessenger';
|
|
|
|
|
let isEnterpriseWeChat = ua.match(/MicroMessenger/i) == 'micromessenger' && ua.match(/wxwork/i) == 'wxwork';
|
|
|
|
|
return isEnterpriseWeChat || isWeChat;
|
|
|
|
|
},
|
|
|
|
|
|
2018-10-08 15:33:40 +08:00
|
|
|
|
FILEEXT_ICON_MAP: {
|
|
|
|
|
|
|
|
|
|
// text file
|
|
|
|
|
'txt': 'txt.png',
|
|
|
|
|
|
2024-08-06 11:46:09 +08:00
|
|
|
|
// markdown file
|
|
|
|
|
'md': 'md.png',
|
|
|
|
|
|
2018-10-08 15:33:40 +08:00
|
|
|
|
// pdf file
|
2024-07-18 11:58:42 +08:00
|
|
|
|
'pdf': 'pdf.png',
|
2018-10-08 15:33:40 +08:00
|
|
|
|
|
|
|
|
|
// document file
|
2024-07-18 11:58:42 +08:00
|
|
|
|
'doc': 'word.png',
|
|
|
|
|
'docx': 'word.png',
|
|
|
|
|
'odt': 'word.png',
|
|
|
|
|
'fodt': 'word.png',
|
2018-10-08 15:33:40 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
'ppt': 'ppt.png',
|
|
|
|
|
'pptx': 'ppt.png',
|
|
|
|
|
'odp': 'ppt.png',
|
|
|
|
|
'fodp': 'ppt.png',
|
2018-10-08 15:33:40 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
'xls': 'excel.png',
|
|
|
|
|
'xlsx': 'excel.png',
|
|
|
|
|
'ods': 'excel.png',
|
|
|
|
|
'fods': 'excel.png',
|
2018-10-08 15:33:40 +08:00
|
|
|
|
|
|
|
|
|
// video
|
|
|
|
|
'mp4': 'video.png',
|
|
|
|
|
'ogv': 'video.png',
|
|
|
|
|
'webm': 'video.png',
|
|
|
|
|
'mov': 'video.png',
|
|
|
|
|
'flv': 'video.png',
|
|
|
|
|
'wmv': 'video.png',
|
|
|
|
|
'rmvb': 'video.png',
|
|
|
|
|
|
|
|
|
|
// music file
|
2024-07-18 11:58:42 +08:00
|
|
|
|
'mp3': 'music.png',
|
|
|
|
|
'oga': 'music.png',
|
|
|
|
|
'ogg': 'music.png',
|
|
|
|
|
'wav': 'music.png',
|
|
|
|
|
'flac': 'music.png',
|
|
|
|
|
'opus': 'music.png',
|
|
|
|
|
'aac': 'music.png',
|
|
|
|
|
'ac3': 'music.png',
|
|
|
|
|
'wma': 'music.png',
|
2018-10-08 15:33:40 +08:00
|
|
|
|
|
|
|
|
|
// image file
|
2024-07-18 11:58:42 +08:00
|
|
|
|
'jpg': 'pic.png',
|
|
|
|
|
'jpeg': 'pic.png',
|
|
|
|
|
'png': 'pic.png',
|
|
|
|
|
'svg': 'pic.png',
|
|
|
|
|
'gif': 'pic.png',
|
|
|
|
|
'bmp': 'pic.png',
|
|
|
|
|
'ico': 'pic.png',
|
2024-10-14 15:20:28 +08:00
|
|
|
|
'heic': 'pic.png',
|
2024-10-17 14:37:54 +08:00
|
|
|
|
'tif': 'pic.png',
|
|
|
|
|
'tiff': 'pic.png',
|
|
|
|
|
'webp': 'pic.png',
|
|
|
|
|
'jfif': 'pic.png',
|
2025-01-07 14:24:47 +08:00
|
|
|
|
'draw': 'draw.png',
|
2025-03-31 11:48:13 +08:00
|
|
|
|
'exdraw': 'draw.png',
|
2024-10-14 15:24:12 +08:00
|
|
|
|
|
2024-10-14 15:20:28 +08:00
|
|
|
|
// photoshop file
|
2024-08-06 11:46:09 +08:00
|
|
|
|
'psd': 'psd.png',
|
|
|
|
|
|
2024-08-26 10:46:51 +08:00
|
|
|
|
// zip file
|
|
|
|
|
'zip': 'zip.png',
|
|
|
|
|
'rar': 'zip.png',
|
|
|
|
|
'tar': 'zip.png',
|
|
|
|
|
|
2024-08-06 11:46:09 +08:00
|
|
|
|
// style file
|
|
|
|
|
'css': 'css.png',
|
|
|
|
|
|
|
|
|
|
// sdoc file
|
|
|
|
|
'sdoc': 'sdoc.png',
|
|
|
|
|
'sdoc_notification': 'sdoc_notification.ico',
|
2018-10-08 15:33:40 +08:00
|
|
|
|
|
|
|
|
|
// default
|
2024-07-18 11:58:42 +08:00
|
|
|
|
'default': 'file.png',
|
2018-10-08 15:33:40 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// check if a file is an image
|
2024-07-18 11:58:42 +08:00
|
|
|
|
imageCheck: function (filename) {
|
2018-10-08 15:33:40 +08:00
|
|
|
|
// no file ext
|
|
|
|
|
if (filename.lastIndexOf('.') == -1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-11-28 20:44:27 +08:00
|
|
|
|
const file_ext = filename.substr(filename.lastIndexOf('.') + 1).toLowerCase();
|
|
|
|
|
const image_exts = ['gif', 'jpeg', 'jpg', 'png', 'ico', 'bmp', 'tif', 'tiff', 'jfif', 'heic', 'webp'];
|
|
|
|
|
return image_exts.includes(file_ext);
|
2018-10-08 15:33:40 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
pdfCheck: function (filename) {
|
2024-06-04 16:06:57 +08:00
|
|
|
|
if (filename.lastIndexOf('.') == -1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-11-28 20:44:27 +08:00
|
|
|
|
const file_ext = filename.substr(filename.lastIndexOf('.') + 1).toLowerCase();
|
|
|
|
|
return file_ext === 'pdf';
|
2024-06-04 16:06:57 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getShareLinkPermissionList: function (itemType, permission, path, canEdit) {
|
2019-10-12 14:54:25 +08:00
|
|
|
|
// itemType: library, dir, file
|
2021-09-13 10:37:07 +08:00
|
|
|
|
// permission: rw, r, admin, cloud-edit, preview, custom-*
|
2019-10-12 14:54:25 +08:00
|
|
|
|
|
2020-04-14 17:16:48 +08:00
|
|
|
|
let permissionOptions = [];
|
2019-10-12 14:54:25 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
const { isCustomPermission } = Utils.getUserPermission(permission);
|
|
|
|
|
if (isCustomPermission) {
|
|
|
|
|
permissionOptions.push('preview_download');
|
|
|
|
|
permissionOptions.push('preview_only');
|
|
|
|
|
return permissionOptions;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-20 16:24:58 +08:00
|
|
|
|
if (permission == 'rw' || permission == 'admin' || permission == 'r') {
|
|
|
|
|
permissionOptions.push('preview_download');
|
|
|
|
|
}
|
|
|
|
|
permissionOptions.push('preview_only');
|
|
|
|
|
|
|
|
|
|
if (itemType == 'library' || itemType == 'dir') {
|
|
|
|
|
if (permission == 'rw' || permission == 'admin') {
|
|
|
|
|
permissionOptions.push('download_upload');
|
2019-10-12 14:54:25 +08:00
|
|
|
|
}
|
2020-10-20 16:24:58 +08:00
|
|
|
|
} else {
|
2019-12-03 13:52:52 +08:00
|
|
|
|
if (this.isEditableOfficeFile(path) && (permission == 'rw' || permission == 'admin') && canEdit) {
|
2020-10-20 16:24:58 +08:00
|
|
|
|
permissionOptions.push('edit_download');
|
2019-10-12 14:54:25 +08:00
|
|
|
|
}
|
2019-12-03 13:52:52 +08:00
|
|
|
|
|
|
|
|
|
// not support
|
|
|
|
|
// if (this.isEditableOfficeFile(path) && (permission == 'cloud-edit')) {
|
2020-10-20 16:24:58 +08:00
|
|
|
|
// permissionOptions.push('cloud_edit');
|
2019-12-03 13:52:52 +08:00
|
|
|
|
// }
|
|
|
|
|
|
2019-10-12 14:54:25 +08:00
|
|
|
|
}
|
|
|
|
|
return permissionOptions;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getShareLinkPermissionStr: function (permissions) {
|
2020-10-20 16:24:58 +08:00
|
|
|
|
const { can_edit, can_download, can_upload } = permissions;
|
|
|
|
|
switch (`${can_edit} ${can_download} ${can_upload}`) {
|
|
|
|
|
case 'false true false':
|
2020-01-02 12:05:50 +08:00
|
|
|
|
return 'preview_download';
|
2020-10-20 16:24:58 +08:00
|
|
|
|
case 'false false false':
|
2020-01-02 12:05:50 +08:00
|
|
|
|
return 'preview_only';
|
2020-10-20 16:24:58 +08:00
|
|
|
|
case 'false true true':
|
|
|
|
|
return 'download_upload';
|
|
|
|
|
case 'true true false':
|
|
|
|
|
return 'edit_download';
|
|
|
|
|
case 'true false false':
|
|
|
|
|
return 'cloud_edit';
|
2020-01-02 12:05:50 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isEditableOfficeFile: function (filename) {
|
2019-06-26 17:21:29 +08:00
|
|
|
|
// no file ext
|
|
|
|
|
if (filename.lastIndexOf('.') == -1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-11-28 20:44:27 +08:00
|
|
|
|
const file_ext = filename.substr(filename.lastIndexOf('.') + 1).toLowerCase();
|
2025-02-20 20:23:06 +08:00
|
|
|
|
|
|
|
|
|
if (enableOnlyoffice) {
|
2025-02-25 11:33:22 +08:00
|
|
|
|
return onlyofficeEditFileExtension.includes(file_ext);
|
2025-02-20 20:23:06 +08:00
|
|
|
|
} else if (enableOfficeWebApp) {
|
2025-02-25 11:33:22 +08:00
|
|
|
|
return officeWebAppEditFileExtension.includes(file_ext);
|
2025-02-20 20:23:06 +08:00
|
|
|
|
} else {
|
2025-02-25 11:33:22 +08:00
|
|
|
|
return false;
|
2025-02-20 20:23:06 +08:00
|
|
|
|
}
|
2019-06-26 17:21:29 +08:00
|
|
|
|
},
|
|
|
|
|
|
2018-10-08 15:33:40 +08:00
|
|
|
|
// check if a file is a video
|
2024-07-18 11:58:42 +08:00
|
|
|
|
videoCheck: function (filename) {
|
2018-10-08 15:33:40 +08:00
|
|
|
|
// no file ext
|
|
|
|
|
if (filename.lastIndexOf('.') == -1) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-11-28 20:44:27 +08:00
|
|
|
|
const file_ext = filename.substr(filename.lastIndexOf('.') + 1).toLowerCase();
|
|
|
|
|
return ['mp4', 'ogv', 'webm', 'mov'].includes(file_ext);
|
2018-10-08 15:33:40 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
checkDuplicatedNameInList: function (list, targetName) {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
return list.some(object => {
|
|
|
|
|
return object.name === targetName;
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
encodePath: function (path) {
|
2018-10-08 15:33:40 +08:00
|
|
|
|
// IE8 does not support 'map()'
|
|
|
|
|
/*
|
|
|
|
|
return path.split('/').map(function(e) {
|
|
|
|
|
return encodeURIComponent(e);
|
|
|
|
|
}).join('/');
|
|
|
|
|
*/
|
2018-12-17 12:03:37 +08:00
|
|
|
|
if (!path) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
2018-10-16 18:19:51 +08:00
|
|
|
|
var path_arr = path.split('/');
|
|
|
|
|
var path_arr_ = [];
|
2018-10-08 15:33:40 +08:00
|
|
|
|
for (var i = 0, len = path_arr.length; i < len; i++) {
|
|
|
|
|
path_arr_.push(encodeURIComponent(path_arr[i]));
|
|
|
|
|
}
|
|
|
|
|
return path_arr_.join('/');
|
2018-10-25 13:36:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
HTMLescape: function (html) {
|
2018-10-25 13:36:06 +08:00
|
|
|
|
return document.createElement('div')
|
2018-10-25 14:42:53 +08:00
|
|
|
|
.appendChild(document.createTextNode(html))
|
|
|
|
|
.parentNode
|
|
|
|
|
.innerHTML;
|
2018-10-25 13:36:06 +08:00
|
|
|
|
},
|
2018-11-08 10:36:41 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
generateDialogTitle: function (title, operationTarget) {
|
2022-10-09 18:32:03 +08:00
|
|
|
|
/*
|
|
|
|
|
* @param title: gettext('...{placeholder}...')
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
const targetStr = this.HTMLescape(operationTarget);
|
|
|
|
|
const str = `<span class="op-target ellipsis ellipsis-op-target" title=${targetStr}>${targetStr}</span>`;
|
|
|
|
|
return title.replace('{placeholder}', str);
|
|
|
|
|
*/
|
|
|
|
|
return title.replace('{placeholder}', operationTarget);
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getFileName: function (filePath) {
|
2018-11-08 10:36:41 +08:00
|
|
|
|
let lastIndex = filePath.lastIndexOf('/');
|
2024-07-18 11:58:42 +08:00
|
|
|
|
return filePath.slice(lastIndex + 1);
|
2018-11-14 10:55:11 +08:00
|
|
|
|
},
|
|
|
|
|
|
2019-01-23 16:25:14 +08:00
|
|
|
|
/**
|
|
|
|
|
* input: '/abc/bc/cb'
|
|
|
|
|
* output: ['/abc', '/abc/bc', '/abc/bc/cb'];
|
|
|
|
|
*/
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getPaths: function (path) {
|
2019-01-23 16:25:14 +08:00
|
|
|
|
let paths = path.split('/').slice(1);
|
|
|
|
|
let result = [];
|
2024-07-18 11:58:42 +08:00
|
|
|
|
while (paths.length) {
|
2019-01-23 16:25:14 +08:00
|
|
|
|
result.push('/' + paths.join('/'));
|
|
|
|
|
paths.pop();
|
|
|
|
|
}
|
|
|
|
|
return result.reverse();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2020-11-02 13:56:35 +08:00
|
|
|
|
* input:
|
2018-12-17 22:34:54 +08:00
|
|
|
|
* eg: /
|
|
|
|
|
* ../abc/abc/
|
|
|
|
|
* ../abc/bc
|
|
|
|
|
* output(return):
|
|
|
|
|
* eg: /
|
|
|
|
|
* abc
|
|
|
|
|
* bc
|
|
|
|
|
*/
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getFolderName: function (path) {
|
2018-12-17 22:34:54 +08:00
|
|
|
|
if (path === '/') {
|
|
|
|
|
return path;
|
|
|
|
|
}
|
2023-08-24 10:18:40 +08:00
|
|
|
|
path = path[path.length - 1] !== '/' ? path : path.slice(0, path.length - 1);
|
2018-12-17 22:34:54 +08:00
|
|
|
|
return path.slice(path.lastIndexOf('/') + 1);
|
|
|
|
|
},
|
|
|
|
|
|
2018-11-22 11:26:00 +08:00
|
|
|
|
/*
|
|
|
|
|
return dirname of a path.
|
|
|
|
|
if path is '/', return '/'.
|
|
|
|
|
*/
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getDirName: function (path) {
|
2018-11-22 11:26:00 +08:00
|
|
|
|
let dir = path.slice(0, path.lastIndexOf('/'));
|
|
|
|
|
if (dir === '') {
|
|
|
|
|
return '/';
|
|
|
|
|
} else {
|
|
|
|
|
return dir;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isChildPath: function (child, parent) {
|
2018-11-22 11:26:00 +08:00
|
|
|
|
let p = this.getDirName(child);
|
|
|
|
|
return p === parent;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isAncestorPath: function (ancestor, path) {
|
2018-11-22 11:26:00 +08:00
|
|
|
|
return path.indexOf(ancestor) > -1;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
renameAncestorPath: function (path, ancestor, newAncestor) {
|
2019-02-20 11:54:25 +08:00
|
|
|
|
return path.replace(ancestor, newAncestor);
|
2018-11-22 11:26:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
joinPath: function (pathA, pathB) {
|
2024-07-01 18:33:57 +08:00
|
|
|
|
if (pathA[pathA.length - 1] === '/') {
|
2018-11-22 11:26:00 +08:00
|
|
|
|
return pathA + pathB;
|
|
|
|
|
} else {
|
|
|
|
|
return pathA + '/' + pathB;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isSupportUploadFolder: function () {
|
|
|
|
|
return navigator.userAgent.indexOf('Firefox') != -1 ||
|
2020-11-02 13:56:35 +08:00
|
|
|
|
navigator.userAgent.indexOf('Chrome') > -1 ||
|
2020-10-20 16:24:58 +08:00
|
|
|
|
navigator.userAgent.indexOf('Safari') > -1;
|
2018-11-19 11:53:44 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-08-12 14:25:37 +08:00
|
|
|
|
isIEBrowser: function () { // is ie <= ie11 not include Edge
|
2019-06-04 16:18:32 +08:00
|
|
|
|
var userAgent = navigator.userAgent;
|
2019-06-21 13:59:17 +08:00
|
|
|
|
var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1;
|
|
|
|
|
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;
|
2019-06-04 16:18:32 +08:00
|
|
|
|
return isIE || isIE11;
|
|
|
|
|
},
|
|
|
|
|
|
2024-11-29 14:42:08 +08:00
|
|
|
|
getDefaultLibIconUrl: function () {
|
|
|
|
|
return mediaUrl + 'img/lib/256/lib.png';
|
2019-02-26 14:14:00 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-11-29 14:42:08 +08:00
|
|
|
|
getLibIconUrl: function (repo) {
|
2024-07-18 11:58:42 +08:00
|
|
|
|
let permission = repo.permission || repo.share_permission; // Compatible with regular repo and repo shared
|
2019-05-29 12:24:06 +08:00
|
|
|
|
|
2019-01-29 15:22:02 +08:00
|
|
|
|
let icon_name = 'lib.png';
|
|
|
|
|
if (repo.encrypted) {
|
2018-11-19 11:53:44 +08:00
|
|
|
|
icon_name = 'lib-encrypted.png';
|
|
|
|
|
}
|
2019-05-29 12:24:06 +08:00
|
|
|
|
switch (permission) {
|
|
|
|
|
case 'r':
|
|
|
|
|
icon_name = 'lib-readonly.png';
|
|
|
|
|
break;
|
|
|
|
|
case 'preview':
|
|
|
|
|
icon_name = 'lib-cloud-preview.png';
|
|
|
|
|
break;
|
|
|
|
|
case 'cloud-edit':
|
|
|
|
|
icon_name = 'lib-cloud-preview-edit.png';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// must be the last
|
|
|
|
|
if (repo.status == 'read-only') {
|
2018-11-19 11:53:44 +08:00
|
|
|
|
icon_name = 'lib-readonly.png';
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-29 14:42:08 +08:00
|
|
|
|
return mediaUrl + 'img/lib/256/' + icon_name;
|
2019-01-29 15:22:02 +08:00
|
|
|
|
},
|
2018-11-19 11:53:44 +08:00
|
|
|
|
|
2019-01-29 15:22:02 +08:00
|
|
|
|
getDirentIcon: function (dirent, isBig) {
|
2024-09-14 15:29:26 +08:00
|
|
|
|
if (!dirent) return '';
|
2024-08-12 17:08:49 +08:00
|
|
|
|
let size = Utils.isHiDPI() ? 48 : 24;
|
2019-01-29 15:22:02 +08:00
|
|
|
|
size = isBig ? 192 : size;
|
2024-10-12 20:32:39 +08:00
|
|
|
|
if (dirent.type == 'file') {
|
|
|
|
|
return Utils.getFileIconUrl(dirent.name);
|
|
|
|
|
} else {
|
2019-01-29 15:22:02 +08:00
|
|
|
|
let readonly = false;
|
|
|
|
|
if (dirent.permission && (dirent.permission === 'r' || dirent.permission === 'preview')) {
|
|
|
|
|
readonly = true;
|
|
|
|
|
}
|
2024-08-12 17:08:49 +08:00
|
|
|
|
return Utils.getFolderIconUrl(readonly, size, dirent.has_been_shared_out);
|
2019-01-29 15:22:02 +08:00
|
|
|
|
}
|
2018-11-19 11:53:44 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-08-05 21:04:31 +08:00
|
|
|
|
getAdminTemplateDirentIcon: function (dirent) {
|
2019-09-24 12:18:53 +08:00
|
|
|
|
if (dirent.is_file) {
|
2024-08-05 21:04:31 +08:00
|
|
|
|
return this.getFileIconUrl(dirent.obj_name);
|
2019-09-24 12:18:53 +08:00
|
|
|
|
} else {
|
|
|
|
|
return this.getFolderIconUrl();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getFolderIconUrl: function (readonly = false, size, sharedOut) {
|
2019-01-29 15:22:02 +08:00
|
|
|
|
if (!size) {
|
|
|
|
|
size = Utils.isHiDPI() ? 48 : 24;
|
|
|
|
|
}
|
|
|
|
|
size = size > 24 ? 192 : 24;
|
2023-11-15 17:01:50 +08:00
|
|
|
|
return `${mediaUrl}img/folder${readonly ? '-read-only' : ''}${sharedOut ? '-shared-out' : ''}-${size}.png`;
|
2018-11-19 11:53:44 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-11-08 15:31:48 +08:00
|
|
|
|
getFileIconName: function (fileName) {
|
|
|
|
|
if (fileName.lastIndexOf('.') == -1) return Utils.FILEEXT_ICON_MAP['default'];
|
|
|
|
|
const file_ext = fileName.substr(fileName.lastIndexOf('.') + 1).toLowerCase();
|
|
|
|
|
if (Utils.FILEEXT_ICON_MAP[file_ext]) return Utils.FILEEXT_ICON_MAP[file_ext];
|
|
|
|
|
return Utils.FILEEXT_ICON_MAP['default'];
|
|
|
|
|
},
|
|
|
|
|
|
2024-08-05 21:04:31 +08:00
|
|
|
|
getFileIconUrl: function (filename) {
|
2019-01-29 15:22:02 +08:00
|
|
|
|
let file_ext = '';
|
|
|
|
|
if (filename.lastIndexOf('.') == -1) {
|
2024-08-12 17:08:49 +08:00
|
|
|
|
return mediaUrl + 'img/file/256/' + Utils.FILEEXT_ICON_MAP['default'];
|
2019-01-29 15:22:02 +08:00
|
|
|
|
} else {
|
|
|
|
|
file_ext = filename.substr(filename.lastIndexOf('.') + 1).toLowerCase();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-12 17:08:49 +08:00
|
|
|
|
if (Utils.FILEEXT_ICON_MAP[file_ext]) {
|
|
|
|
|
return mediaUrl + 'img/file/256/' + Utils.FILEEXT_ICON_MAP[file_ext];
|
2019-01-29 15:22:02 +08:00
|
|
|
|
} else {
|
2024-08-12 17:08:49 +08:00
|
|
|
|
return mediaUrl + 'img/file/256/' + Utils.FILEEXT_ICON_MAP['default'];
|
2019-01-29 15:22:02 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getLibIconTitle: function (repo) {
|
2018-11-19 11:53:44 +08:00
|
|
|
|
var title;
|
2024-07-18 11:58:42 +08:00
|
|
|
|
let permission = repo.permission || repo.share_permission; // Compatible with regular repo and repo shared
|
2019-01-29 15:22:02 +08:00
|
|
|
|
if (repo.encrypted) {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Encrypted library');
|
2019-01-29 15:22:02 +08:00
|
|
|
|
} else if (repo.is_admin) { // shared with 'admin' permission
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Admin access');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
} else {
|
2024-07-18 11:58:42 +08:00
|
|
|
|
switch (permission) {
|
2018-11-19 11:53:44 +08:00
|
|
|
|
case 'rw':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Read-Write library');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Read-Only library');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'cloud-edit':
|
2019-06-25 17:58:02 +08:00
|
|
|
|
title = gettext('Online Read-Write library');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'preview':
|
2019-06-25 17:58:02 +08:00
|
|
|
|
title = gettext('Online Read-Only library');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return title;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getFolderIconTitle: function (options) {
|
2018-11-19 11:53:44 +08:00
|
|
|
|
var title;
|
2024-07-18 11:58:42 +08:00
|
|
|
|
switch (options.permission) {
|
2018-11-19 11:53:44 +08:00
|
|
|
|
case 'rw':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Read-Write folder');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Read-Only folder');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'cloud-edit':
|
2019-06-25 17:58:02 +08:00
|
|
|
|
title = gettext('Online Read-Write folder');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'preview':
|
2019-06-25 17:58:02 +08:00
|
|
|
|
title = gettext('Online Read-Only folder');
|
2018-11-19 11:53:44 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return title;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getFolderOperationList: function (isRepoOwner, currentRepoInfo, dirent, isContextmenu) {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
|
|
|
|
|
let list = [];
|
2025-04-27 17:51:40 +08:00
|
|
|
|
const { SHARE, DOWNLOAD, DELETE, RENAME, MOVE, COPY, PERMISSION, OPEN_VIA_CLIENT, STAR, UNSTAR } = TextTranslation;
|
2019-09-04 14:21:57 +08:00
|
|
|
|
const permission = dirent.permission;
|
2021-09-13 10:37:07 +08:00
|
|
|
|
const { isCustomPermission, customPermission } = Utils.getUserPermission(permission);
|
2019-09-04 14:21:57 +08:00
|
|
|
|
|
|
|
|
|
if (isContextmenu) {
|
|
|
|
|
if (permission == 'rw' || permission == 'r') {
|
2021-10-11 17:57:52 +08:00
|
|
|
|
list.push(DOWNLOAD);
|
2021-09-13 10:37:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isCustomPermission && customPermission.permission.download) {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
list.push(DOWNLOAD);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 15:27:19 +08:00
|
|
|
|
if (permission == 'rw' || permission == 'cloud-edit') {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
list.push(DELETE, 'Divider');
|
|
|
|
|
}
|
2021-10-11 17:57:52 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (isCustomPermission && customPermission.permission.delete) {
|
|
|
|
|
list.push(DELETE, 'Divider');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-24 16:54:19 +08:00
|
|
|
|
if (Utils.isHasPermissionToShare(currentRepoInfo, permission, dirent)) {
|
|
|
|
|
list.push(SHARE);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 15:27:19 +08:00
|
|
|
|
if (permission == 'rw' || permission == 'cloud-edit') {
|
2021-09-13 10:37:07 +08:00
|
|
|
|
list.push(RENAME, MOVE);
|
|
|
|
|
}
|
2021-10-11 17:57:52 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (isCustomPermission && customPermission.permission.modify) {
|
|
|
|
|
list.push(RENAME, MOVE);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 15:27:19 +08:00
|
|
|
|
if (permission == 'rw' || permission == 'cloud-edit') {
|
2021-09-13 10:37:07 +08:00
|
|
|
|
list.push(COPY);
|
|
|
|
|
}
|
2021-10-11 17:57:52 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (isCustomPermission && customPermission.permission.copy) {
|
|
|
|
|
list.push(COPY);
|
2019-09-04 14:21:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-04-27 17:51:40 +08:00
|
|
|
|
if (dirent.starred) {
|
|
|
|
|
list.push(UNSTAR);
|
|
|
|
|
} else {
|
|
|
|
|
list.push(STAR);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 14:21:57 +08:00
|
|
|
|
if (permission == 'rw') {
|
2024-07-18 11:58:42 +08:00
|
|
|
|
if (folderPermEnabled && ((isRepoOwner && currentRepoInfo.has_been_shared_out) || currentRepoInfo.is_admin)) {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
list.push('Divider', PERMISSION);
|
|
|
|
|
}
|
|
|
|
|
list.push('Divider', OPEN_VIA_CLIENT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (permission == 'r' && !currentRepoInfo.encrypted) {
|
|
|
|
|
list.push(COPY);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
// if the last item of menuList is ‘Divider’, delete the last item
|
|
|
|
|
if (list[list.length - 1] === 'Divider') {
|
|
|
|
|
list.pop();
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 14:21:57 +08:00
|
|
|
|
return list;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getFileOperationList: function (isRepoOwner, currentRepoInfo, dirent, isContextmenu) {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
let list = [];
|
2024-08-16 20:27:18 +08:00
|
|
|
|
const {
|
2025-04-02 16:04:39 +08:00
|
|
|
|
SHARE, DOWNLOAD, DELETE, RENAME, MOVE, COPY, UNLOCK, LOCK, UNFREEZE_DOCUMENT, FREEZE_DOCUMENT,
|
2024-08-16 20:27:18 +08:00
|
|
|
|
HISTORY, ACCESS_LOG, PROPERTIES, OPEN_VIA_CLIENT, ONLYOFFICE_CONVERT,
|
2025-04-27 17:51:40 +08:00
|
|
|
|
CONVERT_AND_EXPORT, CONVERT_TO_MARKDOWN, CONVERT_TO_DOCX, EXPORT_DOCX, CONVERT_TO_SDOC, EXPORT_SDOC,
|
|
|
|
|
STAR, UNSTAR
|
2024-08-16 20:27:18 +08:00
|
|
|
|
} = TextTranslation;
|
2019-09-04 14:21:57 +08:00
|
|
|
|
const permission = dirent.permission;
|
2021-09-13 10:37:07 +08:00
|
|
|
|
const { isCustomPermission, customPermission } = Utils.getUserPermission(permission);
|
2019-09-04 14:21:57 +08:00
|
|
|
|
|
|
|
|
|
if (isContextmenu) {
|
|
|
|
|
if (permission == 'rw' || permission == 'r') {
|
|
|
|
|
list.push(DOWNLOAD);
|
|
|
|
|
}
|
2021-10-11 17:57:52 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (isCustomPermission && customPermission.permission.download) {
|
|
|
|
|
list.push(DOWNLOAD);
|
|
|
|
|
}
|
2019-09-04 14:21:57 +08:00
|
|
|
|
|
2023-08-01 15:27:19 +08:00
|
|
|
|
if (permission == 'rw' || permission == 'cloud-edit') {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
if (!dirent.is_locked || (dirent.is_locked && dirent.locked_by_me)) {
|
|
|
|
|
list.push(DELETE);
|
|
|
|
|
}
|
2021-09-13 10:37:07 +08:00
|
|
|
|
list.push('Divider');
|
|
|
|
|
}
|
2021-10-11 17:57:52 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (isCustomPermission && customPermission.permission.delete) {
|
|
|
|
|
if (!dirent.is_locked || (dirent.is_locked && dirent.locked_by_me)) {
|
|
|
|
|
list.push(DELETE);
|
|
|
|
|
}
|
|
|
|
|
list.push('Divider');
|
2019-09-04 14:21:57 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-02 13:56:35 +08:00
|
|
|
|
|
2025-02-24 16:54:19 +08:00
|
|
|
|
if (Utils.isHasPermissionToShare(currentRepoInfo, permission, dirent)) {
|
|
|
|
|
list.push(SHARE);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 15:27:19 +08:00
|
|
|
|
if (permission == 'rw' || permission == 'cloud-edit') {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
if (!dirent.is_locked || (dirent.is_locked && dirent.locked_by_me)) {
|
|
|
|
|
list.push(RENAME, MOVE);
|
|
|
|
|
}
|
2021-09-13 10:37:07 +08:00
|
|
|
|
}
|
2021-10-11 17:57:52 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (isCustomPermission && customPermission.permission.modify) {
|
|
|
|
|
if (!dirent.is_locked || (dirent.is_locked && dirent.locked_by_me)) {
|
|
|
|
|
list.push(RENAME, MOVE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 15:27:19 +08:00
|
|
|
|
if (permission == 'rw' || permission == 'cloud-edit') {
|
2021-09-13 10:37:07 +08:00
|
|
|
|
list.push(COPY);
|
|
|
|
|
}
|
2019-09-04 14:21:57 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (isCustomPermission) {
|
|
|
|
|
if (customPermission.permission.copy) {
|
|
|
|
|
list.push(COPY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-27 17:51:40 +08:00
|
|
|
|
if (dirent.starred) {
|
|
|
|
|
list.push(UNSTAR);
|
|
|
|
|
} else {
|
|
|
|
|
list.push(STAR);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (permission == 'rw') {
|
2019-09-04 14:21:57 +08:00
|
|
|
|
if (isPro) {
|
|
|
|
|
if (dirent.is_locked) {
|
2021-01-26 16:54:12 +08:00
|
|
|
|
if (dirent.locked_by_me || dirent.lock_owner == 'OnlineOffice' || isRepoOwner || currentRepoInfo.is_admin) {
|
2024-04-11 18:26:48 +08:00
|
|
|
|
if (!dirent.name.endsWith('.sdoc')) {
|
|
|
|
|
list.push(UNLOCK);
|
|
|
|
|
}
|
2020-11-02 13:56:35 +08:00
|
|
|
|
}
|
2019-09-04 14:21:57 +08:00
|
|
|
|
} else {
|
2023-11-29 16:14:38 +08:00
|
|
|
|
if (!dirent.name.endsWith('.sdoc')) {
|
2023-11-14 16:06:45 +08:00
|
|
|
|
list.push(LOCK);
|
|
|
|
|
}
|
2019-09-04 14:21:57 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list.push('Divider');
|
2023-11-29 16:14:38 +08:00
|
|
|
|
|
|
|
|
|
if (isPro && !dirent.is_locked && dirent.name.endsWith('.sdoc')) {
|
|
|
|
|
list.push(FREEZE_DOCUMENT);
|
|
|
|
|
}
|
2024-04-11 18:26:48 +08:00
|
|
|
|
if (isPro && dirent.is_locked && dirent.name.endsWith('.sdoc')) {
|
|
|
|
|
list.push(UNFREEZE_DOCUMENT);
|
|
|
|
|
}
|
2023-11-29 16:14:38 +08:00
|
|
|
|
|
2023-09-14 14:36:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-04-22 17:39:13 +08:00
|
|
|
|
if ((permission == 'rw' || permission == 'cloud-edit') && enableSeadoc && !currentRepoInfo.encrypted) {
|
2024-01-22 12:13:31 +08:00
|
|
|
|
if (dirent.name.endsWith('.md') || dirent.name.endsWith('.docx')) {
|
2023-09-18 10:20:47 +08:00
|
|
|
|
list.push(CONVERT_TO_SDOC);
|
|
|
|
|
}
|
2023-09-14 14:36:58 +08:00
|
|
|
|
|
2023-09-18 10:20:47 +08:00
|
|
|
|
if (dirent.name.endsWith('.sdoc')) {
|
2024-08-16 20:27:18 +08:00
|
|
|
|
if (Utils.isDesktop()) {
|
2024-09-09 15:58:33 +08:00
|
|
|
|
let subOpList = [CONVERT_TO_MARKDOWN, CONVERT_TO_DOCX, EXPORT_DOCX, EXPORT_SDOC];
|
2024-08-16 20:27:18 +08:00
|
|
|
|
list.push({ ...CONVERT_AND_EXPORT, subOpList });
|
|
|
|
|
} else {
|
|
|
|
|
list.push(CONVERT_TO_MARKDOWN);
|
|
|
|
|
list.push(CONVERT_TO_DOCX);
|
|
|
|
|
list.push(EXPORT_DOCX);
|
2024-09-09 15:58:33 +08:00
|
|
|
|
list.push(EXPORT_SDOC);
|
2024-08-16 20:27:18 +08:00
|
|
|
|
}
|
2023-09-18 10:20:47 +08:00
|
|
|
|
}
|
2023-09-14 14:36:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (permission == 'rw') {
|
|
|
|
|
list.push('Divider');
|
2023-08-10 19:39:58 +08:00
|
|
|
|
list.push(PROPERTIES, HISTORY);
|
2019-09-04 14:21:57 +08:00
|
|
|
|
if (isPro && fileAuditEnabled) {
|
|
|
|
|
list.push(ACCESS_LOG);
|
2020-11-02 13:56:35 +08:00
|
|
|
|
}
|
2019-09-04 14:21:57 +08:00
|
|
|
|
list.push('Divider', OPEN_VIA_CLIENT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (permission == 'r') {
|
|
|
|
|
if (!currentRepoInfo.encrypted) {
|
|
|
|
|
list.push(COPY);
|
|
|
|
|
}
|
|
|
|
|
list.push(HISTORY);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-02 11:22:25 +08:00
|
|
|
|
if (permission == 'rw' && currentRepoInfo.enable_onlyoffice &&
|
2024-07-24 00:33:12 +08:00
|
|
|
|
onlyofficeConverterExtensions.includes(Utils.getFileExtension(dirent.name, false))) {
|
2021-09-13 11:37:15 +03:00
|
|
|
|
list.push(ONLYOFFICE_CONVERT);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
// if the last item of menuList is ‘Divider’, delete the last item
|
|
|
|
|
if (list[list.length - 1] === 'Divider') {
|
|
|
|
|
list.pop();
|
|
|
|
|
}
|
2023-10-11 20:40:16 +08:00
|
|
|
|
|
|
|
|
|
// Remove adjacent excess 'Divider'
|
|
|
|
|
for (let i = 0; i < list.length; i++) {
|
|
|
|
|
if (list[i] === 'Divider' && list[i + 1] === 'Divider') {
|
|
|
|
|
list.splice(i, 1);
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 14:21:57 +08:00
|
|
|
|
return list;
|
|
|
|
|
},
|
|
|
|
|
|
2021-09-13 11:37:15 +03:00
|
|
|
|
getFileExtension: function (fileName, withoutDot) {
|
2021-10-11 17:57:52 +08:00
|
|
|
|
let parts = fileName.toLowerCase().split('.');
|
2021-09-13 11:37:15 +03:00
|
|
|
|
|
2021-10-11 17:57:52 +08:00
|
|
|
|
return withoutDot ? parts.pop() : '.' + parts.pop();
|
2021-09-13 11:37:15 +03:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getDirentOperationList: function (isRepoOwner, currentRepoInfo, dirent, isContextmenu) {
|
2024-07-23 23:08:53 +08:00
|
|
|
|
const operationListGetter = dirent.type === 'dir' ? Utils.getFolderOperationList : Utils.getFileOperationList;
|
|
|
|
|
return operationListGetter(isRepoOwner, currentRepoInfo, dirent, isContextmenu);
|
2019-09-04 14:21:57 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-10-18 10:54:58 +08:00
|
|
|
|
getRepoOperationList: function (repo) {
|
|
|
|
|
const showResetPasswordMenuItem = isPro && repo.encrypted && enableResetEncryptedRepoPassword && isEmailConfigured;
|
|
|
|
|
const operations = [];
|
|
|
|
|
const DIVIDER = 'Divider';
|
2024-11-06 20:12:39 +08:00
|
|
|
|
const { SHARE, DELETE, RENAME, TRANSFER, FOLDER_PERMISSION, SHARE_ADMIN, CHANGE_PASSWORD, RESET_PASSWORD, UNWATCH_FILE_CHANGES, WATCH_FILE_CHANGES, ADVANCED } = TextTranslation;
|
2024-10-18 10:54:58 +08:00
|
|
|
|
|
|
|
|
|
operations.push(SHARE, DELETE, DIVIDER, RENAME, TRANSFER);
|
|
|
|
|
|
|
|
|
|
if (folderPermEnabled) {
|
|
|
|
|
operations.push(FOLDER_PERMISSION);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operations.push(SHARE_ADMIN, DIVIDER);
|
|
|
|
|
|
|
|
|
|
if (repo.encrypted) {
|
|
|
|
|
operations.push(CHANGE_PASSWORD);
|
|
|
|
|
}
|
|
|
|
|
if (showResetPasswordMenuItem) {
|
|
|
|
|
operations.push(RESET_PASSWORD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isPro) {
|
|
|
|
|
const monitorOp = repo.monitored ? UNWATCH_FILE_CHANGES : WATCH_FILE_CHANGES;
|
|
|
|
|
operations.push(monitorOp);
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-06 20:12:39 +08:00
|
|
|
|
operations.push(DIVIDER);
|
2024-10-18 10:54:58 +08:00
|
|
|
|
const subOpList = Utils.getAdvancedOperations();
|
|
|
|
|
operations.push({ ...ADVANCED, subOpList });
|
|
|
|
|
|
|
|
|
|
// Remove adjacent excess 'Divider'
|
|
|
|
|
return operations.filter((op, i, arr) => !(op === DIVIDER && arr[i + 1] === DIVIDER));
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getAdvancedOperations: function () {
|
|
|
|
|
const operations = [];
|
2024-11-06 20:12:39 +08:00
|
|
|
|
const { API_TOKEN, LABEL_CURRENT_STATE } = TextTranslation;
|
2024-10-18 10:54:58 +08:00
|
|
|
|
|
|
|
|
|
operations.push(API_TOKEN);
|
|
|
|
|
|
|
|
|
|
if (enableRepoSnapshotLabel) {
|
|
|
|
|
operations.push(LABEL_CURRENT_STATE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return operations;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getSharedLibsOperationList: function (lib) {
|
|
|
|
|
const { SHARE, UNSHARE, WATCH_FILE_CHANGES, UNWATCH_FILE_CHANGES } = TextTranslation;
|
|
|
|
|
const operations = [];
|
|
|
|
|
|
|
|
|
|
if (isPro && lib.is_admin) {
|
|
|
|
|
operations.push(SHARE);
|
|
|
|
|
}
|
|
|
|
|
operations.push(UNSHARE);
|
|
|
|
|
|
|
|
|
|
const monitorOp = lib.monitored ? UNWATCH_FILE_CHANGES : WATCH_FILE_CHANGES;
|
|
|
|
|
operations.push(monitorOp);
|
|
|
|
|
|
|
|
|
|
return operations;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getPublicSharedRepoOperationList: function (repo) {
|
|
|
|
|
const { UNSHARE } = TextTranslation;
|
|
|
|
|
const operations = [];
|
|
|
|
|
const isRepoOwner = repo.owner_email === username;
|
|
|
|
|
|
|
|
|
|
if (isSystemStaff || isRepoOwner) {
|
|
|
|
|
operations.push(UNSHARE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return operations;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getSharedRepoOperationList: function (repo, currentGroup, isPublic) {
|
|
|
|
|
const operations = [];
|
2024-11-06 20:12:39 +08:00
|
|
|
|
const { SHARE, UNSHARE, DELETE, RENAME, FOLDER_PERMISSION, SHARE_ADMIN, UNWATCH_FILE_CHANGES, WATCH_FILE_CHANGES, ADVANCED, CHANGE_PASSWORD, RESET_PASSWORD, API_TOKEN } = TextTranslation;
|
2024-10-18 10:54:58 +08:00
|
|
|
|
|
|
|
|
|
const isStaff = currentGroup && currentGroup.admins && currentGroup.admins.indexOf(username) > -1;
|
|
|
|
|
const isRepoOwner = repo.owner_email === username;
|
|
|
|
|
const isAdmin = repo.is_admin;
|
|
|
|
|
const DIVIDER = 'Divider';
|
|
|
|
|
|
|
|
|
|
if (isPublic) {
|
|
|
|
|
if (isSystemStaff || isRepoOwner) {
|
|
|
|
|
operations.push(UNSHARE);
|
|
|
|
|
}
|
|
|
|
|
return operations;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isPro) {
|
|
|
|
|
if (repo.owner_email.indexOf('@seafile_group') !== -1) {
|
|
|
|
|
// is group admin
|
|
|
|
|
if (isStaff) {
|
|
|
|
|
if (repo.owner_email === `${currentGroup.id}@seafile_group`) {
|
|
|
|
|
operations.push(SHARE, DELETE, RENAME);
|
|
|
|
|
if (folderPermEnabled) {
|
|
|
|
|
operations.push(FOLDER_PERMISSION);
|
|
|
|
|
}
|
|
|
|
|
operations.push(SHARE_ADMIN, DIVIDER);
|
|
|
|
|
if (repo.encrypted) {
|
|
|
|
|
operations.push(CHANGE_PASSWORD);
|
|
|
|
|
}
|
|
|
|
|
if (repo.encrypted && enableResetEncryptedRepoPassword && isEmailConfigured) {
|
|
|
|
|
operations.push(RESET_PASSWORD);
|
|
|
|
|
}
|
|
|
|
|
if (repo.permission === 'r' || repo.permission === 'rw') {
|
|
|
|
|
const monitorOp = repo.monitored ? UNWATCH_FILE_CHANGES : WATCH_FILE_CHANGES;
|
|
|
|
|
operations.push(monitorOp);
|
|
|
|
|
}
|
|
|
|
|
if (Utils.isDesktop()) {
|
2024-11-06 20:12:39 +08:00
|
|
|
|
operations.push(DIVIDER);
|
|
|
|
|
const subOpList = [API_TOKEN];
|
2024-10-18 10:54:58 +08:00
|
|
|
|
operations.push({ ...ADVANCED, subOpList });
|
|
|
|
|
}
|
|
|
|
|
return operations;
|
|
|
|
|
} else {
|
|
|
|
|
operations.push(UNSHARE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (isRepoOwner || isAdmin) {
|
|
|
|
|
operations.push(SHARE);
|
|
|
|
|
}
|
|
|
|
|
if (isStaff || isRepoOwner || isAdmin) {
|
|
|
|
|
operations.push(UNSHARE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (repo.permission === 'r' || repo.permission === 'rw') {
|
|
|
|
|
const monitorOp = repo.monitored ? UNWATCH_FILE_CHANGES : WATCH_FILE_CHANGES;
|
|
|
|
|
operations.push(monitorOp);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (isRepoOwner) {
|
|
|
|
|
operations.push(SHARE);
|
|
|
|
|
}
|
|
|
|
|
if (isStaff || isRepoOwner) {
|
|
|
|
|
operations.push(UNSHARE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return operations;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
sharePerms: function (permission) {
|
2018-12-19 16:07:56 +08:00
|
|
|
|
var title;
|
2024-07-18 11:58:42 +08:00
|
|
|
|
switch (permission) {
|
2018-12-19 16:07:56 +08:00
|
|
|
|
case 'rw':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Read-Write');
|
2018-12-19 16:07:56 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Read-Only');
|
2018-12-19 16:07:56 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'admin':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Admin');
|
2018-12-19 16:07:56 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'cloud-edit':
|
2019-06-25 17:58:02 +08:00
|
|
|
|
title = gettext('Online Read-Write');
|
2018-12-19 16:07:56 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'preview':
|
2019-06-25 17:58:02 +08:00
|
|
|
|
title = gettext('Online Read-Only');
|
2018-12-19 16:07:56 +08:00
|
|
|
|
break;
|
2023-07-10 15:48:34 +08:00
|
|
|
|
case 'invisible':
|
|
|
|
|
title = gettext('Invisible');
|
|
|
|
|
break;
|
2018-12-19 16:07:56 +08:00
|
|
|
|
}
|
|
|
|
|
return title;
|
2018-11-22 16:49:48 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
sharePermsExplanation: function (permission) {
|
2019-01-24 17:15:01 +08:00
|
|
|
|
var title;
|
2024-07-18 11:58:42 +08:00
|
|
|
|
switch (permission) {
|
2019-01-24 17:15:01 +08:00
|
|
|
|
case 'rw':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('User can read, write, upload, download and sync files.');
|
2019-01-24 17:15:01 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('User can read, download and sync files.');
|
2019-01-24 17:15:01 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'admin':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('Besides Write permission, user can also share the library.');
|
2019-01-24 17:15:01 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'cloud-edit':
|
2019-04-17 11:02:23 +08:00
|
|
|
|
title = gettext('User can view and edit file online via browser. Files can\'t be downloaded.');
|
2019-01-24 17:15:01 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'preview':
|
2019-01-31 17:37:02 +08:00
|
|
|
|
title = gettext('User can only view files online via browser. Files can\'t be downloaded.');
|
2019-01-24 17:15:01 +08:00
|
|
|
|
break;
|
2023-07-10 15:48:34 +08:00
|
|
|
|
case 'invisible':
|
|
|
|
|
title = gettext('User can not see this folder.');
|
|
|
|
|
break;
|
2019-01-24 17:15:01 +08:00
|
|
|
|
}
|
|
|
|
|
return title;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getShareLinkPermissionObject: function (permission) {
|
2019-08-20 12:00:58 +08:00
|
|
|
|
switch (permission) {
|
|
|
|
|
case 'preview_download':
|
|
|
|
|
return {
|
2020-11-02 13:56:35 +08:00
|
|
|
|
value: permission,
|
|
|
|
|
text: gettext('Preview and download'),
|
2019-08-20 12:00:58 +08:00
|
|
|
|
permissionDetails: {
|
|
|
|
|
'can_edit': false,
|
2020-10-20 16:24:58 +08:00
|
|
|
|
'can_download': true,
|
|
|
|
|
'can_upload': false
|
2019-08-20 12:00:58 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
case 'preview_only':
|
|
|
|
|
return {
|
2020-11-02 13:56:35 +08:00
|
|
|
|
value: permission,
|
|
|
|
|
text: gettext('Preview only'),
|
2019-08-20 12:00:58 +08:00
|
|
|
|
permissionDetails: {
|
|
|
|
|
'can_edit': false,
|
2020-10-20 16:24:58 +08:00
|
|
|
|
'can_download': false,
|
|
|
|
|
'can_upload': false
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
case 'download_upload':
|
|
|
|
|
return {
|
2020-11-02 13:56:35 +08:00
|
|
|
|
value: permission,
|
|
|
|
|
text: gettext('Download and upload'),
|
2020-10-20 16:24:58 +08:00
|
|
|
|
permissionDetails: {
|
|
|
|
|
'can_edit': false,
|
|
|
|
|
'can_download': true,
|
2020-11-02 13:56:35 +08:00
|
|
|
|
'can_upload': true
|
2019-08-20 12:00:58 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
case 'edit_download':
|
|
|
|
|
return {
|
|
|
|
|
value: permission,
|
2020-11-02 13:56:35 +08:00
|
|
|
|
text: gettext('Edit on cloud and download'),
|
2019-08-20 12:00:58 +08:00
|
|
|
|
permissionDetails: {
|
|
|
|
|
'can_edit': true,
|
2020-10-20 16:24:58 +08:00
|
|
|
|
'can_download': true,
|
|
|
|
|
'can_upload': false
|
2019-08-20 12:00:58 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
2019-10-12 14:54:25 +08:00
|
|
|
|
case 'cloud_edit':
|
|
|
|
|
return {
|
|
|
|
|
value: permission,
|
2019-11-29 15:17:00 +08:00
|
|
|
|
text: gettext('Edit on cloud only'),
|
2019-10-12 14:54:25 +08:00
|
|
|
|
permissionDetails: {
|
|
|
|
|
'can_edit': true,
|
2020-10-20 16:24:58 +08:00
|
|
|
|
'can_download': false,
|
|
|
|
|
'can_upload': false
|
2019-10-12 14:54:25 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
2019-08-20 12:00:58 +08:00
|
|
|
|
}
|
2019-10-12 14:54:25 +08:00
|
|
|
|
return {
|
|
|
|
|
text: '',
|
|
|
|
|
};
|
2019-08-20 12:00:58 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
formatSize: function (options) {
|
2018-11-22 16:49:48 +08:00
|
|
|
|
/*
|
|
|
|
|
* param: {bytes, precision}
|
|
|
|
|
*/
|
|
|
|
|
var bytes = options.bytes;
|
|
|
|
|
var precision = options.precision || 0;
|
|
|
|
|
|
2018-11-30 17:18:41 +08:00
|
|
|
|
var kilobyte = 1000;
|
|
|
|
|
var megabyte = kilobyte * 1000;
|
|
|
|
|
var gigabyte = megabyte * 1000;
|
|
|
|
|
var terabyte = gigabyte * 1000;
|
2018-11-22 16:49:48 +08:00
|
|
|
|
|
|
|
|
|
if ((bytes >= 0) && (bytes < kilobyte)) {
|
|
|
|
|
return bytes + ' B';
|
|
|
|
|
|
|
|
|
|
} else if ((bytes >= kilobyte) && (bytes < megabyte)) {
|
|
|
|
|
return (bytes / kilobyte).toFixed(precision) + ' KB';
|
|
|
|
|
|
|
|
|
|
} else if ((bytes >= megabyte) && (bytes < gigabyte)) {
|
|
|
|
|
return (bytes / megabyte).toFixed(precision) + ' MB';
|
|
|
|
|
|
|
|
|
|
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
|
|
|
|
|
return (bytes / gigabyte).toFixed(precision) + ' GB';
|
|
|
|
|
|
|
|
|
|
} else if (bytes >= terabyte) {
|
|
|
|
|
return (bytes / terabyte).toFixed(precision) + ' TB';
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
return bytes + ' B';
|
|
|
|
|
}
|
2018-12-13 20:42:51 +08:00
|
|
|
|
},
|
2018-11-19 11:53:44 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
formatBitRate: function (bits) {
|
2019-01-08 11:26:20 +08:00
|
|
|
|
var Bs;
|
|
|
|
|
if (typeof bits !== 'number') {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
return '';
|
2019-01-08 11:26:20 +08:00
|
|
|
|
}
|
|
|
|
|
Bs = bits / 8;
|
|
|
|
|
if (Bs >= 1000000000) {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
return (Bs / 1000000000).toFixed(2) + ' GB/s';
|
2019-01-08 11:26:20 +08:00
|
|
|
|
}
|
|
|
|
|
if (Bs >= 1000000) {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
return (Bs / 1000000).toFixed(2) + ' MB/s';
|
2019-01-08 11:26:20 +08:00
|
|
|
|
}
|
|
|
|
|
if (Bs >= 1000) {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
return (Bs / 1000).toFixed(2) + ' kB/s';
|
2019-01-08 11:26:20 +08:00
|
|
|
|
}
|
|
|
|
|
return Bs.toFixed(2) + ' B/s';
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isMarkdownFile: function (filePath) {
|
2018-12-13 20:42:51 +08:00
|
|
|
|
let index = filePath.lastIndexOf('.');
|
|
|
|
|
if (index === -1) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
let type = filePath.substring(index).toLowerCase();
|
|
|
|
|
if (type === '.md' || type === '.markdown') {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-28 15:19:10 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isSdocFile: function (filePath) {
|
2023-06-20 21:18:07 +08:00
|
|
|
|
let index = filePath.lastIndexOf('.');
|
|
|
|
|
if (index === -1) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
let type = filePath.substring(index).toLowerCase();
|
|
|
|
|
if (type === '.sdoc') {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-09-10 11:00:53 +08:00
|
|
|
|
isDocxFile: function (filePath) {
|
|
|
|
|
let index = filePath.lastIndexOf('.');
|
|
|
|
|
if (index === -1) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
let type = filePath.substring(index).toLowerCase();
|
|
|
|
|
if (type === '.docx') {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-11-11 17:31:59 +08:00
|
|
|
|
isPptxFile: function (filePath) {
|
|
|
|
|
let index = filePath.lastIndexOf('.');
|
|
|
|
|
if (index === -1) {
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
let type = filePath.substring(index).toLowerCase();
|
|
|
|
|
if (type === '.pptx') {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-09-10 15:18:07 +08:00
|
|
|
|
isDescriptionSupportedFile: function (filePath) {
|
2024-12-25 13:53:26 +08:00
|
|
|
|
return Utils.isSdocFile(filePath) ||
|
|
|
|
|
Utils.isMarkdownFile(filePath) ||
|
|
|
|
|
Utils.pdfCheck(filePath) ||
|
|
|
|
|
Utils.isDocxFile(filePath) ||
|
|
|
|
|
Utils.isPptxFile(filePath) ||
|
|
|
|
|
Utils.imageCheck(filePath);
|
2024-08-30 17:45:34 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isFileMetadata: function (type) {
|
2024-06-29 17:58:27 +08:00
|
|
|
|
return type === PRIVATE_FILE_TYPE.FILE_EXTENDED_PROPERTIES;
|
|
|
|
|
},
|
|
|
|
|
|
2024-11-22 17:11:55 +08:00
|
|
|
|
isTags: function (type) {
|
|
|
|
|
return type === PRIVATE_FILE_TYPE.TAGS_PROPERTIES;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isInternalFileLink: function (url, repoID) {
|
2020-04-08 16:51:21 +08:00
|
|
|
|
var re = new RegExp(serviceURL + '/lib/' + repoID + '/file.*');
|
|
|
|
|
return re.test(url);
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isInternalMarkdownLink: function (url, repoID) {
|
2023-09-13 08:40:50 +08:00
|
|
|
|
// eslint-disable-next-line
|
2025-03-17 12:50:50 +08:00
|
|
|
|
var re = new RegExp(serviceURL + '/lib/' + repoID + '.*(\\.md)$');
|
2019-01-17 16:33:27 +08:00
|
|
|
|
return re.test(url);
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isInternalDirLink: function (url, repoID) {
|
2019-01-24 15:41:01 +08:00
|
|
|
|
var re = new RegExp(serviceURL + '/library/' + repoID + '.*');
|
2019-01-17 16:33:27 +08:00
|
|
|
|
return re.test(url);
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getPathFromInternalMarkdownLink: function (url, repoID) {
|
2023-09-13 08:40:50 +08:00
|
|
|
|
// eslint-disable-next-line
|
2025-03-17 12:50:50 +08:00
|
|
|
|
var re = new RegExp(serviceURL + '/lib/' + repoID + '/file' + '.*(\\.md)$');
|
2019-01-17 16:33:27 +08:00
|
|
|
|
var array = re.exec(url);
|
|
|
|
|
var path = decodeURIComponent(array[1]);
|
|
|
|
|
return path;
|
|
|
|
|
},
|
2020-11-02 13:56:35 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getPathFromInternalDirLink: function (url, repoID) {
|
2019-01-30 11:48:15 +08:00
|
|
|
|
var re = new RegExp(serviceURL + '/library/' + repoID + '(/.*)');
|
2019-01-17 16:33:27 +08:00
|
|
|
|
var array = re.exec(url);
|
|
|
|
|
var path = decodeURIComponent(array[1]);
|
2019-01-30 11:48:15 +08:00
|
|
|
|
path = path.slice(1);
|
|
|
|
|
path = path.slice(path.indexOf('/'));
|
2019-01-17 16:33:27 +08:00
|
|
|
|
return path;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isWikiInternalMarkdownLink: function (url, slug) {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
slug = encodeURIComponent(slug);
|
2023-09-13 08:40:50 +08:00
|
|
|
|
// eslint-disable-next-line
|
2025-03-17 12:50:50 +08:00
|
|
|
|
var re = new RegExp(serviceURL + '/published/' + slug + '.*(\\.md)$');
|
2019-01-24 15:41:01 +08:00
|
|
|
|
return re.test(url);
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isWikiInternalDirLink: function (url, slug) {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
slug = encodeURIComponent(slug);
|
2019-04-24 08:40:23 +00:00
|
|
|
|
var re = new RegExp(serviceURL + '/published/' + slug + '.*');
|
2019-01-24 15:41:01 +08:00
|
|
|
|
return re.test(url);
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getPathFromWikiInternalMarkdownLink: function (url, slug) {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
slug = encodeURIComponent(slug);
|
2023-09-13 08:40:50 +08:00
|
|
|
|
// eslint-disable-next-line
|
2025-03-17 12:50:50 +08:00
|
|
|
|
var re = new RegExp(serviceURL + '/published/' + slug + '.*(\\.md)$');
|
2019-01-24 15:41:01 +08:00
|
|
|
|
var array = re.exec(url);
|
2019-01-30 11:48:15 +08:00
|
|
|
|
var path = array[1];
|
|
|
|
|
try {
|
|
|
|
|
path = decodeURIComponent(path);
|
2024-07-18 11:58:42 +08:00
|
|
|
|
} catch (err) {
|
2019-01-30 11:48:15 +08:00
|
|
|
|
path = path.replace(/%/g, '%25');
|
|
|
|
|
path = decodeURIComponent(path);
|
|
|
|
|
}
|
2019-01-24 15:41:01 +08:00
|
|
|
|
return path;
|
|
|
|
|
},
|
2020-11-02 13:56:35 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getPathFromWikiInternalDirLink: function (url, slug) {
|
2019-01-31 17:37:02 +08:00
|
|
|
|
slug = encodeURIComponent(slug);
|
2019-04-24 08:40:23 +00:00
|
|
|
|
var re = new RegExp(serviceURL + '/published/' + slug + '(/.*)');
|
2019-01-24 15:41:01 +08:00
|
|
|
|
var array = re.exec(url);
|
2019-01-30 11:48:15 +08:00
|
|
|
|
var path = array[1];
|
|
|
|
|
try {
|
|
|
|
|
path = decodeURIComponent(path);
|
2024-07-18 11:58:42 +08:00
|
|
|
|
} catch (err) {
|
2019-01-30 11:48:15 +08:00
|
|
|
|
path = path.replace(/%/g, '%25');
|
|
|
|
|
path = decodeURIComponent(path);
|
|
|
|
|
}
|
2019-01-24 15:41:01 +08:00
|
|
|
|
return path;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
compareTwoWord: function (wordA, wordB) {
|
2018-12-28 15:19:10 +08:00
|
|
|
|
// compare wordA and wordB at lower case
|
|
|
|
|
// if wordA >= wordB, return 1
|
|
|
|
|
// if wordA < wordB, return -1
|
|
|
|
|
|
2023-05-08 17:29:09 +08:00
|
|
|
|
return compareTwoString(wordA, wordB);
|
2018-12-28 15:19:10 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// compare two strings which may have digits in them
|
|
|
|
|
// and compare those digits as number instead of string
|
2024-07-18 11:58:42 +08:00
|
|
|
|
compareStrWithNumbersIn: function (a, b) {
|
2018-12-28 15:19:10 +08:00
|
|
|
|
var reParts = /\d+|\D+/g;
|
|
|
|
|
var reDigit = /\d/;
|
|
|
|
|
var aParts = a.match(reParts);
|
|
|
|
|
var bParts = b.match(reParts);
|
|
|
|
|
var isDigitPart;
|
|
|
|
|
var len = Math.min(aParts.length, bParts.length);
|
2024-07-18 11:58:42 +08:00
|
|
|
|
var aPart; var bPart;
|
2018-12-28 15:19:10 +08:00
|
|
|
|
|
|
|
|
|
if (aParts && bParts &&
|
|
|
|
|
(isDigitPart = reDigit.test(aParts[0])) == reDigit.test(bParts[0])) {
|
|
|
|
|
// Loop through each substring part to compare the overall strings.
|
|
|
|
|
for (var i = 0; i < len; i++) {
|
|
|
|
|
aPart = aParts[i];
|
|
|
|
|
bPart = bParts[i];
|
|
|
|
|
|
|
|
|
|
if (isDigitPart) {
|
|
|
|
|
aPart = parseInt(aPart, 10);
|
|
|
|
|
bPart = parseInt(bPart, 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aPart != bPart) {
|
|
|
|
|
return aPart < bPart ? -1 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Toggle the value of isDigitPart since the parts will alternate.
|
|
|
|
|
isDigitPart = !isDigitPart;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use normal comparison.
|
|
|
|
|
return (a >= b) - (a <= b);
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
sortRepos: function (repos, sortBy, sortOrder) {
|
2018-12-28 15:19:10 +08:00
|
|
|
|
const _this = this;
|
|
|
|
|
let comparator;
|
|
|
|
|
|
|
|
|
|
switch (`${sortBy}-${sortOrder}`) {
|
|
|
|
|
case 'name-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2018-12-28 15:19:10 +08:00
|
|
|
|
if (!a.repo_name) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (!b.repo_name) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
var result = _this.compareTwoWord(a.repo_name, b.repo_name);
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'name-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2018-12-28 15:19:10 +08:00
|
|
|
|
if (!a.repo_name) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (!b.repo_name) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
var result = _this.compareTwoWord(a.repo_name, b.repo_name);
|
|
|
|
|
return -result;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'time-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2018-12-28 15:19:10 +08:00
|
|
|
|
return a.last_modified < b.last_modified ? -1 : 1;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'time-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2018-12-28 15:19:10 +08:00
|
|
|
|
return a.last_modified < b.last_modified ? 1 : -1;
|
|
|
|
|
};
|
|
|
|
|
break;
|
2019-05-29 13:57:12 +08:00
|
|
|
|
case 'size-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2019-05-29 15:11:18 +08:00
|
|
|
|
if (a.size === b.size) {
|
2019-05-29 16:44:37 +08:00
|
|
|
|
let result = _this.compareTwoWord(a.repo_name, b.repo_name);
|
2019-05-29 15:11:18 +08:00
|
|
|
|
return result;
|
|
|
|
|
}
|
2019-05-30 16:01:18 +08:00
|
|
|
|
return a.size_original < b.size_original ? -1 : 1;
|
2019-05-29 13:57:12 +08:00
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'size-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2019-05-29 15:11:18 +08:00
|
|
|
|
if (a.size === b.size) {
|
2019-05-29 16:44:37 +08:00
|
|
|
|
let result = _this.compareTwoWord(a.repo_name, b.repo_name);
|
2019-05-29 15:11:18 +08:00
|
|
|
|
return -result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-30 16:01:18 +08:00
|
|
|
|
return a.size_original < b.size_original ? 1 : -1;
|
2019-05-29 13:57:12 +08:00
|
|
|
|
};
|
|
|
|
|
break;
|
2018-12-28 15:19:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
repos.sort(comparator);
|
|
|
|
|
return repos;
|
2019-01-04 15:06:27 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
sortDirents: function (items, sortBy, sortOrder) {
|
2019-01-04 15:06:27 +08:00
|
|
|
|
const _this = this;
|
|
|
|
|
let comparator;
|
|
|
|
|
|
|
|
|
|
switch (`${sortBy}-${sortOrder}`) {
|
|
|
|
|
case 'name-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2019-01-04 15:06:27 +08:00
|
|
|
|
var result = _this.compareTwoWord(a.name, b.name);
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'name-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2019-01-04 15:06:27 +08:00
|
|
|
|
var result = _this.compareTwoWord(a.name, b.name);
|
|
|
|
|
return -result;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'time-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2019-01-04 15:06:27 +08:00
|
|
|
|
return a.mtime < b.mtime ? -1 : 1;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'time-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2019-01-04 15:06:27 +08:00
|
|
|
|
return a.mtime < b.mtime ? 1 : -1;
|
|
|
|
|
};
|
|
|
|
|
break;
|
2019-05-29 13:57:12 +08:00
|
|
|
|
case 'size-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2019-05-29 13:57:12 +08:00
|
|
|
|
if (a.type == 'dir' && b.type == 'dir') {
|
2020-02-01 16:22:22 +08:00
|
|
|
|
return 0;
|
2020-11-02 13:56:35 +08:00
|
|
|
|
}
|
2019-05-30 16:01:18 +08:00
|
|
|
|
return a.size_original < b.size_original ? -1 : 1;
|
2019-05-29 13:57:12 +08:00
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'size-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2019-05-29 13:57:12 +08:00
|
|
|
|
if (a.type == 'dir' && b.type == 'dir') {
|
2020-02-01 16:22:22 +08:00
|
|
|
|
return 0;
|
2020-11-02 13:56:35 +08:00
|
|
|
|
}
|
2019-05-30 16:01:18 +08:00
|
|
|
|
return a.size_original < b.size_original ? 1 : -1;
|
2019-05-29 13:57:12 +08:00
|
|
|
|
};
|
|
|
|
|
break;
|
2019-01-04 15:06:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
items.sort((a, b) => {
|
|
|
|
|
if (a.type == 'dir' && b.type == 'file') {
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (a.type == 'file' && b.type == 'dir') {
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
return comparator(a, b);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return items;
|
2019-01-24 15:41:01 +08:00
|
|
|
|
},
|
|
|
|
|
|
2020-01-31 19:01:08 +08:00
|
|
|
|
// sort dirents in shared folder
|
2024-07-18 11:58:42 +08:00
|
|
|
|
sortDirentsInSharedDir: function (items, sortBy, sortOrder) {
|
2020-01-31 19:01:08 +08:00
|
|
|
|
const _this = this;
|
|
|
|
|
let comparator;
|
|
|
|
|
|
|
|
|
|
switch (`${sortBy}-${sortOrder}`) {
|
|
|
|
|
case 'name-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2020-01-31 19:01:08 +08:00
|
|
|
|
let result;
|
|
|
|
|
if (a.is_dir) {
|
|
|
|
|
result = _this.compareTwoWord(a.folder_name, b.folder_name);
|
|
|
|
|
} else {
|
|
|
|
|
result = _this.compareTwoWord(a.file_name, b.file_name);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'name-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2020-01-31 19:01:08 +08:00
|
|
|
|
let result;
|
|
|
|
|
if (a.is_dir) {
|
|
|
|
|
result = _this.compareTwoWord(a.folder_name, b.folder_name);
|
|
|
|
|
} else {
|
|
|
|
|
result = _this.compareTwoWord(a.file_name, b.file_name);
|
|
|
|
|
}
|
|
|
|
|
return -result;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'time-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2020-01-31 19:01:08 +08:00
|
|
|
|
return a.last_modified < b.last_modified ? -1 : 1;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'time-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2020-01-31 19:01:08 +08:00
|
|
|
|
return a.last_modified < b.last_modified ? 1 : -1;
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'size-asc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2020-01-31 19:01:08 +08:00
|
|
|
|
if (a.is_dir) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
return a.size < b.size ? -1 : 1;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
case 'size-desc':
|
2024-07-18 11:58:42 +08:00
|
|
|
|
comparator = function (a, b) {
|
2020-01-31 19:01:08 +08:00
|
|
|
|
if (a.is_dir) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
return a.size < b.size ? 1 : -1;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
items.sort((a, b) => {
|
|
|
|
|
if (a.is_dir && !b.is_dir) {
|
|
|
|
|
return -1;
|
|
|
|
|
} else if (!a.is_dir && b.is_dir) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
return comparator(a, b);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return items;
|
|
|
|
|
},
|
|
|
|
|
|
2019-07-04 16:20:13 +08:00
|
|
|
|
/*
|
|
|
|
|
* only used in the 'catch' part of a seafileAPI request
|
|
|
|
|
*/
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getErrorMsg: function (error, showPermissionDeniedTip) {
|
2019-07-04 16:20:13 +08:00
|
|
|
|
let errorMsg = '';
|
|
|
|
|
if (error.response) {
|
2019-12-05 15:45:16 +08:00
|
|
|
|
if (error.response.status == 403) {
|
2019-12-18 16:23:34 +08:00
|
|
|
|
if (showPermissionDeniedTip) {
|
2019-12-05 15:45:16 +08:00
|
|
|
|
toaster.danger(
|
2019-12-18 16:23:34 +08:00
|
|
|
|
<PermissionDeniedTip />,
|
2024-07-18 11:58:42 +08:00
|
|
|
|
{ id: 'permission_denied', duration: 3600 }
|
2019-12-05 15:45:16 +08:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
errorMsg = gettext('Permission denied');
|
2024-09-23 22:37:06 +08:00
|
|
|
|
} else if (error.response.status == 429) {
|
|
|
|
|
errorMsg = gettext('Too many requests');
|
2019-12-05 15:45:16 +08:00
|
|
|
|
} else if (error.response.data &&
|
|
|
|
|
error.response.data['error_msg']) {
|
2019-07-04 16:20:13 +08:00
|
|
|
|
errorMsg = error.response.data['error_msg'];
|
|
|
|
|
} else {
|
|
|
|
|
errorMsg = gettext('Error');
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2024-12-16 09:43:40 +08:00
|
|
|
|
if (typeof error === 'object' && error.name) {
|
|
|
|
|
errorMsg = error.name;
|
|
|
|
|
} else {
|
|
|
|
|
errorMsg = gettext('Please check the network.');
|
|
|
|
|
}
|
|
|
|
|
// eslint-disable-next-line
|
|
|
|
|
console.log(error);
|
2019-07-04 16:20:13 +08:00
|
|
|
|
}
|
|
|
|
|
return errorMsg;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
changeMarkdownNodes: function (nodes, fn) {
|
2023-09-13 08:40:50 +08:00
|
|
|
|
nodes.forEach((item) => {
|
2020-11-02 13:56:35 +08:00
|
|
|
|
fn(item);
|
2024-06-01 09:09:42 +08:00
|
|
|
|
if (item.children && item.children.length > 0) {
|
2020-11-02 13:56:35 +08:00
|
|
|
|
Utils.changeMarkdownNodes(item.children, fn);
|
2019-01-24 15:41:01 +08:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return nodes;
|
|
|
|
|
},
|
2019-01-04 15:06:27 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
chooseLanguage: function (suffix) {
|
2019-02-01 18:44:10 +08:00
|
|
|
|
let mode;
|
2024-07-18 11:58:42 +08:00
|
|
|
|
switch (suffix) {
|
2019-02-01 18:44:10 +08:00
|
|
|
|
case 'py':
|
|
|
|
|
mode = 'python';
|
|
|
|
|
break;
|
|
|
|
|
case 'js':
|
|
|
|
|
mode = 'javascript';
|
|
|
|
|
break;
|
|
|
|
|
case 'c':
|
2022-12-29 12:21:47 +08:00
|
|
|
|
mode = 'c';
|
2019-02-01 18:44:10 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'cpp':
|
2022-12-29 12:21:47 +08:00
|
|
|
|
mode = 'cpp';
|
2019-02-01 18:44:10 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'cs':
|
2022-12-29 12:21:47 +08:00
|
|
|
|
mode = 'csharp';
|
|
|
|
|
break;
|
|
|
|
|
case 'java':
|
|
|
|
|
mode = 'java';
|
2019-02-01 18:44:10 +08:00
|
|
|
|
break;
|
|
|
|
|
case 'mdf':
|
|
|
|
|
mode = 'text/x-sql';
|
|
|
|
|
break;
|
|
|
|
|
case 'html':
|
2022-12-29 12:21:47 +08:00
|
|
|
|
mode = 'html';
|
|
|
|
|
break;
|
|
|
|
|
case 'sh':
|
|
|
|
|
mode = 'shell';
|
2019-02-01 18:44:10 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
mode = suffix;
|
|
|
|
|
}
|
|
|
|
|
return mode;
|
|
|
|
|
},
|
|
|
|
|
|
2019-02-27 14:14:28 +08:00
|
|
|
|
DARK_COLOR_MAP: {
|
|
|
|
|
// old color
|
|
|
|
|
'red': '#D11507',
|
|
|
|
|
'orange': '#FF8C00',
|
|
|
|
|
'yellow': '#EDEF00',
|
|
|
|
|
'green': '#006400',
|
|
|
|
|
'cyan': '#00E0E1',
|
|
|
|
|
'blue': '#2510A3',
|
|
|
|
|
'indigo': '#350C56',
|
|
|
|
|
'purple': '#551054',
|
|
|
|
|
'pink': '#E3A5B0',
|
|
|
|
|
'azure': '#C4D0D0',
|
|
|
|
|
'lime': '#00E100',
|
|
|
|
|
'teal': '#006A6B',
|
|
|
|
|
'gray': '#545454',
|
|
|
|
|
|
|
|
|
|
// new color
|
|
|
|
|
'#FFA8A8': '#E49090',
|
|
|
|
|
'#FFA94D': '#E39136',
|
|
|
|
|
'#FFD43B': '#E0B815',
|
|
|
|
|
'#A0EC50': '#83CF32',
|
|
|
|
|
'#A9E34B': '#8DC72E',
|
|
|
|
|
'#63E6BE': '#43CAA4',
|
|
|
|
|
'#4FD2C9': '#2DB9B0',
|
|
|
|
|
'#72C3FC': '#57ABE3',
|
|
|
|
|
'#91A7FF': '#7A91E7',
|
|
|
|
|
'#E599F7': '#CC82DE',
|
|
|
|
|
'#B197FC': '#9B82E5',
|
|
|
|
|
'#F783AC': '#DF6D97',
|
|
|
|
|
'#CED4DA': '#A8ADB2',
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getDarkColor: function (color) {
|
2019-02-27 14:14:28 +08:00
|
|
|
|
let darkColor;
|
|
|
|
|
darkColor = this.DARK_COLOR_MAP[color];
|
|
|
|
|
return darkColor;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getCopySuccessfulMessage: function (dirNames) {
|
2019-04-11 11:07:31 +08:00
|
|
|
|
let message;
|
|
|
|
|
let dirNamesLength = dirNames.length;
|
|
|
|
|
if (dirNamesLength === 1) {
|
|
|
|
|
message = gettext('Successfully copied %(name)s.');
|
|
|
|
|
} else if (dirNamesLength === 2) {
|
|
|
|
|
message = gettext('Successfully copied %(name)s and 1 other item.');
|
|
|
|
|
} else {
|
|
|
|
|
message = gettext('Successfully copied %(name)s and %(amount)s other items.');
|
|
|
|
|
message = message.replace('%(amount)s', dirNamesLength - 1);
|
|
|
|
|
}
|
|
|
|
|
message = message.replace('%(name)s', dirNames[0]);
|
|
|
|
|
return message;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getMoveSuccessMessage: function (dirNames) {
|
2019-04-11 11:07:31 +08:00
|
|
|
|
let message;
|
|
|
|
|
let dirNamesLength = dirNames.length;
|
|
|
|
|
if (dirNamesLength === 1) {
|
|
|
|
|
message = gettext('Successfully moved %(name)s.');
|
|
|
|
|
} else if (dirNamesLength === 2) {
|
|
|
|
|
message = gettext('Successfully moved %(name)s and 1 other item.');
|
|
|
|
|
} else {
|
|
|
|
|
message = gettext('Successfully moved %(name)s and %(amount)s other items.');
|
|
|
|
|
message = message.replace('%(amount)s', dirNamesLength - 1);
|
|
|
|
|
}
|
|
|
|
|
message = message.replace('%(name)s', dirNames[0]);
|
|
|
|
|
return message;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getCopyFailedMessage: function (dirNames) {
|
2019-04-11 11:07:31 +08:00
|
|
|
|
let message;
|
|
|
|
|
let dirNamesLength = dirNames.length;
|
|
|
|
|
|
|
|
|
|
if (dirNamesLength > 1) {
|
|
|
|
|
message = gettext('Failed to copy %(name)s and %(amount)s other item(s).');
|
|
|
|
|
message = message.replace('%(amount)s', dirNamesLength - 1);
|
|
|
|
|
} else {
|
|
|
|
|
message = gettext('Failed to copy %(name)s.');
|
|
|
|
|
}
|
|
|
|
|
message = message.replace('%(name)s', dirNames[0]);
|
|
|
|
|
return message;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getMoveFailedMessage: function (dirNames) {
|
2019-04-11 11:07:31 +08:00
|
|
|
|
let message;
|
|
|
|
|
let dirNamesLength = dirNames.length;
|
|
|
|
|
if (dirNamesLength > 1) {
|
|
|
|
|
message = gettext('Failed to move %(name)s and %(amount)s other item(s).');
|
|
|
|
|
message = message.replace('%(amount)s', dirNamesLength - 1);
|
|
|
|
|
} else {
|
|
|
|
|
message = gettext('Failed to move %(name)s.');
|
|
|
|
|
}
|
|
|
|
|
message = message.replace('%(name)s', dirNames[0]);
|
|
|
|
|
return message;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
handleSearchedItemClick: function (searchedItem) {
|
2019-04-26 11:34:11 +08:00
|
|
|
|
if (searchedItem.is_dir === true) {
|
|
|
|
|
let url = siteRoot + 'library/' + searchedItem.repo_id + '/' + searchedItem.repo_name + searchedItem.path;
|
|
|
|
|
let newWindow = window.open('about:blank');
|
|
|
|
|
newWindow.location.href = url;
|
|
|
|
|
} else {
|
|
|
|
|
let url = siteRoot + 'lib/' + searchedItem.repo_id + '/file' + Utils.encodePath(searchedItem.path);
|
|
|
|
|
let newWindow = window.open('about:blank');
|
|
|
|
|
newWindow.location.href = url;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2025-03-17 12:31:33 +08:00
|
|
|
|
generateSecureRandomInRange: function (min, max) {
|
|
|
|
|
const start = Math.min(min, max);
|
|
|
|
|
const end = Math.max(min, max);
|
|
|
|
|
const range = end - start + 1;
|
|
|
|
|
const byteSize = Math.ceil(Math.log2(range) / 8);
|
|
|
|
|
|
|
|
|
|
const randomBytes = new Uint8Array(byteSize);
|
|
|
|
|
window.crypto.getRandomValues(randomBytes);
|
|
|
|
|
|
|
|
|
|
const randomValue = Array.from(randomBytes).reduce((pre, byte) => (pre << 8) | byte, 0);
|
|
|
|
|
return start + (randomValue % range);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
generatePassword: function (length) {
|
2021-11-03 16:11:56 +08:00
|
|
|
|
|
2023-04-17 15:32:52 +08:00
|
|
|
|
var password = '';
|
2021-11-03 16:11:56 +08:00
|
|
|
|
|
|
|
|
|
// 65~90:A~Z
|
2025-03-17 12:31:33 +08:00
|
|
|
|
password += String.fromCharCode(this.generateSecureRandomInRange(65, 90));
|
2021-11-03 16:11:56 +08:00
|
|
|
|
|
|
|
|
|
// 97~122:a~z
|
2025-03-17 12:31:33 +08:00
|
|
|
|
password += String.fromCharCode(this.generateSecureRandomInRange(97, 122));
|
2021-11-03 16:11:56 +08:00
|
|
|
|
|
|
|
|
|
// 48~57:0~9
|
2025-03-17 12:31:33 +08:00
|
|
|
|
password += String.fromCharCode(this.generateSecureRandomInRange(48, 57));
|
2021-11-03 16:11:56 +08:00
|
|
|
|
|
|
|
|
|
// 33~47:!~/
|
2025-03-17 12:31:33 +08:00
|
|
|
|
password += String.fromCharCode(this.generateSecureRandomInRange(33, 47));
|
2021-11-03 16:11:56 +08:00
|
|
|
|
|
|
|
|
|
// 33~47:!~/
|
|
|
|
|
// 48~57:0~9
|
|
|
|
|
// 58~64::~@
|
|
|
|
|
// 65~90:A~Z
|
|
|
|
|
// 91~96:[~`
|
|
|
|
|
// 97~122:a~z
|
|
|
|
|
// 123~127:{~
|
2024-07-01 18:33:57 +08:00
|
|
|
|
for (var i = 0; i < length - 4; i++) {
|
2025-03-17 12:31:33 +08:00
|
|
|
|
password += String.fromCharCode(this.generateSecureRandomInRange(33, 127));
|
2019-05-06 16:08:34 +08:00
|
|
|
|
}
|
2021-11-03 16:11:56 +08:00
|
|
|
|
|
2019-05-06 16:08:34 +08:00
|
|
|
|
return password;
|
2019-06-04 16:18:32 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
pathNormalize: function (originalPath) {
|
2019-06-20 18:25:10 +08:00
|
|
|
|
let oldPath = originalPath.split('/');
|
|
|
|
|
let newPath = [];
|
|
|
|
|
for (let i = 0; i < oldPath.length; i++) {
|
|
|
|
|
if (oldPath[i] === '.' || oldPath[i] === '') {
|
|
|
|
|
continue;
|
|
|
|
|
} else if (oldPath[i] === '..') {
|
|
|
|
|
newPath.pop();
|
|
|
|
|
} else {
|
|
|
|
|
newPath.push(oldPath[i]);
|
2019-06-20 14:40:11 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-20 18:03:26 +08:00
|
|
|
|
return newPath.join('/');
|
2019-06-20 14:40:11 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getEventData: function (event, data) {
|
2019-06-04 16:18:32 +08:00
|
|
|
|
if (event.target.dataset) {
|
|
|
|
|
return event.target.dataset[data];
|
|
|
|
|
}
|
|
|
|
|
return event.target.getAttribute('data-' + data);
|
2020-11-02 13:56:35 +08:00
|
|
|
|
|
2019-06-21 17:54:06 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2020-11-02 13:56:35 +08:00
|
|
|
|
* Check whether user has permission to share a dirent.
|
2019-06-21 21:09:12 +08:00
|
|
|
|
* If dirent is none, then check whether the user can share the repo
|
2019-06-21 21:16:05 +08:00
|
|
|
|
* scene 1: root path or folder path, control the share button in the toolbar
|
|
|
|
|
* scene 2: selected a dirent, control the share button in the toolbar dropdown-menu
|
|
|
|
|
* scene 3: dirent list(grid list), control the share button in the dirent-item or righe-menu
|
2020-11-02 13:56:35 +08:00
|
|
|
|
*
|
|
|
|
|
* @param {*} repoInfo
|
|
|
|
|
* @param {*} userDirPermission
|
|
|
|
|
* @param {*} dirent
|
2019-06-21 17:54:06 +08:00
|
|
|
|
*/
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isHasPermissionToShare: function (repoInfo, userDirPermission, dirent) {
|
2020-11-02 13:56:35 +08:00
|
|
|
|
|
2021-09-13 10:37:07 +08:00
|
|
|
|
const { isCustomPermission, customPermission } = Utils.getUserPermission(userDirPermission);
|
|
|
|
|
if (isCustomPermission) {
|
|
|
|
|
const { download_external_link } = customPermission.permission;
|
|
|
|
|
return download_external_link;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-21 17:54:06 +08:00
|
|
|
|
let { is_admin: isAdmin, is_virtual: isVirtual, encrypted: repoEncrypted, owner_email: ownerEmail } = repoInfo;
|
|
|
|
|
let isRepoOwner = ownerEmail === username;
|
|
|
|
|
|
2019-06-21 21:09:12 +08:00
|
|
|
|
if (repoEncrypted) {
|
2020-07-21 11:16:33 +08:00
|
|
|
|
return true;
|
2019-06-21 21:09:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-07 15:36:03 +08:00
|
|
|
|
// for 'file' & 'dir'
|
|
|
|
|
if (dirent) {
|
2020-08-04 07:37:58 +08:00
|
|
|
|
if (userDirPermission == 'rw' || userDirPermission == 'r') {
|
|
|
|
|
// can generate internal link
|
|
|
|
|
return true;
|
2019-06-21 17:54:06 +08:00
|
|
|
|
}
|
2019-06-21 21:09:12 +08:00
|
|
|
|
}
|
2019-06-21 17:54:06 +08:00
|
|
|
|
|
2019-06-21 21:09:12 +08:00
|
|
|
|
// the root path or the dirent type is dir
|
|
|
|
|
let hasGenerateShareLinkPermission = false;
|
|
|
|
|
if (canGenerateShareLink && (userDirPermission == 'rw' || userDirPermission == 'r')) {
|
|
|
|
|
hasGenerateShareLinkPermission = true;
|
|
|
|
|
return hasGenerateShareLinkPermission;
|
|
|
|
|
}
|
2019-06-21 17:54:06 +08:00
|
|
|
|
|
2019-06-21 21:09:12 +08:00
|
|
|
|
let hasGenerateUploadLinkPermission = false;
|
|
|
|
|
if (canGenerateUploadLink && (userDirPermission == 'rw')) {
|
|
|
|
|
hasGenerateUploadLinkPermission = true;
|
|
|
|
|
return hasGenerateUploadLinkPermission;
|
2019-06-21 17:54:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-21 21:09:12 +08:00
|
|
|
|
let hasDirPrivateSharePermission = false;
|
|
|
|
|
if (!isVirtual && (isRepoOwner || isAdmin)) {
|
|
|
|
|
hasDirPrivateSharePermission = true;
|
|
|
|
|
return hasDirPrivateSharePermission;
|
2019-06-21 17:54:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-21 21:09:12 +08:00
|
|
|
|
return false;
|
2019-08-02 20:53:39 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
registerGlobalVariable: function (namespace, key, value) {
|
2019-08-02 20:53:39 +08:00
|
|
|
|
if (!window[namespace]) {
|
|
|
|
|
window[namespace] = {};
|
|
|
|
|
}
|
|
|
|
|
window[namespace][key] = value;
|
2019-08-15 14:52:08 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
formatTime: function (seconds) {
|
2019-08-15 14:52:08 +08:00
|
|
|
|
var ss = parseInt(seconds);
|
|
|
|
|
var mm = 0;
|
|
|
|
|
var hh = 0;
|
|
|
|
|
if (ss > 60) {
|
|
|
|
|
mm = parseInt(ss / 60);
|
|
|
|
|
ss = parseInt(ss % 60);
|
|
|
|
|
}
|
|
|
|
|
if (mm > 60) {
|
|
|
|
|
hh = parseInt(mm / 60);
|
|
|
|
|
mm = parseInt(mm % 60);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var result = ('00' + parseInt(ss)).slice(-2);
|
|
|
|
|
if (mm > 0) {
|
|
|
|
|
result = ('00' + parseInt(mm)).slice(-2) + ':' + result;
|
|
|
|
|
} else {
|
|
|
|
|
result = '00:' + result;
|
|
|
|
|
}
|
|
|
|
|
if (hh > 0) {
|
|
|
|
|
result = ('00' + parseInt(hh)).slice(-2) + ':' + result;
|
|
|
|
|
} else {
|
|
|
|
|
result = '00:' + result;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
2019-10-19 11:21:49 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
hasNextPage(curPage, perPage, totalCount) {
|
|
|
|
|
return curPage * perPage < totalCount;
|
2021-08-12 15:02:03 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getStrengthLevel: function (pwd) {
|
2021-08-12 15:02:03 +08:00
|
|
|
|
const _this = this;
|
|
|
|
|
var num = 0;
|
|
|
|
|
|
|
|
|
|
if (pwd.length < shareLinkPasswordMinLength) {
|
2021-10-08 15:19:04 +08:00
|
|
|
|
return 0;
|
2021-08-12 15:02:03 +08:00
|
|
|
|
} else {
|
2021-10-08 15:19:04 +08:00
|
|
|
|
for (var i = 0; i < pwd.length; i++) {
|
|
|
|
|
// return the unicode
|
|
|
|
|
// bitwise OR
|
|
|
|
|
num |= _this.getCharMode(pwd.charCodeAt(i));
|
|
|
|
|
}
|
|
|
|
|
return _this.calculateBitwise(num);
|
2021-08-12 15:02:03 +08:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getCharMode: function (n) {
|
2021-08-12 15:02:03 +08:00
|
|
|
|
if (n >= 48 && n <= 57) // nums
|
2021-10-08 15:19:04 +08:00
|
|
|
|
return 1;
|
2021-08-12 15:02:03 +08:00
|
|
|
|
if (n >= 65 && n <= 90) // uppers
|
2021-10-08 15:19:04 +08:00
|
|
|
|
return 2;
|
2021-08-12 15:02:03 +08:00
|
|
|
|
if (n >= 97 && n <= 122) // lowers
|
2021-10-08 15:19:04 +08:00
|
|
|
|
return 4;
|
2021-08-12 15:02:03 +08:00
|
|
|
|
else
|
2021-10-08 15:19:04 +08:00
|
|
|
|
return 8;
|
2021-08-12 15:02:03 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
calculateBitwise: function (num) {
|
2021-08-12 15:02:03 +08:00
|
|
|
|
var level = 0;
|
2024-06-01 09:09:42 +08:00
|
|
|
|
for (var i = 0; i < 4; i++) {
|
2021-10-08 15:19:04 +08:00
|
|
|
|
// bitwise AND
|
2024-07-18 11:58:42 +08:00
|
|
|
|
if (num & 1) level++;
|
2021-10-08 15:19:04 +08:00
|
|
|
|
// Right logical shift
|
2024-07-18 11:58:42 +08:00
|
|
|
|
num >>>= 1;
|
2021-08-12 15:02:03 +08:00
|
|
|
|
}
|
|
|
|
|
return level;
|
|
|
|
|
},
|
2021-10-11 17:57:52 +08:00
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getSharedPermission: function (item) {
|
2021-09-13 10:37:07 +08:00
|
|
|
|
let permission = item.permission;
|
|
|
|
|
if (item.is_admin) {
|
|
|
|
|
permission = 'admin';
|
|
|
|
|
}
|
|
|
|
|
if (item.permission.startsWith('custom-')) {
|
|
|
|
|
permission = item.permission.slice(7);
|
|
|
|
|
}
|
|
|
|
|
return permission;
|
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
getUserPermission: function (userPerm) {
|
2021-09-13 10:37:07 +08:00
|
|
|
|
const { custom_permission } = window;
|
|
|
|
|
const common_permissions = ['rw', 'r', 'admin', 'cloud-edit', 'preview'];
|
2021-10-11 17:57:52 +08:00
|
|
|
|
// visit the shared repo(virtual repo) by custom permission
|
2021-09-13 10:37:07 +08:00
|
|
|
|
if (!custom_permission || common_permissions.indexOf(userPerm) > -1) {
|
|
|
|
|
return { isCustomPermission: false };
|
2021-10-11 17:57:52 +08:00
|
|
|
|
}
|
2021-09-13 10:37:07 +08:00
|
|
|
|
// userPerm is startsWith 'custom-'
|
|
|
|
|
if (custom_permission) {
|
|
|
|
|
const permissionId = custom_permission.id;
|
|
|
|
|
const userPermId = parseInt(userPerm.split('-')[1]);
|
|
|
|
|
if (permissionId === userPermId) {
|
|
|
|
|
return { isCustomPermission: true, customPermission: custom_permission };
|
|
|
|
|
}
|
|
|
|
|
// TODO user set custom permission on folder
|
|
|
|
|
}
|
2021-10-11 17:57:52 +08:00
|
|
|
|
return { isCustomPermission: false };
|
|
|
|
|
},
|
2019-05-06 16:08:34 +08:00
|
|
|
|
|
2021-10-08 15:19:04 +08:00
|
|
|
|
// for a11y
|
2024-07-18 11:58:42 +08:00
|
|
|
|
onKeyDown: function (e) {
|
2021-10-08 15:19:04 +08:00
|
|
|
|
if (e.key == 'Enter' || e.key == 'Space') {
|
|
|
|
|
e.target.click();
|
2021-11-03 16:11:56 +08:00
|
|
|
|
}
|
2022-08-05 14:15:37 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
updateTabTitle: function (content) {
|
2022-08-05 14:15:37 +08:00
|
|
|
|
const title = document.getElementsByTagName('title')[0];
|
|
|
|
|
title.innerText = content;
|
2023-04-27 10:36:49 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
generateHistoryURL: function (siteRoot, repoID, path) {
|
2023-04-27 10:36:49 +08:00
|
|
|
|
if (!siteRoot || !repoID || !path) return '';
|
|
|
|
|
return siteRoot + 'repo/file_revisions/' + repoID + '/?p=' + this.encodePath(path);
|
2023-07-06 14:56:31 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
generateRevisionURL: function (siteRoot, repoID, path) {
|
2023-07-06 14:56:31 +08:00
|
|
|
|
if (!siteRoot || !repoID || !path) return '';
|
|
|
|
|
return siteRoot + 'repo/sdoc_revision/' + repoID + '/?p=' + this.encodePath(path);
|
2023-07-07 16:07:14 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
generateRevisionsURL: function (siteRoot, repoID, path) {
|
2023-07-07 16:07:14 +08:00
|
|
|
|
if (!siteRoot || !repoID || !path) return '';
|
|
|
|
|
return siteRoot + 'repo/sdoc_revisions/' + repoID + '/?p=' + this.encodePath(path);
|
2023-07-27 15:11:35 +08:00
|
|
|
|
},
|
|
|
|
|
|
2024-07-18 11:58:42 +08:00
|
|
|
|
isFunction: function (functionToCheck) {
|
2023-07-27 15:11:35 +08:00
|
|
|
|
const getType = {};
|
|
|
|
|
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
|
|
|
|
},
|
2021-10-08 15:19:04 +08:00
|
|
|
|
|
2023-09-08 13:54:05 +08:00
|
|
|
|
getUrlSearches() {
|
|
|
|
|
const search = location.search;
|
|
|
|
|
let searchParams = {};
|
|
|
|
|
if (search.length === 0) {
|
|
|
|
|
return searchParams;
|
|
|
|
|
}
|
|
|
|
|
let allSearches = search.split('?')[1];
|
|
|
|
|
let allSearchesArr = allSearches.split('&');
|
|
|
|
|
allSearchesArr.forEach(item => {
|
|
|
|
|
let itemArr = item.split('=');
|
|
|
|
|
searchParams[itemArr[0]] = decodeURI(itemArr[1]);
|
|
|
|
|
});
|
|
|
|
|
return searchParams;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// If value is null, delete the search parameter; else, add or update the search parameter.
|
|
|
|
|
updateSearchParameter(key, value) {
|
|
|
|
|
const { origin, pathname } = location;
|
|
|
|
|
const searchParams = this.getUrlSearches();
|
|
|
|
|
searchParams[key] = value;
|
|
|
|
|
let newSearch = '?';
|
|
|
|
|
for (let key in searchParams) {
|
|
|
|
|
let value = searchParams[key];
|
|
|
|
|
if (value) {
|
|
|
|
|
newSearch = newSearch === '?' ? `?${key}=${value}` : `${newSearch}&${key}=${value}`;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
history.replaceState(null, '', origin + pathname + newSearch);
|
|
|
|
|
},
|
|
|
|
|
|
2024-05-13 13:54:15 +08:00
|
|
|
|
isRelativePath(url) {
|
|
|
|
|
let RgExp = new RegExp('^(?:[a-z]+:)?//', 'i');
|
|
|
|
|
return !RgExp.test(url);
|
2024-08-06 17:30:11 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
isMac() {
|
|
|
|
|
const platform = navigator.platform;
|
|
|
|
|
return (platform == 'Mac68K') || (platform == 'MacPPC') || (platform == 'Macintosh') || (platform == 'MacIntel');
|
|
|
|
|
},
|
2024-05-13 13:54:15 +08:00
|
|
|
|
|
2018-10-08 15:33:40 +08:00
|
|
|
|
};
|
2024-05-14 18:02:31 +08:00
|
|
|
|
|
|
|
|
|
export const isMobile = (typeof (window) !== 'undefined') && (window.innerWidth < 768 || navigator.userAgent.toLowerCase().match(/(ipod|ipad|iphone|android|coolpad|mmp|smartphone|midp|wap|xoom|symbian|j2me|blackberry|wince)/i) != null);
|
2024-08-05 12:10:36 +08:00
|
|
|
|
|
|
|
|
|
export const evaluatePasswordStrength = (password) => {
|
|
|
|
|
let strength = 0;
|
|
|
|
|
const length = password.length;
|
|
|
|
|
const hasUppercase = /[A-Z]/.test(password);
|
|
|
|
|
const hasLowercase = /[a-z]/.test(password);
|
|
|
|
|
const hasNumbers = /\d/.test(password);
|
|
|
|
|
const hasSpecialChars = /[`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\]/.test(password);
|
|
|
|
|
|
|
|
|
|
// Increased strength based on length
|
|
|
|
|
if (length === 0) return 'empty';
|
|
|
|
|
if (length >= 16) strength += 4;
|
|
|
|
|
else if (length >= 12) strength += 3;
|
|
|
|
|
else if (length >= 8) strength += 2;
|
|
|
|
|
else if (length >= 6) strength += 1;
|
|
|
|
|
|
|
|
|
|
// Increased strength based on character type
|
|
|
|
|
if (hasUppercase) strength += 1;
|
|
|
|
|
if (hasLowercase) strength += 1;
|
|
|
|
|
if (hasNumbers) strength += 1;
|
|
|
|
|
if (hasSpecialChars) strength += 1;
|
|
|
|
|
|
|
|
|
|
// Determine password strength
|
|
|
|
|
if (strength >= 8) return 'very_strong';
|
|
|
|
|
if (strength >= 6) return 'strong';
|
|
|
|
|
if (strength >= 4) return 'medium';
|
|
|
|
|
return 'weak';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const validatePassword = (password) => {
|
|
|
|
|
const { userStrongPasswordRequired } = window.app.pageOptions;
|
|
|
|
|
const passwordStrength = evaluatePasswordStrength(password);
|
|
|
|
|
const requiredStrengths = userStrongPasswordRequired ? ['strong', 'very_strong'] : ['medium', 'strong', 'very_strong'];
|
|
|
|
|
return requiredStrengths.includes(passwordStrength);
|
|
|
|
|
};
|
2024-09-04 15:11:49 +08:00
|
|
|
|
|
|
|
|
|
export const validateName = (newName) => {
|
|
|
|
|
let isValid = true;
|
|
|
|
|
let errMessage = '';
|
|
|
|
|
if (!newName || !newName.trim()) {
|
|
|
|
|
isValid = false;
|
|
|
|
|
errMessage = gettext('Name is required');
|
|
|
|
|
return { isValid, errMessage };
|
|
|
|
|
}
|
|
|
|
|
if (newName.includes('/')) {
|
|
|
|
|
isValid = false;
|
|
|
|
|
errMessage = gettext('Name cannot contain slash');
|
|
|
|
|
return { isValid, errMessage };
|
|
|
|
|
}
|
|
|
|
|
if (newName.includes('`')) {
|
|
|
|
|
isValid = false;
|
|
|
|
|
errMessage = gettext('Name cannot contain backtick');
|
|
|
|
|
return { isValid, errMessage };
|
|
|
|
|
}
|
|
|
|
|
if (newName.includes('\\')) {
|
|
|
|
|
isValid = false;
|
|
|
|
|
errMessage = gettext('Name cannot contain backslash');
|
|
|
|
|
return { isValid, errMessage };
|
|
|
|
|
}
|
2024-10-31 09:33:21 +08:00
|
|
|
|
if (newName === '..') {
|
|
|
|
|
isValid = false;
|
|
|
|
|
errMessage = gettext('Name cannot be double dots');
|
|
|
|
|
return { isValid, errMessage };
|
|
|
|
|
}
|
2024-09-04 15:11:49 +08:00
|
|
|
|
return { isValid, errMessage };
|
|
|
|
|
};
|
2025-01-07 12:17:57 +08:00
|
|
|
|
|
|
|
|
|
export const debounce = (fn, delay, immediate) => {
|
|
|
|
|
let timer = null;
|
|
|
|
|
return (...params) => {
|
|
|
|
|
if (timer) {
|
|
|
|
|
clearTimeout(timer);
|
|
|
|
|
}
|
|
|
|
|
if (immediate && !timer) {
|
|
|
|
|
fn.call(this, ...params);
|
|
|
|
|
} else {
|
|
|
|
|
timer = setTimeout(() => {
|
|
|
|
|
timer = null;
|
|
|
|
|
fn.call(this, ...params);
|
|
|
|
|
}, delay);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const throttle = (func, delay) => {
|
|
|
|
|
let timer = null;
|
|
|
|
|
let startTime = Date.now();
|
|
|
|
|
return function () {
|
|
|
|
|
let curTime = Date.now();
|
|
|
|
|
let remaining = delay - (curTime - startTime);
|
|
|
|
|
let context = this;
|
|
|
|
|
let args = arguments;
|
|
|
|
|
clearTimeout(timer);
|
|
|
|
|
if (remaining <= 0) {
|
|
|
|
|
func.apply(context, args);
|
|
|
|
|
startTime = Date.now();
|
|
|
|
|
} else {
|
|
|
|
|
timer = setTimeout(func, remaining);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
2025-03-01 10:12:48 +08:00
|
|
|
|
|
|
|
|
|
export const getType = (value) => {
|
|
|
|
|
return Object.prototype.toString.call(value).slice(8, -1);
|
|
|
|
|
};
|
2025-05-29 10:12:56 +08:00
|
|
|
|
|
|
|
|
|
export const isCanceled = (error) => {
|
|
|
|
|
return axios.isCancel(error);
|
|
|
|
|
};
|