mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-19 18:29:23 +00:00
Merge pull request #5818 from haiwen/update-seafile-editor
Update seafile editor
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
// eslint-disable-next-line strict
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
@@ -20,7 +21,7 @@ const getClientEnvironment = require('./env');
|
|||||||
const paths = require('./paths');
|
const paths = require('./paths');
|
||||||
const modules = require('./modules');
|
const modules = require('./modules');
|
||||||
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
|
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
|
||||||
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
|
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
||||||
const webpackBundleTracker = require('webpack-bundle-tracker');
|
const webpackBundleTracker = require('webpack-bundle-tracker');
|
||||||
|
|
||||||
const ForkTsCheckerWebpackPlugin =
|
const ForkTsCheckerWebpackPlugin =
|
||||||
@@ -608,7 +609,7 @@ module.exports = function (webpackEnv) {
|
|||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
process: "process/browser.js",
|
process: 'process/browser.js',
|
||||||
}),
|
}),
|
||||||
new NodePolyfillPlugin({
|
new NodePolyfillPlugin({
|
||||||
excludeAliases: ['console'],
|
excludeAliases: ['console'],
|
||||||
|
11958
frontend/package-lock.json
generated
11958
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
|||||||
"@seafile/resumablejs": "1.1.16",
|
"@seafile/resumablejs": "1.1.16",
|
||||||
"@seafile/sdoc-editor": "0.3.23",
|
"@seafile/sdoc-editor": "0.3.23",
|
||||||
"@seafile/seafile-calendar": "0.0.12",
|
"@seafile/seafile-calendar": "0.0.12",
|
||||||
"@seafile/seafile-editor": "0.4.8",
|
"@seafile/seafile-editor": "1.0.6",
|
||||||
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
"@uiw/codemirror-extensions-langs": "^4.19.4",
|
||||||
"@uiw/react-codemirror": "^4.19.4",
|
"@uiw/react-codemirror": "^4.19.4",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
"crypto-js": "4.2.0",
|
"crypto-js": "4.2.0",
|
||||||
"deep-copy": "1.4.2",
|
"deep-copy": "1.4.2",
|
||||||
"glamor": "^2.20.40",
|
"glamor": "^2.20.40",
|
||||||
"i18next": "22.4.6",
|
"i18next": "^17.0.13",
|
||||||
"i18next-browser-languagedetector": "7.0.1",
|
"i18next-browser-languagedetector": "^3.0.3",
|
||||||
"i18next-xhr-backend": "3.2.2",
|
"i18next-xhr-backend": "^3.1.2",
|
||||||
"is-hotkey": "0.2.0",
|
"is-hotkey": "0.2.0",
|
||||||
"MD5": "^1.3.0",
|
"MD5": "^1.3.0",
|
||||||
"moment": "^2.22.2",
|
"moment": "^2.22.2",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"react-chartjs-2": "^2.8.0",
|
"react-chartjs-2": "^2.8.0",
|
||||||
"react-cookies": "^0.1.0",
|
"react-cookies": "^0.1.0",
|
||||||
"react-dom": "17.0.0",
|
"react-dom": "17.0.0",
|
||||||
"react-i18next": "12.1.1",
|
"react-i18next": "^10.12.2",
|
||||||
"react-responsive": "9.0.2",
|
"react-responsive": "9.0.2",
|
||||||
"react-select": "5.7.0",
|
"react-select": "5.7.0",
|
||||||
"react-transition-group": "4.4.5",
|
"react-transition-group": "4.4.5",
|
||||||
|
@@ -2,7 +2,7 @@ import i18n from 'i18next';
|
|||||||
import Backend from 'i18next-xhr-backend';
|
import Backend from 'i18next-xhr-backend';
|
||||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||||
import { initReactI18next } from 'react-i18next';
|
import { initReactI18next } from 'react-i18next';
|
||||||
import { mediaUrl } from './utils/constants';
|
import { mediaUrl } from '../utils/constants';
|
||||||
|
|
||||||
const lang = window.app.pageOptions.lang;
|
const lang = window.app.pageOptions.lang;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ i18n
|
|||||||
lng: lang,
|
lng: lang,
|
||||||
fallbackLng: 'en',
|
fallbackLng: 'en',
|
||||||
ns: ['seafile-editor'],
|
ns: ['seafile-editor'],
|
||||||
defaultNS: 'translations',
|
defaultNS: 'seafile-editor',
|
||||||
|
|
||||||
whitelist: ['en', 'zh-CN', 'fr', 'de', 'cs', 'es', 'es-AR', 'es-MX', 'ru'],
|
whitelist: ['en', 'zh-CN', 'fr', 'de', 'cs', 'es', 'es-AR', 'es-MX', 'ru'],
|
||||||
|
|
@@ -13,6 +13,14 @@ const propTypes = {
|
|||||||
|
|
||||||
class TermsEditorDialog extends React.Component {
|
class TermsEditorDialog extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isValueChanged: false,
|
||||||
|
};
|
||||||
|
this.editorRef = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
title: gettext('Terms'),
|
title: gettext('Terms'),
|
||||||
};
|
};
|
||||||
@@ -22,20 +30,20 @@ class TermsEditorDialog extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
toggle = () => {
|
toggle = () => {
|
||||||
if (this.isContentChanged()) {
|
const { isValueChanged } = this.state;
|
||||||
|
if (isValueChanged) {
|
||||||
let currentContent = this.getCurrentContent();
|
let currentContent = this.getCurrentContent();
|
||||||
this.props.onCommit(currentContent);
|
this.props.onCommit(currentContent);
|
||||||
}
|
}
|
||||||
this.props.onCloseEditorDialog();
|
this.props.onCloseEditorDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
isContentChanged = () => {
|
onContentChanged = () => {
|
||||||
return this.simpleEditor.hasContentChange();
|
return this.setState({isValueChanged: true});
|
||||||
};
|
};
|
||||||
|
|
||||||
getCurrentContent = () => {
|
getCurrentContent = () => {
|
||||||
let markdownContent = this.simpleEditor.getMarkdown();
|
return this.editorRef.current.getValue();
|
||||||
return markdownContent;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setSimpleEditorRef = (editor) => {
|
setSimpleEditorRef = (editor) => {
|
||||||
@@ -58,8 +66,9 @@ class TermsEditorDialog extends React.Component {
|
|||||||
<ModalHeader className="conditions-editor-dialog-title" toggle={this.toggle}>{title}</ModalHeader>
|
<ModalHeader className="conditions-editor-dialog-title" toggle={this.toggle}>{title}</ModalHeader>
|
||||||
<ModalBody className={'conditions-editor-dialog-main'}>
|
<ModalBody className={'conditions-editor-dialog-main'}>
|
||||||
<SimpleEditor
|
<SimpleEditor
|
||||||
onRef={this.setSimpleEditorRef.bind(this)}
|
ref={this.editorRef}
|
||||||
value={content || ''}
|
value={content || ''}
|
||||||
|
onContentChanged={this.onContentChanged}
|
||||||
/>
|
/>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@@ -9,15 +9,14 @@ const { fileContent } = window.app.pageOptions;
|
|||||||
class FileContent extends React.Component {
|
class FileContent extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="file-view-content flex-1 o-auto">
|
<div className="file-view-content md-content">
|
||||||
<div className="md-content">
|
|
||||||
<MarkdownViewer
|
<MarkdownViewer
|
||||||
markdownContent={fileContent}
|
isFetching={false}
|
||||||
showTOC={false}
|
value={fileContent}
|
||||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
isShowOutline={false}
|
||||||
|
mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,300 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { repoID, slug, serviceURL, isPublicWiki } from '../utils/constants';
|
|
||||||
import { Utils } from '../utils/utils';
|
|
||||||
import { deserialize } from '@seafile/seafile-editor';
|
|
||||||
import'../css/index-viewer.css';
|
|
||||||
|
|
||||||
const viewerPropTypes = {
|
|
||||||
indexContent: PropTypes.string.isRequired,
|
|
||||||
onLinkClick: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
class TreeNode {
|
|
||||||
|
|
||||||
constructor({ name, href, parentNode }) {
|
|
||||||
this.name = name;
|
|
||||||
this.href = href;
|
|
||||||
this.parentNode = parentNode || null;
|
|
||||||
this.children = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
setParent(parentNode) {
|
|
||||||
this.parentNode = parentNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
addChildren(nodeList) {
|
|
||||||
nodeList.forEach((node) => {
|
|
||||||
node.setParent(this);
|
|
||||||
});
|
|
||||||
this.children = nodeList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IndexContentViewer extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.links = [];
|
|
||||||
this.treeRoot = new TreeNode({ name: '', href: '' });
|
|
||||||
this.state = {
|
|
||||||
currentPath: '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
UNSAFE_componentWillMount() {
|
|
||||||
this.getRootNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.bindClickEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps() {
|
|
||||||
this.removeClickEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
this.bindClickEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.removeClickEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
bindClickEvent = () => {
|
|
||||||
const contentClass = 'wiki-nav-content';
|
|
||||||
this.links = document.querySelectorAll(`.${contentClass} a`);
|
|
||||||
this.links.forEach(link => {
|
|
||||||
link.addEventListener('click', this.onLinkClick);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
removeClickEvent = () => {
|
|
||||||
this.links.forEach(link => {
|
|
||||||
link.removeEventListener('click', this.onLinkClick);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onLinkClick = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
const currentPath = event.target.getAttribute('data-path');
|
|
||||||
if (currentPath === this.state.currentPath) {
|
|
||||||
return;
|
|
||||||
} else if (currentPath) {
|
|
||||||
this.setState({ currentPath: currentPath });
|
|
||||||
}
|
|
||||||
const link = this.getLink(event.target);
|
|
||||||
if (link) this.props.onLinkClick(link);
|
|
||||||
};
|
|
||||||
|
|
||||||
getLink = (node) => {
|
|
||||||
const tagName = node.tagName;
|
|
||||||
if (!tagName || tagName === 'HTML') return;
|
|
||||||
if (tagName === 'A') {
|
|
||||||
return node.href;
|
|
||||||
} else {
|
|
||||||
return this.getLink(node.parentNode);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
changeInlineNode = (item) => {
|
|
||||||
if (item.type == 'link' || item.type === 'image') {
|
|
||||||
let url;
|
|
||||||
|
|
||||||
// change image url
|
|
||||||
if (item.type == 'image' && isPublicWiki) {
|
|
||||||
url = item.data.src;
|
|
||||||
const re = new RegExp(serviceURL + '/lib/' + repoID +'/file.*raw=1');
|
|
||||||
// different repo
|
|
||||||
if (!re.test(url)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// get image path
|
|
||||||
let index = url.indexOf('/file');
|
|
||||||
let index2 = url.indexOf('?');
|
|
||||||
const imagePath = url.substring(index + 5, index2);
|
|
||||||
// replace url
|
|
||||||
item.data.src = serviceURL + '/view-image-via-public-wiki/?slug=' + slug + '&path=' + imagePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (item.type == 'link') {
|
|
||||||
url = item.data.href;
|
|
||||||
/* eslint-disable */
|
|
||||||
let expression = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/
|
|
||||||
/* eslint-enable */
|
|
||||||
let re = new RegExp(expression);
|
|
||||||
|
|
||||||
// Solving relative paths
|
|
||||||
if (!re.test(url)) {
|
|
||||||
item.data.href = serviceURL + '/published/' + slug + '/' + url;
|
|
||||||
}
|
|
||||||
// change file url
|
|
||||||
else if (Utils.isInternalMarkdownLink(url, repoID)) {
|
|
||||||
let path = Utils.getPathFromInternalMarkdownLink(url, repoID);
|
|
||||||
// replace url
|
|
||||||
item.data.href = serviceURL + '/published/' + slug + path;
|
|
||||||
}
|
|
||||||
// change dir url
|
|
||||||
else if (Utils.isInternalDirLink(url, repoID)) {
|
|
||||||
let path = Utils.getPathFromInternalDirLink(url, repoID);
|
|
||||||
// replace url
|
|
||||||
item.data.href = serviceURL + '/published/' + slug + path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
};
|
|
||||||
|
|
||||||
getRootNode = () => {
|
|
||||||
let value = deserialize(this.props.indexContent);
|
|
||||||
const newNodes = Utils.changeMarkdownNodes(value, this.changeInlineNode);
|
|
||||||
newNodes.forEach((node) => {
|
|
||||||
if (node.type === 'unordered_list' || node.type === 'ordered_list') {
|
|
||||||
let treeRoot = this.transSlateToTree(node.children, this.treeRoot);
|
|
||||||
this.setNodePath(treeRoot, '/');
|
|
||||||
this.treeRoot = treeRoot;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
setNodePath = (node, parentNodePath) => {
|
|
||||||
let name = node.name;
|
|
||||||
let path = parentNodePath === '/' ? parentNodePath + name : parentNodePath + '/' + name;
|
|
||||||
node.path = path;
|
|
||||||
if (node.children.length > 0) {
|
|
||||||
node.children.forEach(child => {
|
|
||||||
this.setNodePath(child, path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// slateNodes is list items of an unordered list or ordered list, translate them to treeNode and add to parentTreeNode
|
|
||||||
transSlateToTree = (slateNodes, parentTreeNode) => {
|
|
||||||
let treeNodes = slateNodes.map((slateNode) => {
|
|
||||||
// item has children(unordered list)
|
|
||||||
if (slateNode.children.length === 2 && (slateNode.children[1].type === 'unordered_list' || slateNode.children[1].type === 'ordered_list')) {
|
|
||||||
// slateNode.nodes[0] is paragraph, create TreeNode, set name and href
|
|
||||||
const paragraphNode = slateNode.children[0];
|
|
||||||
const treeNode = this.transParagraph(paragraphNode);
|
|
||||||
// slateNode.nodes[1] is list, set it as TreeNode's children
|
|
||||||
const listNode = slateNode.children[1];
|
|
||||||
// Add sub list items to the tree node
|
|
||||||
return this.transSlateToTree(listNode.children, treeNode);
|
|
||||||
} else {
|
|
||||||
// item doesn't have children list
|
|
||||||
if (slateNode.children[0] && (slateNode.children[0].type === 'paragraph')) {
|
|
||||||
return this.transParagraph(slateNode.children[0]);
|
|
||||||
} else {
|
|
||||||
// list item contain table/code_block/blockqupta
|
|
||||||
return new TreeNode({ name: '', href: '' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
parentTreeNode.addChildren(treeNodes);
|
|
||||||
return parentTreeNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
// translate slate_paragraph_node to treeNode
|
|
||||||
transParagraph = (paragraphNode) => {
|
|
||||||
let treeNode;
|
|
||||||
if (paragraphNode.children[1] && paragraphNode.children[1].type === 'link') {
|
|
||||||
// paragraph node is a link node
|
|
||||||
const linkNode = paragraphNode.children[1];
|
|
||||||
const textNode = linkNode.children[0];
|
|
||||||
let name = textNode ? textNode.text : '';
|
|
||||||
treeNode = new TreeNode({ name: name, href: linkNode.data.href });
|
|
||||||
} else if (paragraphNode.children[0]) {
|
|
||||||
// paragraph first child node is a text node, then get node name
|
|
||||||
const textNode = paragraphNode.children[0];
|
|
||||||
let name = textNode.text ? textNode.text : '';
|
|
||||||
treeNode = new TreeNode({ name: name, href: '' });
|
|
||||||
} else {
|
|
||||||
treeNode = new TreeNode({ name: '', href: '' });
|
|
||||||
}
|
|
||||||
return treeNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="mx-4 o-hidden">
|
|
||||||
<FolderItem node={this.treeRoot} bindClickEvent={this.bindClickEvent} currentPath={this.state.currentPath}/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IndexContentViewer.propTypes = viewerPropTypes;
|
|
||||||
|
|
||||||
const FolderItemPropTypes = {
|
|
||||||
node: PropTypes.object.isRequired,
|
|
||||||
bindClickEvent: PropTypes.func.isRequired,
|
|
||||||
currentPath: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
class FolderItem extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
expanded: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleExpanded = () => {
|
|
||||||
this.setState({ expanded: !this.state.expanded }, () => {
|
|
||||||
if (this.state.expanded) this.props.bindClickEvent();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
renderLink = ({ href, name, path }) => {
|
|
||||||
const className = `wiki-nav-content ${path === this.props.currentPath ? 'wiki-nav-content-highlight' : ''}`;
|
|
||||||
if (href && name) {
|
|
||||||
return <div className={className}><a href={href} data-path={path} onClick={this.toggleExpanded} title={name}>{name}</a></div>;
|
|
||||||
} else if (name) {
|
|
||||||
return <div className="wiki-nav-content"><span onClick={this.toggleExpanded} title={name}>{name}</span></div>;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (this.props.node && !this.props.node.parentNode) {
|
|
||||||
this.setState({ expanded: true }, () => {
|
|
||||||
this.props.bindClickEvent();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { node } = this.props;
|
|
||||||
if (node.children.length > 0) {
|
|
||||||
return (
|
|
||||||
<React.Fragment>
|
|
||||||
{node.parentNode &&
|
|
||||||
<React.Fragment>
|
|
||||||
<span className="switch-btn" onClick={this.toggleExpanded}>
|
|
||||||
{this.state.expanded ? <i className="fa fa-caret-down"></i> : <i className="fa fa-caret-right"></i>}
|
|
||||||
</span>
|
|
||||||
{this.renderLink(node)}
|
|
||||||
</React.Fragment>
|
|
||||||
}
|
|
||||||
{this.state.expanded && node.children.map((child, index) => {
|
|
||||||
return (
|
|
||||||
<div className="pl-4 position-relative" key={index}>
|
|
||||||
<FolderItem node={child} bindClickEvent={this.props.bindClickEvent} currentPath={this.props.currentPath}/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return this.renderLink(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FolderItem.propTypes = FolderItemPropTypes;
|
|
||||||
|
|
||||||
export default IndexContentViewer;
|
|
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { MarkdownViewer } from '@seafile/seafile-editor';
|
import { EXTERNAL_EVENTS, EventBus, MarkdownViewer } from '@seafile/seafile-editor';
|
||||||
import { gettext, repoID, slug, serviceURL, isPublicWiki, sharedToken, mediaUrl } from '../utils/constants';
|
import { gettext, isPublicWiki, mediaUrl, repoID, serviceURL, sharedToken, slug } from '../utils/constants';
|
||||||
import Loading from './loading';
|
import Loading from './loading';
|
||||||
import { Utils } from '../utils/utils';
|
import { Utils } from '../utils/utils';
|
||||||
|
|
||||||
@@ -25,109 +25,30 @@ class WikiMarkdownViewer extends React.Component {
|
|||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.scrollRef = React.createRef();
|
||||||
activeTitleIndex: 0,
|
|
||||||
};
|
|
||||||
this.markdownContainer = React.createRef();
|
|
||||||
this.links = [];
|
|
||||||
this.titlesInfo = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
// Bind event when first loaded
|
const eventBus = EventBus.getInstance();
|
||||||
this.links = document.querySelectorAll(`.${contentClass} a`);
|
this.unsubscribeLinkClick = eventBus.subscribe(EXTERNAL_EVENTS.ON_LINK_CLICK, this.onLinkClick);
|
||||||
this.links.forEach(link => {
|
|
||||||
link.addEventListener('click', this.onLinkClick);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.getTitlesInfo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
||||||
if (this.props.markdownContent === nextProps.markdownContent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Unbound event when updating
|
|
||||||
this.links.forEach(link => {
|
|
||||||
link.removeEventListener('click', this.onLinkClick);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
// Update completed, rebind event
|
|
||||||
this.links = document.querySelectorAll(`.${contentClass} a`);
|
|
||||||
this.links.forEach(link => {
|
|
||||||
link.addEventListener('click', this.onLinkClick);
|
|
||||||
});
|
|
||||||
if (this.titlesInfo.length === 0) {
|
|
||||||
this.getTitlesInfo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
// Unbound events when the component is destroyed
|
this.unsubscribeLinkClick();
|
||||||
this.links.forEach(link => {
|
|
||||||
link.removeEventListener('click', this.onLinkClick);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTitlesInfo = () => {
|
|
||||||
let titlesInfo = [];
|
|
||||||
const titleDom = document.querySelectorAll('h1[id^="user-content"]')[0];
|
|
||||||
if (titleDom) {
|
|
||||||
const id = titleDom.getAttribute('id');
|
|
||||||
let content = id && id.replace('user-content-', '');
|
|
||||||
content = content ? `${content} - ${slug}` : slug;
|
|
||||||
Utils.updateTabTitle(content);
|
|
||||||
}
|
|
||||||
let headingList = document.querySelectorAll('h2[id^="user-content"], h3[id^="user-content"]');
|
|
||||||
for (let i = 0; i < headingList.length; i++) {
|
|
||||||
titlesInfo.push(headingList[i].offsetTop);
|
|
||||||
}
|
|
||||||
this.titlesInfo = titlesInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
onLinkClick = (event) => {
|
onLinkClick = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
let link = '';
|
let link = '';
|
||||||
if (event.target.tagName !== 'A') {
|
let target = event.target;
|
||||||
let target = event.target.parentNode;
|
while (!target.dataset || !target.dataset.url) {
|
||||||
while (target.tagName !== 'A') {
|
|
||||||
target = target.parentNode;
|
target = target.parentNode;
|
||||||
}
|
}
|
||||||
link = target.href;
|
if (!target) return;
|
||||||
} else {
|
link = target.dataset.url;
|
||||||
link = event.target.href;
|
|
||||||
}
|
|
||||||
this.props.onLinkClick(link);
|
this.props.onLinkClick(link);
|
||||||
};
|
};
|
||||||
|
|
||||||
onScrollHandler = () => {
|
|
||||||
const contentScrollTop = this.markdownContainer.current.scrollTop + 180;
|
|
||||||
let titlesLength = this.titlesInfo.length;
|
|
||||||
let activeTitleIndex;
|
|
||||||
if (contentScrollTop <= this.titlesInfo[0]) {
|
|
||||||
activeTitleIndex = 0;
|
|
||||||
this.setState({activeTitleIndex: activeTitleIndex});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (contentScrollTop > this.titlesInfo[titlesLength - 1]) {
|
|
||||||
activeTitleIndex = this.titlesInfo.length - 1;
|
|
||||||
this.setState({activeTitleIndex: activeTitleIndex});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < titlesLength; i++) {
|
|
||||||
if (contentScrollTop > this.titlesInfo[i]) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
activeTitleIndex = i - 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setState({activeTitleIndex: activeTitleIndex});
|
|
||||||
};
|
|
||||||
|
|
||||||
changeInlineNode = (item) => {
|
changeInlineNode = (item) => {
|
||||||
let url, imagePath;
|
let url, imagePath;
|
||||||
|
|
||||||
@@ -149,21 +70,21 @@ class WikiMarkdownViewer extends React.Component {
|
|||||||
}
|
}
|
||||||
item.data.src = serviceURL + '/view-image-via-public-wiki/?slug=' + slug + '&path=' + imagePath;
|
item.data.src = serviceURL + '/view-image-via-public-wiki/?slug=' + slug + '&path=' + imagePath;
|
||||||
} else if (item.type == 'link') { // change link url
|
} else if (item.type == 'link') { // change link url
|
||||||
url = item.data.href;
|
url = item.url;
|
||||||
if (Utils.isInternalFileLink(url, repoID)) { // change file url
|
if (Utils.isInternalFileLink(url, repoID)) { // change file url
|
||||||
if (Utils.isInternalMarkdownLink(url, repoID)) {
|
if (Utils.isInternalMarkdownLink(url, repoID)) {
|
||||||
let path = Utils.getPathFromInternalMarkdownLink(url, repoID);
|
let path = Utils.getPathFromInternalMarkdownLink(url, repoID);
|
||||||
// replace url
|
// replace url
|
||||||
item.data.href = serviceURL + '/published/' + slug + path;
|
item.url = serviceURL + '/published/' + slug + path;
|
||||||
} else {
|
} else {
|
||||||
item.data.href = url.replace(/(.*)lib\/([-0-9a-f]{36})\/file(.*)/g, (match, p1, p2, p3) => {
|
item.url = url.replace(/(.*)lib\/([-0-9a-f]{36})\/file(.*)/g, (match, p1, p2, p3) => {
|
||||||
return `${p1}d/${sharedToken}/files/?p=${p3}&dl=1`;
|
return `${p1}d/${sharedToken}/files/?p=${p3}&dl=1`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (Utils.isInternalDirLink(url, repoID)) { // change dir url
|
} else if (Utils.isInternalDirLink(url, repoID)) { // change dir url
|
||||||
let path = Utils.getPathFromInternalDirLink(url, repoID);
|
let path = Utils.getPathFromInternalDirLink(url, repoID);
|
||||||
// replace url
|
// replace url
|
||||||
item.data.href = serviceURL + '/published/' + slug + path;
|
item.url = serviceURL + '/published/' + slug + path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,30 +97,16 @@ class WikiMarkdownViewer extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderMarkdown = () => {
|
renderMarkdown = () => {
|
||||||
let isTOCShow = true;
|
const { isTOCShow = true, isWiki, markdownContent } = this.props;
|
||||||
if (this.props.isTOCShow === false) {
|
const props = {
|
||||||
isTOCShow = false;
|
isShowOutline: isTOCShow,
|
||||||
}
|
mathJaxSource: `${mediaUrl}js/mathjax/tex-svg.js`,
|
||||||
if (this.props.isWiki) {
|
value: markdownContent,
|
||||||
return (
|
scrollRef: this.scrollRef,
|
||||||
<MarkdownViewer
|
...(isWiki && {beforeRenderCallback: this.modifyValueBeforeRender})
|
||||||
showTOC={isTOCShow}
|
};
|
||||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
|
||||||
markdownContent={this.props.markdownContent}
|
|
||||||
activeTitleIndex={this.state.activeTitleIndex}
|
|
||||||
modifyValueBeforeRender={this.modifyValueBeforeRender}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return <MarkdownViewer {...props} />;
|
||||||
<MarkdownViewer
|
|
||||||
showTOC={isTOCShow}
|
|
||||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
|
||||||
markdownContent={this.props.markdownContent}
|
|
||||||
activeTitleIndex={this.state.activeTitleIndex}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -209,7 +116,7 @@ class WikiMarkdownViewer extends React.Component {
|
|||||||
// In dir-column-file repoID is one of props, width is 100%; In wiki-viewer repoID is not props, width isn't 100%
|
// In dir-column-file repoID is one of props, width is 100%; In wiki-viewer repoID is not props, width isn't 100%
|
||||||
let contentClassName = `${this.props.repoID ? contentClass + ' w-100' : contentClass}`;
|
let contentClassName = `${this.props.repoID ? contentClass + ' w-100' : contentClass}`;
|
||||||
return (
|
return (
|
||||||
<div ref={this.markdownContainer} className="wiki-page-container" onScroll={this.onScrollHandler.bind(this)}>
|
<div ref={this.scrollRef} className="wiki-page-container">
|
||||||
<div className={contentClassName}>
|
<div className={contentClassName}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
{this.renderMarkdown()}
|
{this.renderMarkdown()}
|
||||||
|
@@ -1,102 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
const itemPropTypes = {
|
|
||||||
activeIndex: PropTypes.number.isRequired,
|
|
||||||
item: PropTypes.object.isRequired,
|
|
||||||
handleNavItemClick: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
class WikiOutlineItem extends React.Component {
|
|
||||||
|
|
||||||
handleNavItemClick = () => {
|
|
||||||
var activeId = this.props.item.id;
|
|
||||||
this.props.handleNavItemClick(activeId);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let item = this.props.item;
|
|
||||||
let activeIndex = parseInt(this.props.activeIndex);
|
|
||||||
let levelClass = item.depth === 3 ? ' textindent-2' : '';
|
|
||||||
let activeClass = item.key === activeIndex ? ' wiki-outline-item-active' : '';
|
|
||||||
let clazz = 'wiki-outline-item'+ levelClass + activeClass;
|
|
||||||
return (
|
|
||||||
<li className={clazz} data-index={item.key} onClick={this.handleNavItemClick}>
|
|
||||||
<a href={item.id} title={item.text}>{item.text}</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
WikiOutlineItem.propTypes = itemPropTypes;
|
|
||||||
|
|
||||||
const outlinePropTypes = {
|
|
||||||
navItems: PropTypes.array.isRequired,
|
|
||||||
activeId: PropTypes.oneOfType([
|
|
||||||
PropTypes.string,
|
|
||||||
PropTypes.number
|
|
||||||
]).isRequired,
|
|
||||||
handleNavItemClick: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
class WikiOutline extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
activeIndex : 0,
|
|
||||||
scrollTop: 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
||||||
let _this = this;
|
|
||||||
let activeId = nextProps.activeId;
|
|
||||||
let navItems = nextProps.navItems;
|
|
||||||
let length = navItems.length;
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
let flag = false;
|
|
||||||
let item = navItems[i];
|
|
||||||
if (item.id === activeId && item.key !== _this.state.activeIndex) {
|
|
||||||
let scrollTop = 0;
|
|
||||||
if (item.key > 20) {
|
|
||||||
scrollTop = - (item.key - 20)*27 + 'px';
|
|
||||||
if (parseInt(scrollTop) > 0) { // handle scroll quickly;
|
|
||||||
scrollTop = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_this.setState({
|
|
||||||
activeIndex : item.key,
|
|
||||||
scrollTop: scrollTop
|
|
||||||
});
|
|
||||||
flag = true;
|
|
||||||
}
|
|
||||||
if (flag) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let style = {top: this.state.scrollTop};
|
|
||||||
return (
|
|
||||||
<ul className="wiki-viewer-outline" ref="outlineContainer" style={style}>
|
|
||||||
{this.props.navItems.map(item => {
|
|
||||||
return (
|
|
||||||
<WikiOutlineItem
|
|
||||||
key={item.key}
|
|
||||||
item={item}
|
|
||||||
activeIndex={this.state.activeIndex}
|
|
||||||
handleNavItemClick={this.props.handleNavItemClick}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WikiOutline.propTypes = outlinePropTypes;
|
|
||||||
|
|
||||||
export default WikiOutline;
|
|
@@ -1,3 +1,9 @@
|
|||||||
|
#wrapper {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.header .button-group {
|
.header .button-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@@ -29,20 +29,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content-viewer {
|
.content-viewer {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-viewer .sf-slate-viewer-scroll-container {
|
||||||
background-color: #fafaf9;
|
background-color: #fafaf9;
|
||||||
border-radius: 10px;
|
padding: 20px 40px;
|
||||||
overflow: auto;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.markdown-viewer-render-content {
|
.content-viewer .sf-slate-viewer-article-container .article {
|
||||||
background-color: #fff;
|
width: 100%;
|
||||||
word-break: break-word;
|
max-width: 100%;
|
||||||
margin: 20px 40px;
|
|
||||||
border: 1px solid #e6e6dd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.markdown-viewer-render-content .diff-view {
|
|
||||||
padding: 40px 60px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-header {
|
.panel-header {
|
||||||
@@ -124,10 +124,14 @@
|
|||||||
.history-content .main-panel {
|
.history-content .main-panel {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
.markdown-viewer-render-content {
|
.content-viewer .sf-slate-viewer-scroll-container {
|
||||||
margin: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
.markdown-viewer-render-content .diff-view {
|
.content-viewer .sf-slate-viewer-article-container {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.content-viewer .sf-slate-viewer-article-container .article {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -205,8 +205,17 @@
|
|||||||
background-color: #f6f6f6;
|
background-color: #f6f6f6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wiki-page-content .sf-slate-viewer-scroll-container {
|
||||||
|
padding: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
border: none;
|
||||||
|
overflow: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
.dir-content-main .wiki-page-content .article {
|
.dir-content-main .wiki-page-content .article {
|
||||||
|
margin: 0;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wiki-page-content a {
|
.wiki-page-content a {
|
||||||
|
@@ -1,3 +1,8 @@
|
|||||||
|
html, body, #root {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -168,3 +173,10 @@
|
|||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
color: #888;
|
color: #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sf-md-viewer-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
@@ -1,9 +1,14 @@
|
|||||||
.md-content {
|
.file-view-content.md-content {
|
||||||
box-shadow: 0 0 6px #ccc;
|
width: 100%;
|
||||||
border: 1px solid #ccc;
|
height: 100%;
|
||||||
padding: 70px 75px;
|
background: #f4f4f4;
|
||||||
width: calc(100% - 40px);
|
border-right: none;
|
||||||
max-width: 950px;
|
padding: 0;
|
||||||
background: #fff;
|
display: flex;
|
||||||
margin: 0 auto;
|
}
|
||||||
|
|
||||||
|
.md-content .sf-slate-viewer-scroll-container .article {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
box-shadow: 0 0 6px #ccc;
|
||||||
|
padding: 70px 75px;
|
||||||
}
|
}
|
||||||
|
@@ -48,24 +48,14 @@
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shared-file-view-body .article {
|
.shared-file-view-body.md-view {
|
||||||
min-height: calc(100% - 15px);
|
padding: 0;
|
||||||
background: #fff;
|
display: flex;
|
||||||
padding: 40px 60px;
|
min-height: 0;
|
||||||
margin: 0 340px 15px 40px;
|
|
||||||
border: 1px solid #e6e6dd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.shared-file-view-body .article-no-outline {
|
.shared-file-view-body .sf-slate-viewer-outline {
|
||||||
max-width: 950px;
|
top: 145px !important;
|
||||||
margin: 0 auto 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shared-file-view-body .seafile-markdown-outline {
|
|
||||||
width: 300px;
|
|
||||||
top: 145px;
|
|
||||||
bottom: 30px;
|
|
||||||
height: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 991.98px) {
|
@media (max-width: 991.98px) {
|
||||||
@@ -73,27 +63,4 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
}
|
}
|
||||||
.shared-file-view-body .md-view {
|
|
||||||
width: 95%;
|
|
||||||
}
|
|
||||||
.shared-file-view-body .md-view {
|
|
||||||
padding: 55px 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.shared-file-view-body .md-view {
|
|
||||||
padding: 0 10px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shared-file-view-body .md-view .article {
|
|
||||||
display: flex;
|
|
||||||
padding: 20px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shared-file-view-body .seafile-markdown-outline {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,251 +0,0 @@
|
|||||||
.wiki-side-panel .panel-top {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
.wiki-side-nav {
|
|
||||||
flex:auto;
|
|
||||||
display:flex;
|
|
||||||
flex-direction:column;
|
|
||||||
overflow:hidden; /* for ff */
|
|
||||||
border-right:1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-pages-heading {
|
|
||||||
position: relative;
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: normal;
|
|
||||||
padding: 0.5rem 0 0.5rem 2rem;
|
|
||||||
border-bottom: 1px solid #e8e8e8;
|
|
||||||
line-height: 1.5;
|
|
||||||
height: 40px;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
.heading-icon {
|
|
||||||
position: absolute;
|
|
||||||
right: 1rem;
|
|
||||||
top: 25%;
|
|
||||||
color: #888;
|
|
||||||
font-size: 0.8125rem;
|
|
||||||
}
|
|
||||||
.wiki-pages-container {
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
.wiki-pages-container:hover {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.wiki-pages-container .tree-view {
|
|
||||||
margin-left: -10px;
|
|
||||||
padding-left:0;
|
|
||||||
}
|
|
||||||
.wiki-pages-container .article {
|
|
||||||
padding: 0 20px;
|
|
||||||
}
|
|
||||||
.wiki-pages-container .tree-view {
|
|
||||||
margin-top: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-md-viewer-rendered-content {
|
|
||||||
padding: 30px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
img[src=""] {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-side-panel {
|
|
||||||
flex: 0 0 20%;
|
|
||||||
display:flex;
|
|
||||||
flex-direction:column;
|
|
||||||
overflow:hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
|
||||||
.wiki-side-panel {
|
|
||||||
z-index: 1051;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-main-panel {
|
|
||||||
flex: 1 0 80%;
|
|
||||||
display:flex;
|
|
||||||
flex-direction:column;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-main-panel .main-panel-north {
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cur-view-content .wiki-page-container {
|
|
||||||
margin: 0 -1rem -1.25rem;
|
|
||||||
padding: 30px 1rem 1.25rem;
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
padding-left: 30px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-main-panel .cur-view-content .article {
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-main-panel .cur-view-content .article h1 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cur-view-content .wiki-page-container .outline-h2,
|
|
||||||
.cur-view-content .wiki-page-container .outline-h3 {
|
|
||||||
height: 24px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #4d5156;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cur-view-content .wiki-page-container .outline-h2.active,
|
|
||||||
.cur-view-content .wiki-page-container .outline-h3.active {
|
|
||||||
color: #eb8205;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cur-view-content .wiki-page-container .seafile-markdown-outline {
|
|
||||||
overflow-y: hidden;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cur-view-content .wiki-page-container .seafile-markdown-outline:hover {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cur-view-content .wiki-page-content {
|
|
||||||
width: calc(100% - 200px);
|
|
||||||
padding-right: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cur-view-content .wiki-page-content .seafile-markdown-outline {
|
|
||||||
position: fixed;
|
|
||||||
padding-right: 1rem;
|
|
||||||
top: 79px;
|
|
||||||
right: 0;
|
|
||||||
width: 200px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-hide {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 991.98px) {
|
|
||||||
.cur-view-content .wiki-page-container {
|
|
||||||
padding: 0 14px;
|
|
||||||
padding-top: 30px;
|
|
||||||
}
|
|
||||||
.cur-view-content .wiki-page-content {
|
|
||||||
width: 100%;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
.cur-view-content .seafile-markdown-outline {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-main .wiki-viewer-outline {
|
|
||||||
position: relative;
|
|
||||||
top: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
border-left: solid 1px #eee;
|
|
||||||
}
|
|
||||||
.textindent-2 {
|
|
||||||
text-indent: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-main .wiki-outline-item {
|
|
||||||
padding: 3px 15px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-outline-item a {
|
|
||||||
display: block;
|
|
||||||
color: #444;
|
|
||||||
text-decoration: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-outline-item a:hover {
|
|
||||||
color: #eb8205;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-outline-item-active {
|
|
||||||
border-left: 1px solid #eb8205;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-outline-item-active a {
|
|
||||||
color: #eb8205 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-page-ops {
|
|
||||||
position:fixed;
|
|
||||||
top:10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.wiki-page-ops:before {
|
|
||||||
content:'';
|
|
||||||
border-left:1px solid #ddd;
|
|
||||||
position:absolute;
|
|
||||||
top:3px;
|
|
||||||
left:-16px;
|
|
||||||
bottom:3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-page-list-item {
|
|
||||||
word-break:break-all;
|
|
||||||
line-height:1.6;
|
|
||||||
margin:3px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-page-link,
|
|
||||||
.wiki-page-link:hover {
|
|
||||||
font-size:1.15em;
|
|
||||||
font-weight:normal;
|
|
||||||
color:#444;
|
|
||||||
margin-left:5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#wiki-page-last-modified {
|
|
||||||
padding: 40px 10px;
|
|
||||||
font-size:12px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-md-viewer-rendered-content.article h1 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-page-content a {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-side-nav .wiki-page-content a {
|
|
||||||
color: #212529;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.index-edit {
|
|
||||||
position: absolute;
|
|
||||||
right: 0.25rem;
|
|
||||||
top: 0.25rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-main-panel .wiki-page-content .ml-2 {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wiki-main-panel .wiki-page-content .ml-2:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
color:#eb8205;
|
|
||||||
}
|
|
@@ -1,737 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDom from 'react-dom';
|
import ReactDom from 'react-dom';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import axios from 'axios';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import { Button, Tooltip, Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap';
|
|
||||||
/* eslint-disable */
|
|
||||||
import Prism from 'prismjs';
|
|
||||||
/* eslint-enable */
|
|
||||||
import { ReactEditor, DiffViewer } from '@seafile/seafile-editor';
|
|
||||||
import { siteRoot, gettext, draftOriginFilePath, draftFilePath, author, authorAvatar, originFileExists, draftFileExists, draftID, draftFileName, draftRepoID, draftStatus, draftPublishVersion, originFileVersion, filePermission, serviceURL, mediaUrl } from './utils/constants';
|
|
||||||
import { seafileAPI } from './utils/seafile-api';
|
|
||||||
import Loading from './components/loading';
|
|
||||||
import AddReviewerDialog from './components/dialog/add-reviewer-dialog';
|
|
||||||
import HistoryList from './pages/review/history-list';
|
|
||||||
import ModalPortal from './components/modal-portal';
|
|
||||||
|
|
||||||
import './css/layout.css';
|
|
||||||
import './css/toolbar.css';
|
|
||||||
import './css/dirent-detail.css';
|
|
||||||
import './css/draft.css';
|
import './css/draft.css';
|
||||||
|
|
||||||
const URL = require('url-parse');
|
export default function Draft() {
|
||||||
var moment = require('moment');
|
|
||||||
|
|
||||||
const { toDOMNode } = ReactEditor;
|
|
||||||
|
|
||||||
class Draft extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
draftContent: '',
|
|
||||||
draftOriginContent: '',
|
|
||||||
draftInfo: {},
|
|
||||||
isLoading: true,
|
|
||||||
isShowDiff: true,
|
|
||||||
showDiffTip: false,
|
|
||||||
activeTab: 'reviewInfo',
|
|
||||||
changedNodes: [],
|
|
||||||
originRepoName: '',
|
|
||||||
activeItem: null,
|
|
||||||
historyList: [],
|
|
||||||
showReviewerDialog: false,
|
|
||||||
reviewers: [],
|
|
||||||
draftStatus: draftStatus,
|
|
||||||
};
|
|
||||||
this.quote = '';
|
|
||||||
this.newIndex = null;
|
|
||||||
this.oldIndex = null;
|
|
||||||
this.changeIndex = -1;
|
|
||||||
this.range = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
initialContent = () => {
|
|
||||||
switch(draftStatus) {
|
|
||||||
case 'open':
|
|
||||||
if (!draftFileExists) {
|
|
||||||
this.setState({
|
|
||||||
isLoading: false,
|
|
||||||
isShowDiff: false
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!originFileExists) {
|
|
||||||
seafileAPI.getFileDownloadLink(draftRepoID, draftFilePath)
|
|
||||||
.then(res => {
|
|
||||||
seafileAPI.getFileContent(res.data)
|
|
||||||
.then(res => {
|
|
||||||
this.setState({
|
|
||||||
draftContent: res.data,
|
|
||||||
draftOriginContent: res.data,
|
|
||||||
isLoading: false,
|
|
||||||
isShowDiff: false
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line
|
|
||||||
const hash = window.location.hash;
|
|
||||||
if (hash.indexOf('#history-') === 0) {
|
|
||||||
const currentCommitID = hash.slice(9, 49);
|
|
||||||
const preCommitID = hash.slice(50, 90);
|
|
||||||
let preItemFilePath, currentItemFilePath;
|
|
||||||
this.setState({
|
|
||||||
isLoading: false,
|
|
||||||
activeTab: 'history',
|
|
||||||
});
|
|
||||||
seafileAPI.listFileHistoryRecords(draftRepoID, draftFilePath, 1, 25).then((res) => {
|
|
||||||
const historyList = res.data.data;
|
|
||||||
this.setState({
|
|
||||||
historyList: historyList,
|
|
||||||
totalReversionCount: res.data.total_count
|
|
||||||
});
|
|
||||||
for (let i = 0, length = historyList.length; i < length; i++) {
|
|
||||||
if (preCommitID === historyList[i].commit_id) {
|
|
||||||
this.setState({
|
|
||||||
activeItem: i
|
|
||||||
});
|
|
||||||
preItemFilePath = historyList[i].path;
|
|
||||||
}
|
|
||||||
if (currentCommitID === historyList[i].commit_id) {
|
|
||||||
currentItemFilePath = historyList[i].path;
|
|
||||||
}
|
|
||||||
if (preItemFilePath && currentItemFilePath) break;
|
|
||||||
}
|
|
||||||
axios.all([
|
|
||||||
seafileAPI.getFileRevision(draftRepoID, currentCommitID, currentItemFilePath),
|
|
||||||
seafileAPI.getFileRevision(draftRepoID, preCommitID, preItemFilePath)
|
|
||||||
]).then(axios.spread((res1, res2) => {
|
|
||||||
axios.all([seafileAPI.getFileContent(res1.data), seafileAPI.getFileContent(res2.data)]).then(axios.spread((content1, content2) => {
|
|
||||||
this.setDiffViewerContent(content2.data, content1.data);
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
axios.all([
|
|
||||||
seafileAPI.getFileDownloadLink(draftRepoID, draftFilePath),
|
|
||||||
seafileAPI.getFileDownloadLink(draftRepoID, draftOriginFilePath)
|
|
||||||
]).then(axios.spread((res1, res2) => {
|
|
||||||
axios.all([
|
|
||||||
seafileAPI.getFileContent(res1.data),
|
|
||||||
seafileAPI.getFileContent(res2.data)
|
|
||||||
]).then(axios.spread((draftContent, draftOriginContent) => {
|
|
||||||
this.setState({
|
|
||||||
draftContent: draftContent.data,
|
|
||||||
draftOriginContent: draftOriginContent.data,
|
|
||||||
isLoading: false
|
|
||||||
});
|
|
||||||
let that = this;
|
|
||||||
setTimeout(() => {
|
|
||||||
that.getChangedNodes();
|
|
||||||
}, 100);
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'published':
|
|
||||||
if (!originFileExists) {
|
|
||||||
this.setState({
|
|
||||||
isLoading: false,
|
|
||||||
isShowDiff: false
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
|
||||||
let dl0 = siteRoot + 'repo/' + draftRepoID + '/' + draftPublishVersion + '/download?' + 'p=' + draftOriginFilePath;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
let dl = siteRoot + 'repo/' + draftRepoID + '/' + originFileVersion + '/download?' + 'p=' + draftOriginFilePath;
|
|
||||||
axios.all([
|
|
||||||
seafileAPI.getFileContent(dl0),
|
|
||||||
seafileAPI.getFileContent(dl)
|
|
||||||
]).then(axios.spread((draftContent, draftOriginContent) => {
|
|
||||||
this.setState({
|
|
||||||
draftContent: draftContent.data,
|
|
||||||
draftOriginContent: draftOriginContent.data,
|
|
||||||
isLoading: false,
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onHistoryItemClick = (currentItem, preItem, activeItem) => {
|
|
||||||
const preCommitID = preItem.commit_id;
|
|
||||||
const currentCommitID = currentItem.commit_id;
|
|
||||||
const url = 'history-' + preCommitID + '-' + currentCommitID;
|
|
||||||
this.setURL(url);
|
|
||||||
this.setState({
|
|
||||||
activeItem: activeItem,
|
|
||||||
isLoading: true,
|
|
||||||
});
|
|
||||||
axios.all([
|
|
||||||
seafileAPI.getFileRevision(draftRepoID, currentCommitID, currentItem.path),
|
|
||||||
seafileAPI.getFileRevision(draftRepoID, preCommitID, preItem.path)
|
|
||||||
]).then(axios.spread((res1, res2) => {
|
|
||||||
axios.all([seafileAPI.getFileContent(res1.data), seafileAPI.getFileContent(res2.data)]).then(axios.spread((content1,content2) => {
|
|
||||||
this.setDiffViewerContent(content1.data, content2.data);
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
onHistoryListChange = (historyList) => {
|
|
||||||
this.setState({historyList: historyList });
|
|
||||||
};
|
|
||||||
|
|
||||||
getOriginRepoInfo = () => {
|
|
||||||
seafileAPI.getRepoInfo(draftRepoID).then((res) => {
|
|
||||||
this.setState({ originRepoName: res.data.repo_name });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
getDraftInfo = () => {
|
|
||||||
if (draftStatus === 'open') {
|
|
||||||
seafileAPI.getFileInfo(draftRepoID, draftFilePath).then((res) => {
|
|
||||||
this.setState({ draftInfo: res.data });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
getChangedNodes = () => {
|
|
||||||
const nodes = this.refs.diffViewer.value;
|
|
||||||
let keys = [];
|
|
||||||
let lastDiffState = '';
|
|
||||||
nodes.forEach((node, index) => {
|
|
||||||
const diff_state = node.data['diff_state'];
|
|
||||||
if (diff_state === 'diff-added' && lastDiffState !== 'diff-added') {
|
|
||||||
keys.push(index);
|
|
||||||
} else if (diff_state === 'diff-removed' && lastDiffState !== 'diff-removed') {
|
|
||||||
keys.push(index);
|
|
||||||
} else if (diff_state === 'diff-replaced' && lastDiffState !== 'diff-replaced') {
|
|
||||||
keys.push(index);
|
|
||||||
}
|
|
||||||
lastDiffState = node.data.diff_state;
|
|
||||||
});
|
|
||||||
this.setState({
|
|
||||||
changedNodes: keys
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
scrollToChangedNode = (scroll) => {
|
|
||||||
if (this.state.changedNodes.length == 0) return;
|
|
||||||
if (scroll === 'up') { this.changeIndex++; } else { this.changeIndex--; }
|
|
||||||
if (this.changeIndex > this.state.changedNodes.length - 1) {
|
|
||||||
this.changeIndex = 0;
|
|
||||||
}
|
|
||||||
if (this.changeIndex < 0) {
|
|
||||||
this.changeIndex = this.state.changedNodes.length - 1;
|
|
||||||
}
|
|
||||||
const win = window;
|
|
||||||
let key = this.state.changedNodes[this.changeIndex];
|
|
||||||
let node = window.viewer.children[key];
|
|
||||||
let element = toDOMNode(window.viewer, node);
|
|
||||||
// fix code-block or tables
|
|
||||||
while (element.className.indexOf('diff-') === -1 && element.tagName !== 'BODY') {
|
|
||||||
element = element.parentNode;
|
|
||||||
}
|
|
||||||
const scroller = this.findScrollContainer(element, win);
|
|
||||||
const isWindow = scroller == win.document.body || scroller == win.document.documentElement;
|
|
||||||
if (isWindow) {
|
|
||||||
win.scrollTo(0, element.offsetTop);
|
|
||||||
} else {
|
|
||||||
scroller.scrollTop = element.offsetTop;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
findScrollContainer = (element, window) => {
|
|
||||||
let parent = element.parentNode;
|
|
||||||
const OVERFLOWS = ['auto', 'overlay', 'scroll'];
|
|
||||||
let scroller;
|
|
||||||
while (!scroller) {
|
|
||||||
if (!parent.parentNode) break;
|
|
||||||
const style = window.getComputedStyle(parent);
|
|
||||||
const { overflowY } = style;
|
|
||||||
if (OVERFLOWS.includes(overflowY)) {
|
|
||||||
scroller = parent;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
parent = parent.parentNode;
|
|
||||||
}
|
|
||||||
if (!scroller) {
|
|
||||||
return window.document.body;
|
|
||||||
}
|
|
||||||
return scroller;
|
|
||||||
};
|
|
||||||
|
|
||||||
showDiffViewer = () => {
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div style={{display: 'flex', flex: 1, flexDirection: 'column', justifyContent: 'center', alignItems: 'center'}}>
|
||||||
{this.state.isShowDiff ?
|
<h1>Draft module</h1>
|
||||||
<DiffViewer
|
<div>The current module is no longer supported</div>
|
||||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
|
||||||
newMarkdownContent={this.state.draftContent}
|
|
||||||
oldMarkdownContent={this.state.draftOriginContent}
|
|
||||||
ref="diffViewer"
|
|
||||||
/> :
|
|
||||||
<DiffViewer
|
|
||||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
|
||||||
newMarkdownContent={this.state.draftContent}
|
|
||||||
oldMarkdownContent={this.state.draftContent}
|
|
||||||
ref="diffViewer"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
listReviewers = () => {
|
|
||||||
seafileAPI.listDraftReviewers(draftID).then((res) => {
|
|
||||||
this.setState({
|
|
||||||
reviewers: res.data.reviewers
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onSwitchShowDiff = () => {
|
|
||||||
if (!this.state.isShowDiff) {
|
|
||||||
let that = this;
|
|
||||||
setTimeout(() => {
|
|
||||||
that.getChangedNodes();
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
isShowDiff: !this.state.isShowDiff,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleDiffTip = () => {
|
|
||||||
this.setState({
|
|
||||||
showDiffTip: !this.state.showDiffTip
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleAddReviewerDialog = () => {
|
|
||||||
if (this.state.showReviewerDialog) {
|
|
||||||
this.listReviewers();
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
showReviewerDialog: !this.state.showReviewerDialog
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
showDiffButton = () => {
|
|
||||||
return (
|
|
||||||
<div className={'seafile-toggle-diff'}>
|
|
||||||
<label className="custom-switch" id="toggle-diff">
|
|
||||||
<input type="checkbox" checked={this.state.isShowDiff && 'checked'}
|
|
||||||
name="option" className="custom-switch-input"
|
|
||||||
onChange={this.onSwitchShowDiff}/>
|
|
||||||
<span className="custom-switch-indicator"></span>
|
|
||||||
</label>
|
|
||||||
<Tooltip placement="bottom" isOpen={this.state.showDiffTip}
|
|
||||||
target="toggle-diff" toggle={this.toggleDiffTip}>
|
|
||||||
{gettext('View diff')}</Tooltip>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
onPublishDraft = () => {
|
|
||||||
seafileAPI.publishDraft(draftID).then(res => {
|
|
||||||
this.setState({
|
|
||||||
draftStatus: res.data.draft_status,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
initialDiffViewerContent = () => {
|
|
||||||
seafileAPI.listFileHistoryRecords(draftRepoID, draftFilePath, 1, 25).then((res) => {
|
|
||||||
this.setState({
|
|
||||||
historyList: res.data.data,
|
|
||||||
totalReversionCount: res.data.total_count
|
|
||||||
});
|
|
||||||
if (res.data.data.length > 1) {
|
|
||||||
axios.all([
|
|
||||||
seafileAPI.getFileRevision(draftRepoID, res.data.data[0].commit_id, draftFilePath),
|
|
||||||
seafileAPI.getFileRevision(draftRepoID, res.data.data[1].commit_id, draftFilePath)
|
|
||||||
]).then(axios.spread((res1, res2) => {
|
|
||||||
axios.all([seafileAPI.getFileContent(res1.data), seafileAPI.getFileContent(res2.data)]).then(axios.spread((content1,content2) => {
|
|
||||||
this.setState({
|
|
||||||
draftContent: content1.data,
|
|
||||||
draftOriginContent: content2.data
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
seafileAPI.getFileRevision(draftRepoID, res.data.data[0].commit_id, draftFilePath).then((res) => {
|
|
||||||
seafileAPI.getFileContent(res.data).then((content) => {
|
|
||||||
this.setState({
|
|
||||||
draftContent: content.data,
|
|
||||||
draftOriginContent: ''
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
setDiffViewerContent = (newContent, prevContent) => {
|
|
||||||
this.setState({
|
|
||||||
draftContent: newContent,
|
|
||||||
draftOriginContent: prevContent,
|
|
||||||
isLoading: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
setURL = (newurl) => {
|
|
||||||
let url = new URL(window.location.href);
|
|
||||||
url.set('hash', newurl);
|
|
||||||
window.location.href = url.toString();
|
|
||||||
};
|
|
||||||
|
|
||||||
tabItemClick = (tab) => {
|
|
||||||
if (this.state.activeTab !== tab) {
|
|
||||||
if (tab !== 'history' && window.location.hash) {
|
|
||||||
this.setURL('#');
|
|
||||||
}
|
|
||||||
if (tab == 'reviewInfo') {
|
|
||||||
this.initialContent();
|
|
||||||
} else if (tab == 'history') {
|
|
||||||
this.initialDiffViewerContent();
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
activeTab: tab
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
showNavItem = (showTab) => {
|
|
||||||
switch(showTab) {
|
|
||||||
case 'info':
|
|
||||||
return (
|
|
||||||
<NavItem className="nav-item">
|
|
||||||
<NavLink
|
|
||||||
className={classnames({ active: this.state.activeTab === 'reviewInfo' })}
|
|
||||||
onClick={() => { this.tabItemClick('reviewInfo');}}
|
|
||||||
>
|
|
||||||
<i className="fas fa-info-circle"></i>
|
|
||||||
</NavLink>
|
|
||||||
</NavItem>
|
|
||||||
);
|
|
||||||
case 'history':
|
|
||||||
return (
|
|
||||||
<NavItem className="nav-item">
|
|
||||||
<NavLink
|
|
||||||
className={classnames({ active: this.state.activeTab === 'history' })}
|
|
||||||
onClick={() => { this.tabItemClick('history');}}
|
|
||||||
>
|
|
||||||
<i className="fas fa-history"></i>
|
|
||||||
</NavLink>
|
|
||||||
</NavItem>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.getOriginRepoInfo();
|
|
||||||
this.getDraftInfo();
|
|
||||||
this.listReviewers();
|
|
||||||
this.initialContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
renderDiffButton = () => {
|
|
||||||
switch(draftStatus) {
|
|
||||||
case 'open':
|
|
||||||
if (!draftFileExists || !originFileExists) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.showDiffButton();
|
|
||||||
case 'published':
|
|
||||||
if (!originFileExists) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.showDiffButton();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderNavItems = () => {
|
|
||||||
switch (draftStatus) {
|
|
||||||
case 'open':
|
|
||||||
if (!draftFileExists) {
|
|
||||||
return (
|
|
||||||
<Nav tabs className="review-side-panel-nav">
|
|
||||||
{this.showNavItem('info')}
|
|
||||||
</Nav>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Nav tabs className="review-side-panel-nav">
|
|
||||||
{this.showNavItem('info')}
|
|
||||||
{this.showNavItem('history')}
|
|
||||||
</Nav>
|
|
||||||
);
|
|
||||||
case 'published':
|
|
||||||
if (!originFileExists) {
|
|
||||||
return (
|
|
||||||
<Nav tabs className="review-side-panel-nav">
|
|
||||||
{this.showNavItem('info')}
|
|
||||||
</Nav>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Nav tabs className="review-side-panel-nav">
|
|
||||||
{this.showNavItem('info')}
|
|
||||||
</Nav>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
renderContent = () => {
|
|
||||||
switch(draftStatus) {
|
|
||||||
case 'open':
|
|
||||||
if (!draftFileExists) {
|
|
||||||
return <p className="error">{gettext('Draft has been deleted.')}</p>;
|
|
||||||
}
|
|
||||||
return this.showDiffViewer();
|
|
||||||
case 'published':
|
|
||||||
if (!originFileExists) {
|
|
||||||
return <p className="error">{gettext('Original file has been deleted.')}</p>;
|
|
||||||
}
|
|
||||||
return this.showDiffViewer();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { draftInfo, reviewers, originRepoName, draftStatus } = this.state;
|
|
||||||
const draftLink = siteRoot + 'lib/' + draftRepoID + '/file' + draftFilePath + '?mode=edit';
|
|
||||||
const showPublishedButton = this.state.draftStatus == 'published';
|
|
||||||
const showPublishButton = this.state.draftStatus == 'open' && filePermission == 'rw';
|
|
||||||
const showEditButton = this.state.draftStatus == 'open' && filePermission == 'rw';
|
|
||||||
const time = moment(draftInfo.mtime * 1000).format('YYYY-MM-DD HH:mm');
|
|
||||||
const url = `${siteRoot}profile/${encodeURIComponent(draftInfo.last_modifier_email)}/`;
|
|
||||||
return(
|
|
||||||
<div className="wrapper">
|
|
||||||
<div id="header" className="header review">
|
|
||||||
<div className="cur-file-info">
|
|
||||||
<div className="info-item file-feature">
|
|
||||||
<span className="sf2-icon-review"></span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="info-item file-info">
|
|
||||||
<span className="file-name">{draftFileName}</span>
|
|
||||||
<span className="mx-2 file-review">{gettext('Review')}</span>
|
|
||||||
</div>
|
|
||||||
{(!showPublishedButton && draftInfo.mtime) &&
|
|
||||||
<div className="last-modification">
|
|
||||||
<a href={url}>{draftInfo.last_modifier_name}</a><span className="mx-1">{time}</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="button-group">
|
|
||||||
{this.renderDiffButton()}
|
|
||||||
{showEditButton &&
|
|
||||||
<a href={draftLink} className="mx-1">
|
|
||||||
<Button className="file-operation-btn" color="secondary">{gettext('Edit Draft')}</Button>
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
{showPublishButton &&
|
|
||||||
<button className='btn btn-success file-operation-btn' title={gettext('Publish draft')} onClick={this.onPublishDraft}>
|
|
||||||
{gettext('Publish')}
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
{showPublishedButton &&
|
|
||||||
<button className='btn btn-success file-operation-btn' title={gettext('Published')} disabled>
|
|
||||||
{gettext('Published')}
|
|
||||||
</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="main" className="main" ref="main">
|
|
||||||
<div className="cur-view-container">
|
|
||||||
<div className='cur-view-content' ref="viewContent">
|
|
||||||
{this.state.isLoading ?
|
|
||||||
<div className="markdown-viewer-render-content article">
|
|
||||||
<Loading />
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
<div className="markdown-viewer-render-content article">
|
|
||||||
{this.renderContent()}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div className="cur-view-right-part">
|
|
||||||
<div className="review-side-panel">
|
|
||||||
{this.renderNavItems()}
|
|
||||||
<TabContent activeTab={this.state.activeTab}>
|
|
||||||
<TabPane tabId="reviewInfo">
|
|
||||||
<div className="review-side-panel-body">
|
|
||||||
<SidePanelReviewers
|
|
||||||
reviewers={reviewers}
|
|
||||||
toggleAddReviewerDialog={this.toggleAddReviewerDialog}/>
|
|
||||||
<SidePanelAuthor/>
|
|
||||||
{(this.state.isShowDiff === true && this.state.changedNodes.length > 0) &&
|
|
||||||
<SidePanelChanges
|
|
||||||
changedNumber={this.state.changedNodes.length}
|
|
||||||
scrollToChangedNode={this.scrollToChangedNode}/>
|
|
||||||
}
|
|
||||||
<SidePanelOrigin originRepoName={originRepoName} draftInfo={draftInfo} draftStatus={draftStatus}/>
|
|
||||||
</div>
|
|
||||||
</TabPane>
|
|
||||||
<TabPane tabId="history" className="history">
|
|
||||||
<HistoryList
|
|
||||||
activeItem={this.state.activeItem}
|
|
||||||
historyList={this.state.historyList}
|
|
||||||
totalReversionCount={this.state.totalReversionCount}
|
|
||||||
onHistoryItemClick={this.onHistoryItemClick}
|
|
||||||
onHistoryListChange={this.onHistoryListChange}
|
|
||||||
/>
|
|
||||||
</TabPane>
|
|
||||||
</TabContent>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{this.state.showReviewerDialog &&
|
|
||||||
<ModalPortal>
|
|
||||||
<AddReviewerDialog
|
|
||||||
showReviewerDialog={this.state.showReviewerDialog}
|
|
||||||
toggleAddReviewerDialog={this.toggleAddReviewerDialog}
|
|
||||||
draftID={draftID}
|
|
||||||
reviewers={reviewers}
|
|
||||||
/>
|
|
||||||
</ModalPortal>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class SidePanelReviewers extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { reviewers } = this.props;
|
|
||||||
return (
|
|
||||||
<div className="review-side-panel-item">
|
|
||||||
<div className="review-side-panel-header">{gettext('Reviewers')}
|
|
||||||
<i className="fa fa-cog" onClick={this.props.toggleAddReviewerDialog}></i>
|
|
||||||
</div>
|
|
||||||
{reviewers.length > 0 ?
|
|
||||||
reviewers.map((item, index = 0, arr) => {
|
|
||||||
return (
|
|
||||||
<div className="reviewer-info" key={index}>
|
|
||||||
<img className="avatar review-side-panel-avatar" src={item.avatar_url} alt=""/>
|
|
||||||
<span className="reviewer-name ellipsis">{item.user_name}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
:
|
|
||||||
<span>{gettext('No reviewer yet.')}</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sidePanelReviewersPropTypes = {
|
|
||||||
reviewers: PropTypes.array.isRequired,
|
|
||||||
toggleAddReviewerDialog: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
SidePanelReviewers.propTypes = sidePanelReviewersPropTypes;
|
|
||||||
|
|
||||||
class SidePanelAuthor extends React.Component {
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="review-side-panel-item">
|
|
||||||
<div className="review-side-panel-header">{gettext('Author')}</div>
|
|
||||||
<div className="author-info">
|
|
||||||
<img className="avatar review-side-panel-avatar" src={authorAvatar} alt=""/>
|
|
||||||
<span className="author-name ellipsis">{author}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SidePanelOrigin extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { draftStatus, originRepoName } = this.props;
|
|
||||||
const filePath = serviceURL + '/lib/' + draftRepoID + '/file' + draftOriginFilePath;
|
|
||||||
return (
|
|
||||||
<div className="dirent-table-container">
|
|
||||||
<table className="table-thead-hidden">
|
|
||||||
<thead>
|
|
||||||
<tr><th width="25%"></th><th width="75%"></th></tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th className="align-text-top">{gettext('Location')}</th>
|
|
||||||
<td>
|
|
||||||
{draftStatus === 'open' ?
|
|
||||||
<span>{originRepoName}{draftFilePath}</span> :
|
|
||||||
<a href={filePath} className="text-dark">{filePath}</a>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SidePanelOriginPropTypes = {
|
|
||||||
originRepoName: PropTypes.string.isRequired,
|
|
||||||
draftStatus: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
SidePanelOrigin.propTypes = SidePanelOriginPropTypes;
|
|
||||||
|
|
||||||
class SidePanelChanges extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="review-side-panel-item">
|
|
||||||
<div className="review-side-panel-header">{gettext('Changes')}</div>
|
|
||||||
<div className="changes-info">
|
|
||||||
<span>{gettext('Number of changes:')}{' '}{this.props.changedNumber}</span>
|
|
||||||
{this.props.changedNumber > 0 &&
|
|
||||||
<div>
|
|
||||||
<i className="fa fa-arrow-circle-up" onClick={() => { this.props.scrollToChangedNode('down');}}></i>
|
|
||||||
<i className="fa fa-arrow-circle-down" onClick={() => { this.props.scrollToChangedNode('up');}}></i>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sidePanelChangesPropTypes = {
|
|
||||||
changedNumber: PropTypes.number.isRequired,
|
|
||||||
scrollToChangedNode: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
SidePanelChanges.propTypes = sidePanelChangesPropTypes;
|
|
||||||
|
|
||||||
|
|
||||||
ReactDom.render(<Draft />, document.getElementById('wrapper'));
|
ReactDom.render(<Draft />, document.getElementById('wrapper'));
|
||||||
|
@@ -31,19 +31,6 @@ class FileHistory extends React.Component {
|
|||||||
|
|
||||||
onHistoryItemClick = (item, preItem)=> {
|
onHistoryItemClick = (item, preItem)=> {
|
||||||
this.setState({renderingContent: true});
|
this.setState({renderingContent: true});
|
||||||
if (preItem) {
|
|
||||||
axios.all([
|
|
||||||
seafileAPI.getFileRevision(historyRepoID, item.commit_id, item.path),
|
|
||||||
seafileAPI.getFileRevision(historyRepoID, preItem.commit_id, preItem.path)
|
|
||||||
]).then(axios.spread((res, res1) => {
|
|
||||||
axios.all([
|
|
||||||
seafileAPI.getFileContent(res.data),
|
|
||||||
seafileAPI.getFileContent(res1.data)
|
|
||||||
]).then(axios.spread((content1, content2) => {
|
|
||||||
this.setDiffContent(content1.data, content2.data);
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
seafileAPI.getFileRevision(historyRepoID, item.commit_id, item.path).then((res) => {
|
seafileAPI.getFileRevision(historyRepoID, item.commit_id, item.path).then((res) => {
|
||||||
axios.all([
|
axios.all([
|
||||||
seafileAPI.getFileContent(res.data),
|
seafileAPI.getFileContent(res.data),
|
||||||
@@ -51,7 +38,6 @@ class FileHistory extends React.Component {
|
|||||||
this.setDiffContent(content1.data, '');
|
this.setDiffContent(content1.data, '');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onBackClick = (event) => {
|
onBackClick = (event) => {
|
||||||
|
@@ -1,15 +1,18 @@
|
|||||||
// Import React!
|
// Import React!
|
||||||
import React from 'react';
|
import React, { Suspense } from 'react';
|
||||||
import ReactDom from 'react-dom';
|
import ReactDom from 'react-dom';
|
||||||
import { I18nextProvider } from 'react-i18next';
|
import { I18nextProvider } from 'react-i18next';
|
||||||
import i18n from './i18n-seafile-editor';
|
import i18n from './_i18n/i18n-seafile-editor';
|
||||||
import MarkdownEditor from './pages/markdown-editor';
|
import MarkdownEditor from './pages/markdown-editor';
|
||||||
|
import Loading from './components/loading';
|
||||||
|
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
ReactDom.render(
|
ReactDom.render(
|
||||||
<I18nextProvider i18n={ i18n } >
|
<I18nextProvider i18n={ i18n } >
|
||||||
|
<Suspense fallback={<Loading />}>
|
||||||
<MarkdownEditor />
|
<MarkdownEditor />
|
||||||
|
</Suspense>
|
||||||
</I18nextProvider>,
|
</I18nextProvider>,
|
||||||
document.getElementById('root')
|
document.getElementById('root')
|
||||||
);
|
);
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Prism from 'prismjs';
|
import Prism from 'prismjs';
|
||||||
import { DiffViewer } from '@seafile/seafile-editor';
|
import { MarkdownViewer } from '@seafile/seafile-editor';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import { mediaUrl } from '../../utils/constants';
|
import { mediaUrl } from '../../utils/constants';
|
||||||
|
|
||||||
const contentClass = 'markdown-viewer-render-content';
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
renderingContent: PropTypes.bool.isRequired,
|
renderingContent: PropTypes.bool.isRequired,
|
||||||
content: PropTypes.string,
|
content: PropTypes.string,
|
||||||
@@ -24,19 +23,18 @@ class MainPanel extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { renderingContent, newMarkdownContent } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="content-viewer flex-fill">
|
<div className="content-viewer flex-fill">
|
||||||
<div className={contentClass}>
|
{renderingContent && <Loading />}
|
||||||
{this.props.renderingContent ?
|
{!renderingContent && (
|
||||||
(<Loading />) :
|
<MarkdownViewer
|
||||||
(<div className="diff-view article">
|
isFetching={renderingContent}
|
||||||
<DiffViewer
|
value={newMarkdownContent}
|
||||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
isShowOutline={false}
|
||||||
newMarkdownContent={this.props.newMarkdownContent}
|
mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||||
oldMarkdownContent={this.props.oldMarkdownContent}
|
|
||||||
/>
|
/>
|
||||||
</div>)}
|
)}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -23,3 +23,7 @@
|
|||||||
.collab-users-dropdown.dropdown {
|
.collab-users-dropdown.dropdown {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-active[data-active=true] {
|
||||||
|
color: #eb8205;
|
||||||
|
}
|
||||||
|
@@ -45,7 +45,7 @@ class EditorApi {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getParentDectionaryUrl() {
|
getParentDictionaryUrl() {
|
||||||
let parentPath = this.filePath.substring(0, this.filePath.lastIndexOf('/'));
|
let parentPath = this.filePath.substring(0, this.filePath.lastIndexOf('/'));
|
||||||
let libName = encodeURIComponent(repoName);
|
let libName = encodeURIComponent(repoName);
|
||||||
let path = Utils.encodePath(parentPath);
|
let path = Utils.encodePath(parentPath);
|
||||||
|
@@ -23,7 +23,6 @@ const propTypes = {
|
|||||||
onEdit: PropTypes.func.isRequired,
|
onEdit: PropTypes.func.isRequired,
|
||||||
toggleNewDraft: PropTypes.func.isRequired,
|
toggleNewDraft: PropTypes.func.isRequired,
|
||||||
toggleStar: PropTypes.func.isRequired,
|
toggleStar: PropTypes.func.isRequired,
|
||||||
openParentDirectory: PropTypes.func.isRequired,
|
|
||||||
openDialogs: PropTypes.func.isRequired,
|
openDialogs: PropTypes.func.isRequired,
|
||||||
showFileHistory: PropTypes.bool.isRequired,
|
showFileHistory: PropTypes.bool.isRequired,
|
||||||
toggleHistory: PropTypes.func.isRequired,
|
toggleHistory: PropTypes.func.isRequired,
|
||||||
@@ -31,6 +30,7 @@ const propTypes = {
|
|||||||
readOnly: PropTypes.bool.isRequired,
|
readOnly: PropTypes.bool.isRequired,
|
||||||
contentChanged: PropTypes.bool.isRequired,
|
contentChanged: PropTypes.bool.isRequired,
|
||||||
saving: PropTypes.bool.isRequired,
|
saving: PropTypes.bool.isRequired,
|
||||||
|
onSaveEditorContent: PropTypes.func.isRequired,
|
||||||
showDraftSaved: PropTypes.bool.isRequired,
|
showDraftSaved: PropTypes.bool.isRequired,
|
||||||
isLocked: PropTypes.bool.isRequired,
|
isLocked: PropTypes.bool.isRequired,
|
||||||
lockedByMe: PropTypes.bool.isRequired,
|
lockedByMe: PropTypes.bool.isRequired,
|
||||||
@@ -52,10 +52,13 @@ class HeaderToolbar extends React.Component {
|
|||||||
location.href = `seafile://openfile?repo_id=${encodeURIComponent(repoID)}&path=${encodeURIComponent(path)}`;
|
location.href = `seafile://openfile?repo_id=${encodeURIComponent(repoID)}&path=${encodeURIComponent(path)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
openParentDirectory = () => {
|
||||||
|
const { editorApi } = this.props;
|
||||||
|
window.location.href = editorApi.getParentDictionaryUrl();
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let { contentChanged, saving, isLocked, lockedByMe } = this.props;
|
let { contentChanged, saving, isLocked, lockedByMe } = this.props;
|
||||||
let canPublishDraft = this.props.fileInfo.permission == 'rw';
|
|
||||||
let canCreateDraft = canPublishDraft && (!this.props.hasDraft && !this.props.isDraft && this.props.isDocs);
|
|
||||||
|
|
||||||
if (this.props.editorMode === 'rich') {
|
if (this.props.editorMode === 'rich') {
|
||||||
return (
|
return (
|
||||||
@@ -71,27 +74,7 @@ class HeaderToolbar extends React.Component {
|
|||||||
mediaUrl={mediaUrl}
|
mediaUrl={mediaUrl}
|
||||||
isStarred={this.props.fileInfo.isStarred}
|
isStarred={this.props.fileInfo.isStarred}
|
||||||
/>
|
/>
|
||||||
{(this.props.hasDraft && !this.props.isDraft) &&
|
|
||||||
<div className='seafile-btn-view-review'>
|
|
||||||
<div className='tag tag-green'>{gettext('This file is in draft stage.')}
|
|
||||||
<a className="ml-2" onMouseDown={this.props.editorApi.goDraftPage}>{gettext('View Draft')}</a></div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div className="topbar-btn-container">
|
<div className="topbar-btn-container">
|
||||||
{canCreateDraft &&
|
|
||||||
<button onMouseDown={this.props.toggleNewDraft} className="btn btn-success btn-new-draft">
|
|
||||||
{gettext('New Draft')}</button>
|
|
||||||
}
|
|
||||||
{this.props.isDraft &&
|
|
||||||
<div>
|
|
||||||
<button type="button" className="btn btn-success seafile-btn-add-review"
|
|
||||||
onMouseDown={this.props.editorApi.goDraftPage}>{gettext('Start review')}</button>
|
|
||||||
{canPublishDraft &&
|
|
||||||
<button type="button" className="btn btn-success seafile-btn-add-review"
|
|
||||||
onMouseDown={this.props.editorApi.publishDraftFile}>{gettext('Publish')}</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
{(seafileCollabServer && this.props.collabUsers.length > 0) &&
|
{(seafileCollabServer && this.props.collabUsers.length > 0) &&
|
||||||
<CollabUsersButton
|
<CollabUsersButton
|
||||||
className="collab-users-dropdown"
|
className="collab-users-dropdown"
|
||||||
@@ -100,24 +83,43 @@ class HeaderToolbar extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<ButtonItem text={gettext('Open parent directory')} id={'parentDirectory'}
|
<ButtonItem
|
||||||
icon={'fa fa-folder-open'} onMouseDown={this.props.openParentDirectory}/>
|
text={gettext('Open parent directory')}
|
||||||
{(canLockUnlockFile && !isLocked) &&
|
id={'parentDirectory'}
|
||||||
<ButtonItem id="lock-unlock-file" icon='fa fa-lock' text={gettext('Lock')} onMouseDown={this.props.toggleLockFile}/>
|
icon={'fa fa-folder-open'}
|
||||||
}
|
onMouseDown={this.openParentDirectory}
|
||||||
{(canLockUnlockFile && lockedByMe) &&
|
/>
|
||||||
<ButtonItem id="lock-unlock-file" icon='fa fa-unlock' text={gettext('Unlock')} onMouseDown={this.props.toggleLockFile}/>
|
{(canLockUnlockFile && !isLocked) && (
|
||||||
}
|
<ButtonItem
|
||||||
{canGenerateShareLink &&
|
id="lock-unlock-file"
|
||||||
<ButtonItem id={'shareBtn'} text={gettext('Share')} icon={'fa fa-share-alt'}
|
icon='fa fa-lock'
|
||||||
onMouseDown={this.props.toggleShareLinkDialog}/>
|
text={gettext('Lock')}
|
||||||
}
|
onMouseDown={this.props.toggleLockFile}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{(canLockUnlockFile && lockedByMe) && (
|
||||||
|
<ButtonItem
|
||||||
|
id="lock-unlock-file"
|
||||||
|
icon='fa fa-unlock'
|
||||||
|
text={gettext('Unlock')}
|
||||||
|
onMouseDown={this.props.toggleLockFile}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{canGenerateShareLink && (
|
||||||
|
<ButtonItem
|
||||||
|
id={'shareBtn'}
|
||||||
|
text={gettext('Share')}
|
||||||
|
icon={'fa fa-share-alt'}
|
||||||
|
onMouseDown={this.props.toggleShareLinkDialog}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{saving ?
|
{saving ?
|
||||||
<button type={'button'} aria-label={gettext('Saving...')} className={'btn btn-icon btn-secondary btn-active'}>
|
<button type={'button'} aria-label={gettext('Saving...')} className={'btn btn-icon btn-secondary btn-active'}>
|
||||||
<i className={'fa fa-spin fa-spinner'}/></button>
|
<i className={'fa fa-spin fa-spinner'}/>
|
||||||
|
</button>
|
||||||
:
|
:
|
||||||
<ButtonItem text={gettext('Save')} id={'saveButton'} icon={'fa fa-save'} disabled={!contentChanged}
|
<ButtonItem text={gettext('Save')} id={'saveButton'} icon={'fa fa-save'} disabled={!contentChanged}
|
||||||
onMouseDown={window.seafileEditor && window.seafileEditor.onRichEditorSave} isActive={contentChanged}/>
|
onMouseDown={this.props.onSaveEditorContent} isActive={contentChanged}/>
|
||||||
}
|
}
|
||||||
{canDownloadFile && (
|
{canDownloadFile && (
|
||||||
<ButtonItem
|
<ButtonItem
|
||||||
@@ -127,14 +129,14 @@ class HeaderToolbar extends React.Component {
|
|||||||
onClick={this.downloadFile}
|
onClick={this.downloadFile}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{this.props.fileInfo.permission == 'rw' &&
|
{this.props.fileInfo.permission == 'rw' && (
|
||||||
<ButtonItem
|
<ButtonItem
|
||||||
id="open-via-client"
|
id="open-via-client"
|
||||||
icon="sf3-font sf3-font-desktop"
|
icon="sf3-font sf3-font-desktop"
|
||||||
text={gettext('Open via Client')}
|
text={gettext('Open via Client')}
|
||||||
onClick={this.openFileViaClient}
|
onClick={this.openFileViaClient}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<MoreMenu
|
<MoreMenu
|
||||||
readOnly={this.props.readOnly}
|
readOnly={this.props.readOnly}
|
||||||
@@ -170,7 +172,7 @@ class HeaderToolbar extends React.Component {
|
|||||||
editorMode={this.props.editorMode}
|
editorMode={this.props.editorMode}
|
||||||
onEdit={this.props.onEdit}
|
onEdit={this.props.onEdit}
|
||||||
toggleShareLinkDialog={this.props.toggleShareLinkDialog}
|
toggleShareLinkDialog={this.props.toggleShareLinkDialog}
|
||||||
openParentDirectory={this.props.openParentDirectory}
|
openParentDirectory={this.openParentDirectory}
|
||||||
showFileHistory={this.props.showFileHistory}
|
showFileHistory={this.props.showFileHistory}
|
||||||
toggleHistory={this.props.toggleHistory}
|
toggleHistory={this.props.toggleHistory}
|
||||||
isSmallScreen={true}
|
isSmallScreen={true}
|
||||||
@@ -179,7 +181,9 @@ class HeaderToolbar extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (this.props.editorMode === 'plain') {
|
}
|
||||||
|
|
||||||
|
if (this.props.editorMode === 'plain') {
|
||||||
return (
|
return (
|
||||||
<div className="sf-md-viewer-topbar">
|
<div className="sf-md-viewer-topbar">
|
||||||
<div className="sf-md-viewer-topbar-first d-flex justify-content-between">
|
<div className="sf-md-viewer-topbar-first d-flex justify-content-between">
|
||||||
@@ -196,7 +200,8 @@ class HeaderToolbar extends React.Component {
|
|||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
{saving ?
|
{saving ?
|
||||||
<button type={'button'} className={'btn btn-icon btn-secondary btn-active'}>
|
<button type={'button'} className={'btn btn-icon btn-secondary btn-active'}>
|
||||||
<i className={'fa fa-spin fa-spinner'}/></button>
|
<i className={'fa fa-spin fa-spinner'}/>
|
||||||
|
</button>
|
||||||
:
|
:
|
||||||
<ButtonItem id={'saveButton'} text={gettext('Save')} icon={'fa fa-save'} onMouseDown={window.seafileEditor && window.seafileEditor.onPlainEditorSave} disabled={!contentChanged} isActive={contentChanged} />
|
<ButtonItem id={'saveButton'} text={gettext('Save')} icon={'fa fa-save'} onMouseDown={window.seafileEditor && window.seafileEditor.onPlainEditorSave} disabled={!contentChanged} isActive={contentChanged} />
|
||||||
}
|
}
|
||||||
@@ -238,10 +243,11 @@ class HeaderToolbar extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { EXTERNAL_EVENTS, EventBus } from '@seafile/seafile-editor';
|
||||||
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem, Tooltip } from 'reactstrap';
|
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem, Tooltip } from 'reactstrap';
|
||||||
import { gettext, canGenerateShareLink } from '../../../utils/constants';
|
import { gettext, canGenerateShareLink } from '../../../utils/constants';
|
||||||
|
|
||||||
@@ -35,6 +36,11 @@ class MoreMenu extends React.PureComponent {
|
|||||||
this.setState({ dropdownOpen: !this.state.dropdownOpen });
|
this.setState({ dropdownOpen: !this.state.dropdownOpen });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onHelpModuleToggle = (event) => {
|
||||||
|
const eventBus = EventBus.getInstance();
|
||||||
|
eventBus.dispatch(EXTERNAL_EVENTS.ON_HELP_INFO_TOGGLE, true);
|
||||||
|
};
|
||||||
|
|
||||||
downloadFile = () => {
|
downloadFile = () => {
|
||||||
location.href = '?dl=1';
|
location.href = '?dl=1';
|
||||||
};
|
};
|
||||||
@@ -51,18 +57,18 @@ class MoreMenu extends React.PureComponent {
|
|||||||
</DropdownToggle>
|
</DropdownToggle>
|
||||||
<DropdownMenu className="drop-list" right={true}>
|
<DropdownMenu className="drop-list" right={true}>
|
||||||
{(!this.props.readOnly && editorMode === 'rich') &&
|
{(!this.props.readOnly && editorMode === 'rich') &&
|
||||||
<DropdownItem onMouseDown={this.props.onEdit.bind(this, 'plain')}>{gettext('Switch to plain text editor')}</DropdownItem>}
|
<DropdownItem onClick={this.props.onEdit.bind(this, 'plain')}>{gettext('Switch to plain text editor')}</DropdownItem>}
|
||||||
{(!this.props.readOnly && editorMode === 'plain') &&
|
{(!this.props.readOnly && editorMode === 'plain') &&
|
||||||
<DropdownItem onMouseDown={this.props.onEdit.bind(this, 'rich')}>{gettext('Switch to rich text editor')}</DropdownItem>}
|
<DropdownItem onClick={this.props.onEdit.bind(this, 'rich')}>{gettext('Switch to rich text editor')}</DropdownItem>}
|
||||||
{!isSmall && this.props.showFileHistory &&
|
{!isSmall && this.props.showFileHistory &&
|
||||||
<DropdownItem onMouseDown={this.props.toggleHistory}>{gettext('History')}</DropdownItem>}
|
<DropdownItem onClick={this.props.toggleHistory}>{gettext('History')}</DropdownItem>}
|
||||||
{(this.props.openDialogs && editorMode === 'rich') &&
|
{(this.props.openDialogs && editorMode === 'rich') &&
|
||||||
<DropdownItem onMouseDown={this.props.openDialogs.bind(this, 'help')}>{gettext('Help')}</DropdownItem>
|
<DropdownItem onClick={this.onHelpModuleToggle}>{gettext('Help')}</DropdownItem>
|
||||||
}
|
}
|
||||||
{isSmall && <DropdownItem onMouseDown={this.props.openParentDirectory}>{gettext('Open parent directory')}</DropdownItem>}
|
{isSmall && <DropdownItem onClick={this.props.openParentDirectory}>{gettext('Open parent directory')}</DropdownItem>}
|
||||||
{isSmall && canGenerateShareLink && <DropdownItem onMouseDown={this.props.toggleShareLinkDialog}>{gettext('Share')}</DropdownItem>}
|
{isSmall && canGenerateShareLink && <DropdownItem onClick={this.props.toggleShareLinkDialog}>{gettext('Share')}</DropdownItem>}
|
||||||
{(isSmall && this.props.showFileHistory) &&
|
{(isSmall && this.props.showFileHistory) &&
|
||||||
<DropdownItem onMouseDown={this.props.toggleHistory}>{gettext('History')}</DropdownItem>
|
<DropdownItem onClick={this.props.toggleHistory}>{gettext('History')}</DropdownItem>
|
||||||
}
|
}
|
||||||
{isSmall && canDownloadFile &&
|
{isSmall && canDownloadFile &&
|
||||||
<DropdownItem onClick={this.downloadFile}>{gettext('Download')}</DropdownItem>
|
<DropdownItem onClick={this.downloadFile}>{gettext('Download')}</DropdownItem>
|
||||||
|
@@ -1,21 +1,21 @@
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import io from 'socket.io-client';
|
import io from 'socket.io-client';
|
||||||
import { serialize, deserialize } from '@seafile/seafile-editor';
|
import { EXTERNAL_EVENTS, EventBus, RichMarkdownEditor } from '@seafile/seafile-editor';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { seafileAPI } from '../../utils/seafile-api';
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { gettext, isDocs, mediaUrl } from '../../utils/constants';
|
import { gettext, isDocs, mediaUrl } from '../../utils/constants';
|
||||||
import toaster from '../../components/toast';
|
import toaster from '../../components/toast';
|
||||||
import ShareDialog from '../../components/dialog/share-dialog';
|
import ShareDialog from '../../components/dialog/share-dialog';
|
||||||
import InsertFileDialog from '../../components/dialog/insert-file-dialog';
|
import InsertFileDialog from '../../components/dialog/insert-file-dialog';
|
||||||
import LocalDraftDialog from '../../components/dialog/local-draft-dialog';
|
|
||||||
import HeaderToolbar from './header-toolbar';
|
import HeaderToolbar from './header-toolbar';
|
||||||
import SeafileEditor from './seafile-editor';
|
|
||||||
import editorApi from './editor-api';
|
import editorApi from './editor-api';
|
||||||
|
import DetailListView from './detail-list-view';
|
||||||
|
|
||||||
import '../../css/markdown-viewer/markdown-editor.css';
|
import '../../css/markdown-viewer/markdown-editor.css';
|
||||||
|
|
||||||
const CryptoJS = require('crypto-js');
|
const CryptoJS = require('crypto-js');
|
||||||
const URL = require('url-parse');
|
const URL = require('url-parse');
|
||||||
|
|
||||||
const { repoID, filePath, fileName, draftID, isDraft, hasDraft, isLocked, lockedByMe } = window.app.pageOptions;
|
const { repoID, filePath, fileName, draftID, isDraft, hasDraft, isLocked, lockedByMe } = window.app.pageOptions;
|
||||||
const { siteRoot, serviceUrl, seafileCollabServer } = window.app.config;
|
const { siteRoot, serviceUrl, seafileCollabServer } = window.app.config;
|
||||||
const userInfo = window.app.userInfo;
|
const userInfo = window.app.userInfo;
|
||||||
@@ -75,6 +75,9 @@ class MarkdownEditor extends React.Component {
|
|||||||
this.socket_id = socket.id;
|
this.socket_id = socket.id;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
this.editorRef = React.createRef();
|
||||||
|
this.isParticipant = false;
|
||||||
|
this.editorSelection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleLockFile = () => {
|
toggleLockFile = () => {
|
||||||
@@ -121,6 +124,8 @@ class MarkdownEditor extends React.Component {
|
|||||||
|
|
||||||
|
|
||||||
receivePresenceData(data) {
|
receivePresenceData(data) {
|
||||||
|
let collabUsers = [];
|
||||||
|
let editingUsers = [];
|
||||||
switch(data.response) {
|
switch(data.response) {
|
||||||
case 'user_join':
|
case 'user_join':
|
||||||
toaster.notify(`user ${data.user.name} joined`, {
|
toaster.notify(`user ${data.user.name} joined`, {
|
||||||
@@ -142,7 +147,13 @@ class MarkdownEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setState({collabUsers: Object.values(data.users)});
|
collabUsers = Object.values(data.users);
|
||||||
|
editingUsers = collabUsers.filter(ele => ele.is_editing === true && ele.myself === undefined);
|
||||||
|
if (editingUsers.length > 0) {
|
||||||
|
const message = gettext('Another user is editing this file!');
|
||||||
|
toaster.danger(message, {duration: 3});
|
||||||
|
}
|
||||||
|
this.setState({ collabUsers });
|
||||||
return;
|
return;
|
||||||
case 'user_editing':
|
case 'user_editing':
|
||||||
toaster.danger(`user ${data.user.name} is editing this file!`, {
|
toaster.danger(`user ${data.user.name} is editing this file!`, {
|
||||||
@@ -176,14 +187,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setContent = (str) => {
|
|
||||||
let value = deserialize(str);
|
|
||||||
this.setState({
|
|
||||||
markdownContent: str,
|
|
||||||
value: value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
checkDraft = () => {
|
checkDraft = () => {
|
||||||
let draftKey = editorApi.getDraftKey();
|
let draftKey = editorApi.getDraftKey();
|
||||||
let draft = localStorage.getItem(draftKey);
|
let draft = localStorage.getItem(draftKey);
|
||||||
@@ -227,9 +230,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
|
|
||||||
openDialogs = (option) => {
|
openDialogs = (option) => {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case 'help':
|
|
||||||
window.richMarkdownEditor.showHelpDialog();
|
|
||||||
break;
|
|
||||||
case 'share_link':
|
case 'share_link':
|
||||||
this.setState({
|
this.setState({
|
||||||
showMarkdownEditorDialog: true,
|
showMarkdownEditorDialog: true,
|
||||||
@@ -247,18 +247,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.socket.emit('repo_update', {
|
|
||||||
request: 'unwatch_update',
|
|
||||||
repo_id: editorApi.repoID,
|
|
||||||
user: {
|
|
||||||
name: editorApi.name,
|
|
||||||
username: editorApi.username,
|
|
||||||
contact_email: editorApi.contact_email,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
|
|
||||||
const fileIcon = Utils.getFileIconUrl(fileName, 192);
|
const fileIcon = Utils.getFileIconUrl(fileName, 192);
|
||||||
@@ -276,7 +264,6 @@ class MarkdownEditor extends React.Component {
|
|||||||
// get file content
|
// get file content
|
||||||
const fileContentRes = await seafileAPI.getFileContent(downloadUrl);
|
const fileContentRes = await seafileAPI.getFileContent(downloadUrl);
|
||||||
const markdownContent = fileContentRes.data;
|
const markdownContent = fileContentRes.data;
|
||||||
const value = deserialize(markdownContent);
|
|
||||||
|
|
||||||
// init permission
|
// init permission
|
||||||
let hasPermission = permission === 'rw' || permission === 'cloud-edit';
|
let hasPermission = permission === 'rw' || permission === 'cloud-edit';
|
||||||
@@ -300,7 +287,7 @@ class MarkdownEditor extends React.Component {
|
|||||||
loading: false,
|
loading: false,
|
||||||
fileInfo: {...fileInfo, mtime, size, starred, permission, lastModifier, id},
|
fileInfo: {...fileInfo, mtime, size, starred, permission, lastModifier, id},
|
||||||
markdownContent,
|
markdownContent,
|
||||||
value,
|
value: '',
|
||||||
readOnly: !hasPermission || hasDraft,
|
readOnly: !hasPermission || hasDraft,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -333,8 +320,36 @@ class MarkdownEditor extends React.Component {
|
|||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
|
window.addEventListener('beforeunload', this.onUnload);
|
||||||
|
const eventBus = EventBus.getInstance();
|
||||||
|
this.unsubscribeInsertSeafileImage = eventBus.subscribe(EXTERNAL_EVENTS.ON_INSERT_IMAGE, this.onInsertImageToggle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
window.removeEventListener('beforeunload', this.onUnload);
|
||||||
|
this.unsubscribeInsertSeafileImage();
|
||||||
|
if (!this.socket) return;
|
||||||
|
this.socket.emit('repo_update', {
|
||||||
|
request: 'unwatch_update',
|
||||||
|
repo_id: editorApi.repoID,
|
||||||
|
user: {
|
||||||
|
name: editorApi.name,
|
||||||
|
username: editorApi.username,
|
||||||
|
contact_email: editorApi.contact_email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnload = (event) => {
|
||||||
|
const { contentChanged } = this.state;
|
||||||
|
if (!contentChanged) return;
|
||||||
|
this.clearTimer();
|
||||||
|
|
||||||
|
const confirmationMessage = gettext('Leave this page? The system may not save your changes.');
|
||||||
|
event.returnValue = confirmationMessage;
|
||||||
|
return confirmationMessage;
|
||||||
|
};
|
||||||
|
|
||||||
listFileTags = () => {
|
listFileTags = () => {
|
||||||
seafileAPI.listFileTags(repoID, filePath).then(res => {
|
seafileAPI.listFileTags(repoID, filePath).then(res => {
|
||||||
let fileTagList = res.data.file_tags;
|
let fileTagList = res.data.file_tags;
|
||||||
@@ -381,84 +396,82 @@ class MarkdownEditor extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
autoSaveDraft = () => {
|
|
||||||
let that = this;
|
|
||||||
if (that.timer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
that.timer = setTimeout(() => {
|
|
||||||
let str = '';
|
|
||||||
if (this.state.editorMode == 'rich') {
|
|
||||||
let value = this.draftRichValue;
|
|
||||||
str = serialize(value);
|
|
||||||
}
|
|
||||||
else if (this.state.editorMode == 'plain') {
|
|
||||||
str = this.draftPlainValue;
|
|
||||||
}
|
|
||||||
let draftKey = editorApi.getDraftKey();
|
|
||||||
localStorage.setItem(draftKey, str);
|
|
||||||
that.setState({
|
|
||||||
showDraftSaved: true
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
that.setState({
|
|
||||||
showDraftSaved: false
|
|
||||||
});
|
|
||||||
}, 3000);
|
|
||||||
that.timer = null;
|
|
||||||
}, 60000);
|
|
||||||
};
|
|
||||||
|
|
||||||
openParentDirectory = () => {
|
|
||||||
window.location.href = editorApi.getParentDectionaryUrl();
|
|
||||||
};
|
|
||||||
|
|
||||||
onEdit = (editorMode) => {
|
|
||||||
if (editorMode === 'rich') {
|
|
||||||
window.seafileEditor.switchToRichTextEditor();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (editorMode === 'plain') {
|
|
||||||
window.seafileEditor.switchToPlainTextEditor();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleShareLinkDialog = () => {
|
toggleShareLinkDialog = () => {
|
||||||
this.openDialogs('share_link');
|
this.openDialogs('share_link');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onInsertImageToggle = (selection) => {
|
||||||
|
this.editorSelection = selection;
|
||||||
|
this.openDialogs('insert_file');
|
||||||
|
};
|
||||||
|
|
||||||
toggleHistory = () => {
|
toggleHistory = () => {
|
||||||
window.location.href = siteRoot + 'repo/file_revisions/' + repoID + '/?p=' + Utils.encodePath(filePath);
|
window.location.href = siteRoot + 'repo/file_revisions/' + repoID + '/?p=' + Utils.encodePath(filePath);
|
||||||
};
|
};
|
||||||
|
|
||||||
getInsertLink = (repoID, filePath) => {
|
getInsertLink = (repoID, filePath) => {
|
||||||
|
const selection = this.editorSelection;
|
||||||
const fileName = Utils.getFileName(filePath);
|
const fileName = Utils.getFileName(filePath);
|
||||||
const suffix = fileName.slice(fileName.indexOf('.') + 1);
|
const suffix = fileName.slice(fileName.indexOf('.') + 1);
|
||||||
|
const eventBus = EventBus.getInstance();
|
||||||
if (IMAGE_SUFFIXES.includes(suffix)) {
|
if (IMAGE_SUFFIXES.includes(suffix)) {
|
||||||
let innerURL = serviceUrl + '/lib/' + repoID + '/file' + Utils.encodePath(filePath) + '?raw=1';
|
let innerURL = serviceUrl + '/lib/' + repoID + '/file' + Utils.encodePath(filePath) + '?raw=1';
|
||||||
window.richMarkdownEditor.addLink(fileName, innerURL, true);
|
eventBus.dispatch(EXTERNAL_EVENTS.INSERT_IMAGE, { title: fileName, url: innerURL, isImage: true, selection });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let innerURL = serviceUrl + '/lib/' + repoID + '/file' + Utils.encodePath(filePath);
|
let innerURL = serviceUrl + '/lib/' + repoID + '/file' + Utils.encodePath(filePath);
|
||||||
window.richMarkdownEditor.addLink(fileName, innerURL);
|
eventBus.dispatch(EXTERNAL_EVENTS.INSERT_IMAGE, { title: fileName, url: innerURL, selection});
|
||||||
};
|
};
|
||||||
|
|
||||||
onContentChanged = (value) => {
|
addParticipants = () => {
|
||||||
this.setState({ contentChanged: value });
|
if (this.isParticipant || !window.showParticipants) return;
|
||||||
|
const { userName } = editorApi;
|
||||||
|
const { participants } = this.state;
|
||||||
|
if (participants && participants.length !== 0) {
|
||||||
|
const isParticipant = participants.some((participant) => {
|
||||||
|
return participant.email === userName;
|
||||||
|
});
|
||||||
|
if (isParticipant) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emails = [userName];
|
||||||
|
editorApi.addFileParticipants(emails).then((res) => {
|
||||||
|
this.isParticipant = true;
|
||||||
|
this.listFileParticipants();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onSaving = (value) => {
|
onContentChanged = () => {
|
||||||
this.setState({ saving: value });
|
this.setState({ contentChanged: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
onSaveEditorContent = () => {
|
||||||
|
this.setState({ saving: true });
|
||||||
|
const content = this.editorRef.current.getValue();
|
||||||
|
editorApi.saveContent(content).then(() => {
|
||||||
|
this.setState({
|
||||||
|
saving: false,
|
||||||
|
contentChanged: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.lastModifyTime = new Date();
|
||||||
|
const message = gettext('Successfully saved');
|
||||||
|
toaster.success(message, {duration: 2,});
|
||||||
|
|
||||||
|
editorApi.getFileInfo().then((res) => {
|
||||||
|
this.setFileInfoMtime(res.data);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addParticipants();
|
||||||
|
}, () => {
|
||||||
|
this.setState({ saving: false });
|
||||||
|
const message = gettext('Failed to save');
|
||||||
|
toaster.danger(message, {duration: 2});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.loading) {
|
const { loading, editorMode, markdownContent, fileInfo, fileTagList } = this.state;
|
||||||
return (
|
|
||||||
<div className="empty-loading-page">
|
|
||||||
<div className="lds-ripple page-centered"><div></div><div></div></div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
@@ -470,10 +483,9 @@ class MarkdownEditor extends React.Component {
|
|||||||
collabUsers={this.state.collabUsers}
|
collabUsers={this.state.collabUsers}
|
||||||
fileInfo={this.state.fileInfo}
|
fileInfo={this.state.fileInfo}
|
||||||
toggleStar={this.toggleStar}
|
toggleStar={this.toggleStar}
|
||||||
openParentDirectory={this.openParentDirectory}
|
|
||||||
openDialogs={this.openDialogs}
|
openDialogs={this.openDialogs}
|
||||||
toggleShareLinkDialog={this.toggleShareLinkDialog}
|
toggleShareLinkDialog={this.toggleShareLinkDialog}
|
||||||
onEdit={this.onEdit}
|
onEdit={this.setEditorMode}
|
||||||
toggleNewDraft={editorApi.createDraftFile}
|
toggleNewDraft={editorApi.createDraftFile}
|
||||||
showFileHistory={this.state.isShowHistory ? false : true }
|
showFileHistory={this.state.isShowHistory ? false : true }
|
||||||
toggleHistory={this.toggleHistory}
|
toggleHistory={this.toggleHistory}
|
||||||
@@ -481,50 +493,28 @@ class MarkdownEditor extends React.Component {
|
|||||||
editorMode={this.state.editorMode}
|
editorMode={this.state.editorMode}
|
||||||
contentChanged={this.state.contentChanged}
|
contentChanged={this.state.contentChanged}
|
||||||
saving={this.state.saving}
|
saving={this.state.saving}
|
||||||
|
onSaveEditorContent={this.onSaveEditorContent}
|
||||||
showDraftSaved={this.state.showDraftSaved}
|
showDraftSaved={this.state.showDraftSaved}
|
||||||
isLocked={this.state.isLocked}
|
isLocked={this.state.isLocked}
|
||||||
lockedByMe={this.state.lockedByMe}
|
lockedByMe={this.state.lockedByMe}
|
||||||
toggleLockFile={this.toggleLockFile}
|
toggleLockFile={this.toggleLockFile}
|
||||||
/>
|
/>
|
||||||
<SeafileEditor
|
<div className='sf-md-viewer-content'>
|
||||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
<RichMarkdownEditor
|
||||||
fileInfo={this.state.fileInfo}
|
ref={this.editorRef}
|
||||||
markdownContent={this.state.markdownContent}
|
mode={editorMode}
|
||||||
|
isFetching={loading}
|
||||||
|
initValue={fileName}
|
||||||
|
value={markdownContent}
|
||||||
editorApi={editorApi}
|
editorApi={editorApi}
|
||||||
collabUsers={this.state.collabUsers}
|
onSave={this.onSaveEditorContent}
|
||||||
setFileInfoMtime={this.setFileInfoMtime}
|
|
||||||
setEditorMode={this.setEditorMode}
|
|
||||||
setContent={this.setContent}
|
|
||||||
draftID={draftID}
|
|
||||||
isDraft={isDraft}
|
|
||||||
mode={this.state.mode}
|
|
||||||
emitSwitchEditor={this.emitSwitchEditor}
|
|
||||||
hasDraft={hasDraft}
|
|
||||||
editorMode={this.state.editorMode}
|
|
||||||
siteRoot={siteRoot}
|
|
||||||
autoSaveDraft={this.autoSaveDraft}
|
|
||||||
setDraftValue={this.setDraftValue}
|
|
||||||
clearTimer={this.clearTimer}
|
|
||||||
openDialogs={this.openDialogs}
|
|
||||||
deleteDraft={this.deleteDraft}
|
|
||||||
readOnly={this.state.readOnly}
|
|
||||||
onContentChanged={this.onContentChanged}
|
onContentChanged={this.onContentChanged}
|
||||||
onSaving={this.onSaving}
|
mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||||
contentChanged={this.state.contentChanged}
|
isSupportInsertSeafileImage={true}
|
||||||
fileTagList={this.state.fileTagList}
|
>
|
||||||
onFileTagChanged={this.onFileTagChanged}
|
<DetailListView fileInfo={fileInfo} fileTagList={fileTagList} onFileTagChanged={this.onFileTagChanged}/>
|
||||||
participants={this.state.participants}
|
</RichMarkdownEditor>
|
||||||
onParticipantsChange={this.onParticipantsChange}
|
</div>
|
||||||
markdownLint={fileName.toLowerCase() !== 'index.md'}
|
|
||||||
/>
|
|
||||||
{this.state.localDraftDialog &&
|
|
||||||
<LocalDraftDialog
|
|
||||||
localDraftDialog={this.state.localDraftDialog}
|
|
||||||
deleteDraft={this.deleteDraft}
|
|
||||||
closeDraftDialog={this.closeDraftDialog}
|
|
||||||
useDraft={this.useDraft}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{this.state.showMarkdownEditorDialog && (
|
{this.state.showMarkdownEditorDialog && (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{this.state.showInsertFileDialog &&
|
{this.state.showInsertFileDialog &&
|
||||||
|
@@ -1,113 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { EditorContext, Toolbar, MarkdownEditor, UserHelp } from '@seafile/seafile-editor';
|
|
||||||
import SidePanel from './side-panel';
|
|
||||||
|
|
||||||
import '../css/rich-editor.css';
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
scriptSource: PropTypes.string,
|
|
||||||
markdownContent: PropTypes.string,
|
|
||||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
|
|
||||||
issues: PropTypes.object,
|
|
||||||
fileInfo: PropTypes.object,
|
|
||||||
readOnly: PropTypes.bool,
|
|
||||||
editorApi: PropTypes.object,
|
|
||||||
onSave: PropTypes.func.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
resetRichValue: PropTypes.func,
|
|
||||||
fileTagList: PropTypes.array,
|
|
||||||
onFileTagChanged: PropTypes.func,
|
|
||||||
participants: PropTypes.array,
|
|
||||||
onParticipantsChange: PropTypes.func,
|
|
||||||
openDialogs: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
class RichMarkdownEditor extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
isShowSidePanel: false,
|
|
||||||
isShowHelpPanel: false,
|
|
||||||
};
|
|
||||||
window.richMarkdownEditor = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleSidePanel = () => {
|
|
||||||
this.setState({
|
|
||||||
isShowSidePanel: !this.state.isShowSidePanel,
|
|
||||||
isShowHelpPanel: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
showHelpDialog = () => {
|
|
||||||
this.setState({isShowSidePanel: false, isShowHelpPanel: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
hideHelpDialog = () => {
|
|
||||||
this.setState({isShowHelpPanel: false});
|
|
||||||
};
|
|
||||||
|
|
||||||
insertRepoFile = () => {
|
|
||||||
if (this.props.readOnly) return;
|
|
||||||
this.props.openDialogs && this.props.openDialogs('insert_file');
|
|
||||||
};
|
|
||||||
|
|
||||||
addLink = (fileName, url, isImage) => {
|
|
||||||
const editorRef = EditorContext.getEditorRef();
|
|
||||||
editorRef.addLink(fileName, url, isImage);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const hasSidePanel = true;
|
|
||||||
const { isShowSidePanel, isShowHelpPanel } = this.state;
|
|
||||||
const { value } = this.props;
|
|
||||||
|
|
||||||
const isShowHelpWrapper = isShowSidePanel || isShowHelpPanel;
|
|
||||||
const helpWrapperStyle = isShowHelpPanel ? {width: '350px'} : {};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='seafile-markdown-editor'>
|
|
||||||
<div className='markdown-editor-toolbar'>
|
|
||||||
<Toolbar
|
|
||||||
hasSidePanel={hasSidePanel}
|
|
||||||
isShowSidePanel={isShowSidePanel}
|
|
||||||
toggleSidePanel={this.toggleSidePanel}
|
|
||||||
insertRepoFile={this.insertRepoFile}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='markdown-editor-content'>
|
|
||||||
<div className={`markdown-editor-wrapper ${isShowHelpWrapper ? '' : 'full-screen'}`}>
|
|
||||||
<MarkdownEditor
|
|
||||||
scriptSource={this.props.scriptSource}
|
|
||||||
value={value}
|
|
||||||
onSave={this.props.onSave}
|
|
||||||
editorApi={this.props.editorApi}
|
|
||||||
onChange={this.props.onChange}
|
|
||||||
resetRichValue={this.props.resetRichValue}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={`markdown-help-wrapper ${isShowHelpWrapper ? 'show' : ''}`} style={helpWrapperStyle}>
|
|
||||||
{isShowSidePanel && (
|
|
||||||
<SidePanel
|
|
||||||
document={value}
|
|
||||||
fileInfo={this.props.fileInfo}
|
|
||||||
fileTagList={this.props.fileTagList}
|
|
||||||
onFileTagChanged={this.props.onFileTagChanged}
|
|
||||||
participants={this.props.participants}
|
|
||||||
onParticipantsChange={this.props.onParticipantsChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isShowHelpPanel && <UserHelp hideHelpDialog={this.hideHelpDialog} />}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RichMarkdownEditor.propTypes = propTypes;
|
|
||||||
|
|
||||||
|
|
||||||
export default RichMarkdownEditor;
|
|
@@ -1,73 +0,0 @@
|
|||||||
/* eslint-disable jsx-a11y/anchor-is-valid */
|
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Outline as OutlineView } from '@seafile/seafile-editor';
|
|
||||||
import DetailListView from './detail-list-view';
|
|
||||||
|
|
||||||
import '../css/side-panel.css';
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
document: PropTypes.array,
|
|
||||||
fileInfo: PropTypes.object.isRequired,
|
|
||||||
fileTagList: PropTypes.array,
|
|
||||||
onFileTagChanged: PropTypes.func.isRequired,
|
|
||||||
participants: PropTypes.array,
|
|
||||||
onParticipantsChange: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
class SidePanel extends React.PureComponent {
|
|
||||||
|
|
||||||
state = {
|
|
||||||
navItem: 'outline'
|
|
||||||
};
|
|
||||||
|
|
||||||
onOutlineClick = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
this.setState({navItem: 'outline'});
|
|
||||||
};
|
|
||||||
|
|
||||||
onDetailClick = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
this.setState({navItem: 'detail'});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
var outlineActive = '';
|
|
||||||
var detailList = '';
|
|
||||||
if (this.state.navItem === 'outline') {
|
|
||||||
outlineActive = 'active';
|
|
||||||
} else if (this.state.navItem === 'detail') {
|
|
||||||
detailList = 'active';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="side-panel d-flex flex-column">
|
|
||||||
<ul className="flex-shrink-0 nav justify-content-around bg-white">
|
|
||||||
<li className="nav-item">
|
|
||||||
<a className={'nav-link ' + outlineActive} href="" onClick={this.onOutlineClick}><i className="iconfont icon-list-ul"/></a>
|
|
||||||
</li>
|
|
||||||
<li className="nav-item">
|
|
||||||
<a className={'nav-link ' + detailList} href="" onClick={this.onDetailClick}><i className={'iconfont icon-info-circle'}/></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div className="side-panel-content flex-fill">
|
|
||||||
{this.state.navItem === 'outline' &&
|
|
||||||
<OutlineView document={this.props.document} />
|
|
||||||
}
|
|
||||||
{this.state.navItem === 'detail' &&
|
|
||||||
<DetailListView
|
|
||||||
fileInfo={this.props.fileInfo}
|
|
||||||
fileTagList={this.props.fileTagList}
|
|
||||||
onFileTagChanged={this.props.onFileTagChanged}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SidePanel.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default SidePanel;
|
|
@@ -1,268 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Text } from 'slate';
|
|
||||||
import { deserialize, serialize, PlainMarkdownEditor } from '@seafile/seafile-editor';
|
|
||||||
import toaster from '../../../components/toast';
|
|
||||||
import { gettext } from '../../../utils/constants';
|
|
||||||
import RichMarkdownEditor from '../rich-markdown-editor';
|
|
||||||
|
|
||||||
const propTypes = {
|
|
||||||
mode: PropTypes.string,
|
|
||||||
editorMode: PropTypes.string,
|
|
||||||
readOnly: PropTypes.bool,
|
|
||||||
isDraft: PropTypes.bool,
|
|
||||||
scriptSource: PropTypes.string,
|
|
||||||
markdownContent: PropTypes.string,
|
|
||||||
editorApi: PropTypes.object.isRequired,
|
|
||||||
collaUsers: PropTypes.array,
|
|
||||||
onContentChanged: PropTypes.func.isRequired,
|
|
||||||
onSaving: PropTypes.func.isRequired,
|
|
||||||
saving: PropTypes.bool,
|
|
||||||
fileTagList: PropTypes.array,
|
|
||||||
onFileTagChanged: PropTypes.func.isRequired,
|
|
||||||
participants: PropTypes.array.isRequired,
|
|
||||||
onParticipantsChange: PropTypes.func.isRequired,
|
|
||||||
markdownLint: PropTypes.bool,
|
|
||||||
setFileInfoMtime: PropTypes.func.isRequired,
|
|
||||||
setEditorMode: PropTypes.func,
|
|
||||||
autoSaveDraft: PropTypes.func,
|
|
||||||
setDraftValue: PropTypes.func,
|
|
||||||
clearTimer: PropTypes.func,
|
|
||||||
deleteDraft: PropTypes.func,
|
|
||||||
contentChanged: PropTypes.bool,
|
|
||||||
openDialogs: PropTypes.func,
|
|
||||||
fileInfo: PropTypes.object.isRequired,
|
|
||||||
collabUsers: PropTypes.array.isRequired,
|
|
||||||
emitSwitchEditor: PropTypes.func.isRequired,
|
|
||||||
isSaving: PropTypes.bool,
|
|
||||||
collabServer: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
class SeafileEditor extends React.Component {
|
|
||||||
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
const { mode, markdownContent, isDraft } = this.props;
|
|
||||||
const isEditMode = mode === 'editor' || isDraft;
|
|
||||||
const richValue = isEditMode ? deserialize(markdownContent) : deserialize('');
|
|
||||||
this.state = {
|
|
||||||
initialPlainValue: '',
|
|
||||||
currentContent: markdownContent,
|
|
||||||
richValue: richValue,
|
|
||||||
issues: { issue_list: []}
|
|
||||||
};
|
|
||||||
this.lastModifyTime = null;
|
|
||||||
this.autoSave = false;
|
|
||||||
this.isParticipant = false;
|
|
||||||
window.seafileEditor = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
UNSAFE_componentWillMount() {
|
|
||||||
if (this.props.editorMode === 'rich') {
|
|
||||||
const document = this.state.richValue;
|
|
||||||
const firstNode = document[0];
|
|
||||||
/**
|
|
||||||
* if the markdown content is empty, the rich value contains
|
|
||||||
* only a paragraph which contains a empty text node
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
if (document.length === 1 &&
|
|
||||||
firstNode.type === 'paragraph' &&
|
|
||||||
firstNode.children.length === 1 &&
|
|
||||||
Text.isText(firstNode.children[0]) &&
|
|
||||||
firstNode.children[0].text.length === 0) {
|
|
||||||
let headerContent = this.props.fileInfo.name.slice(0, this.props.fileInfo.name.lastIndexOf('.'));
|
|
||||||
const header = {
|
|
||||||
type: 'header_one',
|
|
||||||
children: [{text: headerContent, marks: []}]
|
|
||||||
};
|
|
||||||
document.push(header);
|
|
||||||
document.shift();
|
|
||||||
|
|
||||||
this.setState({richValue: document});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
window.addEventListener('beforeunload', this.onUnload);
|
|
||||||
|
|
||||||
// notify current user if others are also editing this file
|
|
||||||
const { collabUsers } = this.props;
|
|
||||||
const editingUsers = collabUsers.filter(ele => ele.is_editing === true && ele.myself === undefined);
|
|
||||||
if (editingUsers.length > 0) {
|
|
||||||
const message = gettext('Another user is editing this file!');
|
|
||||||
toaster.danger(message, {duration: 3});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
window.removeEventListener('beforeunload', this.onUnload);
|
|
||||||
}
|
|
||||||
|
|
||||||
onUnload = (event) => {
|
|
||||||
if (!this.props.contentChanged) return;
|
|
||||||
const confirmationMessage = gettext('Leave this page? The system may not save your changes.');
|
|
||||||
this.props.clearTimer();
|
|
||||||
this.props.deleteDraft && this.props.deleteDraft();
|
|
||||||
event.returnValue = confirmationMessage;
|
|
||||||
return confirmationMessage;
|
|
||||||
};
|
|
||||||
|
|
||||||
switchToPlainTextEditor = () => {
|
|
||||||
// TODO: performance, change to do serialize in async way
|
|
||||||
if (this.props.editorMode === 'rich') {
|
|
||||||
const value = this.state.richValue;
|
|
||||||
const str = serialize(value);
|
|
||||||
this.props.setEditorMode('plain');
|
|
||||||
this.setState({
|
|
||||||
initialPlainValue: str,
|
|
||||||
currentContent: str
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (this.props.collabServer) {
|
|
||||||
this.props.emitSwitchEditor(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
switchToRichTextEditor = () => {
|
|
||||||
// TODO: performance, change to do deserialize in async way
|
|
||||||
this.setState({richValue: deserialize(this.state.currentContent)});
|
|
||||||
this.props.setEditorMode('rich');
|
|
||||||
|
|
||||||
if (this.props.collabServer) {
|
|
||||||
this.props.emitSwitchEditor(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
saveContent = (str) => {
|
|
||||||
this.props.onSaving(true);
|
|
||||||
this.props.editorApi.saveContent(str).then(() => {
|
|
||||||
this.props.onSaving(false);
|
|
||||||
this.props.onContentChanged(false);
|
|
||||||
// remove markdown lint temporarily
|
|
||||||
// if (this.props.markdownLint) {
|
|
||||||
// const slateValue = this.state.richValue;
|
|
||||||
// this.props.editorApi.markdownLint(JSON.stringify(slateValue)).then((res) => {
|
|
||||||
// this.setState({
|
|
||||||
// issues: res.data
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
this.lastModifyTime = new Date();
|
|
||||||
const message = gettext('Successfully saved');
|
|
||||||
toaster.success(message, {duration: 2,});
|
|
||||||
|
|
||||||
this.props.editorApi.getFileInfo().then((res) => {
|
|
||||||
this.props.setFileInfoMtime(res.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.addParticipants();
|
|
||||||
}, () => {
|
|
||||||
this.props.onSaving(false);
|
|
||||||
const message = gettext('Failed to save');
|
|
||||||
toaster.danger(message, {duration: 2});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onRichEditorSave = () => {
|
|
||||||
if (this.props.isSaving) return;
|
|
||||||
const value = this.state.richValue;
|
|
||||||
const str = serialize(value);
|
|
||||||
this.saveContent(str);
|
|
||||||
this.props.clearTimer();
|
|
||||||
this.props.deleteDraft && this.props.deleteDraft();
|
|
||||||
};
|
|
||||||
|
|
||||||
onPlainEditorSave = () => {
|
|
||||||
if (this.props.isSaving) return;
|
|
||||||
const str = this.state.currentContent;
|
|
||||||
this.saveContent(str);
|
|
||||||
this.props.clearTimer();
|
|
||||||
this.props.deleteDraft && this.props.deleteDraft();
|
|
||||||
};
|
|
||||||
|
|
||||||
resetRichValue = () => {
|
|
||||||
const value = this.state.richValue;
|
|
||||||
this.setState({ richValue: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
onChange = (value, operations) => {
|
|
||||||
if (this.props.editorMode === 'rich') {
|
|
||||||
this.setState({richValue: value,});
|
|
||||||
this.props.setDraftValue('rich', this.state.richValue);
|
|
||||||
const ops = operations.filter(o => {
|
|
||||||
return o.type !== 'set_selection' && o.type !== 'set_value';
|
|
||||||
});
|
|
||||||
if (ops.length !== 0) {
|
|
||||||
this.props.onContentChanged(true);
|
|
||||||
if (this.autoSave) this.props.autoSaveDraft();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.setState({currentContent: value});
|
|
||||||
this.props.onContentChanged(true);
|
|
||||||
this.props.setDraftValue('rich', this.state.richValue);
|
|
||||||
this.props.autoSaveDraft();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
addParticipants = () => {
|
|
||||||
if (this.isParticipant || !window.showParticipants) return;
|
|
||||||
const { userName, addFileParticipants } = this.props.editorApi;
|
|
||||||
const { participants } = this.props;
|
|
||||||
if (participants && participants.length !== 0) {
|
|
||||||
this.isParticipant = participants.every((participant) => {
|
|
||||||
return participant.email === userName;
|
|
||||||
});
|
|
||||||
if (this.isParticipant) return;
|
|
||||||
}
|
|
||||||
let emails = [userName];
|
|
||||||
addFileParticipants(emails).then((res) => {
|
|
||||||
this.isParticipant = true;
|
|
||||||
this.props.onParticipantsChange();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
if (this.props.editorMode === 'rich') {
|
|
||||||
return (
|
|
||||||
<RichMarkdownEditor
|
|
||||||
scriptSource={this.props.scriptSource}
|
|
||||||
readOnly={this.props.readOnly}
|
|
||||||
value={this.state.richValue}
|
|
||||||
editorApi={this.props.editorApi}
|
|
||||||
fileInfo={this.props.fileInfo}
|
|
||||||
collaUsers={this.props.collaUsers}
|
|
||||||
onChange={this.onChange}
|
|
||||||
onSave={this.onRichEditorSave}
|
|
||||||
resetRichValue={this.resetRichValue}
|
|
||||||
fileTagList={this.props.fileTagList}
|
|
||||||
onFileTagChanged={this.props.onFileTagChanged}
|
|
||||||
participants={this.props.participants}
|
|
||||||
onParticipantsChange={this.props.onParticipantsChange}
|
|
||||||
openDialogs={this.props.openDialogs}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PlainMarkdownEditor
|
|
||||||
scriptSource={this.props.scriptSource}
|
|
||||||
editorApi={this.props.editorApi}
|
|
||||||
initialValue={this.state.initialPlainValue}
|
|
||||||
currentContent={this.state.currentContent}
|
|
||||||
contentChanged={this.props.contentChanged}
|
|
||||||
fileInfo={this.props.fileInfo}
|
|
||||||
collabUsers={this.props.collabUsers}
|
|
||||||
onSave={this.onPlainEditorSave}
|
|
||||||
onChange={this.onChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SeafileEditor.propTypes = propTypes;
|
|
||||||
|
|
||||||
export default SeafileEditor;
|
|
@@ -3,8 +3,10 @@ import ReactDom from 'react-dom';
|
|||||||
import MediaQuery from 'react-responsive';
|
import MediaQuery from 'react-responsive';
|
||||||
import { Modal } from 'reactstrap';
|
import { Modal } from 'reactstrap';
|
||||||
import { Router } from '@gatsbyjs/reach-router';
|
import { Router } from '@gatsbyjs/reach-router';
|
||||||
|
import { I18nextProvider } from 'react-i18next';
|
||||||
import { siteRoot } from '../../utils/constants';
|
import { siteRoot } from '../../utils/constants';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
|
import i18n from '../../_i18n/i18n-seafile-editor';
|
||||||
|
|
||||||
import SidePanel from './side-panel';
|
import SidePanel from './side-panel';
|
||||||
import MainPanel from './main-panel';
|
import MainPanel from './main-panel';
|
||||||
@@ -292,4 +294,9 @@ class SysAdmin extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDom.render(<SysAdmin />, document.getElementById('wrapper'));
|
ReactDom.render(
|
||||||
|
<I18nextProvider value={i18n}>
|
||||||
|
<SysAdmin />
|
||||||
|
</I18nextProvider>,
|
||||||
|
document.getElementById('wrapper')
|
||||||
|
);
|
||||||
|
114
frontend/src/pages/wiki/index-md-viewer/index.js
Normal file
114
frontend/src/pages/wiki/index-md-viewer/index.js
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { mdStringToSlate } from '@seafile/seafile-editor';
|
||||||
|
import { isPublicWiki, repoID, serviceURL, slug } from '../../../utils/constants';
|
||||||
|
import { Utils } from '../../../utils/utils';
|
||||||
|
import { generateNavItems } from '../utils/generate-navs';
|
||||||
|
import NavItem from './nav-item';
|
||||||
|
|
||||||
|
import'./style.css';
|
||||||
|
|
||||||
|
const viewerPropTypes = {
|
||||||
|
indexContent: PropTypes.string.isRequired,
|
||||||
|
onLinkClick: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class IndexMdViewer extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.links = [];
|
||||||
|
this.state = {
|
||||||
|
currentPath: '',
|
||||||
|
treeRoot: { name: '', href: '', children: [], isRoot: true },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const { indexContent } = this.props;
|
||||||
|
const slateNodes = mdStringToSlate(indexContent);
|
||||||
|
const newSlateNodes = Utils.changeMarkdownNodes(slateNodes, this.changeInlineNode);
|
||||||
|
const treeRoot = generateNavItems(newSlateNodes);
|
||||||
|
this.setState({
|
||||||
|
treeRoot: treeRoot,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onLinkClick = (node) => {
|
||||||
|
const { currentPath } = this.state;
|
||||||
|
if (node.path === currentPath) return;
|
||||||
|
if (node.path) {
|
||||||
|
this.setState({ currentPath: node.path });
|
||||||
|
}
|
||||||
|
if (node.href) this.props.onLinkClick(node.href);
|
||||||
|
};
|
||||||
|
|
||||||
|
changeInlineNode = (item) => {
|
||||||
|
if (item.type == 'link' || item.type === 'image') {
|
||||||
|
let url;
|
||||||
|
|
||||||
|
// change image url
|
||||||
|
if (item.type == 'image' && isPublicWiki) {
|
||||||
|
url = item.data.src;
|
||||||
|
const re = new RegExp(serviceURL + '/lib/' + repoID +'/file.*raw=1');
|
||||||
|
// different repo
|
||||||
|
if (!re.test(url)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// get image path
|
||||||
|
let index = url.indexOf('/file');
|
||||||
|
let index2 = url.indexOf('?');
|
||||||
|
const imagePath = url.substring(index + 5, index2);
|
||||||
|
// replace url
|
||||||
|
item.data.src = serviceURL + '/view-image-via-public-wiki/?slug=' + slug + '&path=' + imagePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (item.type == 'link') {
|
||||||
|
url = item.url;
|
||||||
|
/* eslint-disable */
|
||||||
|
let expression = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/
|
||||||
|
/* eslint-enable */
|
||||||
|
let re = new RegExp(expression);
|
||||||
|
|
||||||
|
// Solving relative paths
|
||||||
|
if (!re.test(url)) {
|
||||||
|
if (url.startsWith('./')) {
|
||||||
|
url = url.slice(2);
|
||||||
|
}
|
||||||
|
item.url = serviceURL + '/published/' + slug + '/' + url;
|
||||||
|
}
|
||||||
|
// change file url
|
||||||
|
else if (Utils.isInternalMarkdownLink(url, repoID)) {
|
||||||
|
let path = Utils.getPathFromInternalMarkdownLink(url, repoID);
|
||||||
|
// replace url
|
||||||
|
item.url = serviceURL + '/published/' + slug + path;
|
||||||
|
}
|
||||||
|
// change dir url
|
||||||
|
else if (Utils.isInternalDirLink(url, repoID)) {
|
||||||
|
let path = Utils.getPathFromInternalDirLink(url, repoID);
|
||||||
|
// replace url
|
||||||
|
item.url = serviceURL + '/published/' + slug + path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { treeRoot, currentPath } = this.state;
|
||||||
|
return (
|
||||||
|
<div className="mx-4 o-hidden">
|
||||||
|
{treeRoot.children.map(node => {
|
||||||
|
return (
|
||||||
|
<NavItem key={node.path} node={node} currentPath={currentPath} onLinkClick={this.onLinkClick} />
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexMdViewer.propTypes = viewerPropTypes;
|
||||||
|
|
||||||
|
export default IndexMdViewer;
|
91
frontend/src/pages/wiki/index-md-viewer/nav-item.js
Normal file
91
frontend/src/pages/wiki/index-md-viewer/nav-item.js
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
const propTypes = {
|
||||||
|
node: PropTypes.object.isRequired,
|
||||||
|
currentPath: PropTypes.string,
|
||||||
|
onLinkClick: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
class NavItem extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
expanded: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleExpanded = () => {
|
||||||
|
const { expanded } = this.state;
|
||||||
|
this.setState({ expanded: !expanded });
|
||||||
|
};
|
||||||
|
|
||||||
|
onLinkClick = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const { node } = this.props;
|
||||||
|
const { expanded } = this.state;
|
||||||
|
if (node.children && node.children.length > 0 && !expanded) {
|
||||||
|
this.setState({expanded: !expanded});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.props.onLinkClick(node);
|
||||||
|
};
|
||||||
|
|
||||||
|
itemClick = () => {
|
||||||
|
const { node } = this.props;
|
||||||
|
const { expanded } = this.state;
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
this.setState({expanded: !expanded});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderLink = ({ href, name, path, children }) => {
|
||||||
|
const { currentPath } = this.props;
|
||||||
|
const className = classNames('wiki-nav-content', {
|
||||||
|
'no-children': !children || children.length === 0,
|
||||||
|
'wiki-nav-content-highlight': currentPath === path,
|
||||||
|
});
|
||||||
|
if (href && name) {
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<a href={href} data-path={path} onClick={this.onLinkClick} title={name}>{name}</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
return <div className={className} onClick={this.itemClick}><span title={name}>{name}</span></div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { node } = this.props;
|
||||||
|
const { expanded } = this.state;
|
||||||
|
if (node.children.length > 0) {
|
||||||
|
return (
|
||||||
|
<div className="pl-4 position-relative">
|
||||||
|
<span className="switch-btn" onClick={this.toggleExpanded}>
|
||||||
|
{<i className={`fa fa-caret-${expanded ? 'down': 'right'}`}></i>}
|
||||||
|
</span>
|
||||||
|
{this.renderLink(node)}
|
||||||
|
{expanded && node.children.map((child, index) => {
|
||||||
|
return (
|
||||||
|
<NavItem key={index} node={child} currentPath={this.props.currentPath} onLinkClick={this.props.onLinkClick} />
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.renderLink(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NavItem.propTypes = propTypes;
|
||||||
|
|
||||||
|
export default NavItem;
|
@@ -1,7 +1,13 @@
|
|||||||
.wiki-nav-content {
|
.wiki-nav-content {
|
||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
}
|
}
|
||||||
.wiki-nav-content a, .wiki-nav-content span {
|
|
||||||
|
.wiki-nav-content.no-children {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-nav-content a,
|
||||||
|
.wiki-nav-content span {
|
||||||
color: #4d5156;
|
color: #4d5156;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -9,14 +15,17 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.wiki-nav-content-highlight a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #eb8205;
|
|
||||||
}
|
|
||||||
.wiki-nav-content a:hover {
|
.wiki-nav-content a:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #eb8205;
|
color: #eb8205;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wiki-nav-content-highlight a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #eb8205;
|
||||||
|
}
|
||||||
|
|
||||||
.switch-btn {
|
.switch-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
510
frontend/src/pages/wiki/index.js
Normal file
510
frontend/src/pages/wiki/index.js
Normal file
@@ -0,0 +1,510 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
|
import MediaQuery from 'react-responsive';
|
||||||
|
import { Modal } from 'reactstrap';
|
||||||
|
import { Utils } from '../../utils/utils';
|
||||||
|
import { slug, siteRoot, initialPath, isDir, sharedToken, hasIndex, lang } from '../../utils/constants';
|
||||||
|
import { seafileAPI } from '../../utils/seafile-api';
|
||||||
|
import Dirent from '../../models/dirent';
|
||||||
|
import TreeNode from '../../components/tree-view/tree-node';
|
||||||
|
import treeHelper from '../../components/tree-view/tree-helper';
|
||||||
|
import SidePanel from './side-panel';
|
||||||
|
import MainPanel from './main-panel';
|
||||||
|
|
||||||
|
import '../../css/layout.css';
|
||||||
|
import '../../css/side-panel.css';
|
||||||
|
import '../../css/toolbar.css';
|
||||||
|
import '../../css/search.css';
|
||||||
|
import './wiki.css';
|
||||||
|
|
||||||
|
moment.locale(lang);
|
||||||
|
|
||||||
|
class Wiki extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
path: '',
|
||||||
|
pathExist: true,
|
||||||
|
closeSideBar: false,
|
||||||
|
isViewFile: true,
|
||||||
|
isDataLoading: false,
|
||||||
|
direntList: [],
|
||||||
|
content: '',
|
||||||
|
permission: '',
|
||||||
|
lastModified: '',
|
||||||
|
latestContributor: '',
|
||||||
|
isTreeDataLoading: true,
|
||||||
|
treeData: treeHelper.buildTree(),
|
||||||
|
currentNode: null,
|
||||||
|
indexNode: null,
|
||||||
|
indexContent: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
window.onpopstate = this.onpopstate;
|
||||||
|
this.indexPath = '/index.md';
|
||||||
|
this.homePath = '/home.md';
|
||||||
|
this.pythonWrapper = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNSAFE_componentWillMount() {
|
||||||
|
if (!Utils.isDesktop()) {
|
||||||
|
this.setState({ closeSideBar: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.loadSidePanel(initialPath);
|
||||||
|
this.loadWikiData(initialPath);
|
||||||
|
|
||||||
|
this.links = document.querySelectorAll('#wiki-file-content a');
|
||||||
|
this.links.forEach(link => link.addEventListener('click', this.onConentLinkClick));
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.links.forEach(link => link.removeEventListener('click', this.onConentLinkClick));
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSidePanel = (initialPath) => {
|
||||||
|
if (hasIndex) {
|
||||||
|
this.loadIndexNode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load dir list
|
||||||
|
initialPath = isDir === 'None' ? '/' : initialPath;
|
||||||
|
this.loadNodeAndParentsByPath(initialPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
loadWikiData = (initialPath) => {
|
||||||
|
this.pythonWrapper = document.getElementById('wiki-file-content');
|
||||||
|
if (isDir === 'False') {
|
||||||
|
// this.showFile(initialPath);
|
||||||
|
this.setState({path: initialPath});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it is a file list, remove the template content provided by python
|
||||||
|
this.removePythonWrapper();
|
||||||
|
|
||||||
|
if (isDir === 'True') {
|
||||||
|
this.showDir(initialPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDir === 'None' && initialPath === '/home.md') {
|
||||||
|
this.showDir('/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDir === 'None') {
|
||||||
|
this.setState({pathExist: false});
|
||||||
|
let fileUrl = siteRoot + 'published/' + slug + Utils.encodePath(initialPath);
|
||||||
|
window.history.pushState({url: fileUrl, path: initialPath}, initialPath, fileUrl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadIndexNode = () => {
|
||||||
|
seafileAPI.listWikiDir(slug, '/').then(res => {
|
||||||
|
let tree = this.state.treeData;
|
||||||
|
this.addFirstResponseListToNode(res.data.dirent_list, tree.root);
|
||||||
|
let indexNode = tree.getNodeByPath(this.indexPath);
|
||||||
|
seafileAPI.getWikiFileContent(slug, indexNode.path).then(res => {
|
||||||
|
this.setState({
|
||||||
|
treeData: tree,
|
||||||
|
indexNode: indexNode,
|
||||||
|
indexContent: res.data.content,
|
||||||
|
isTreeDataLoading: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
this.setState({isLoadFailed: true});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
showDir = (dirPath) => {
|
||||||
|
this.removePythonWrapper();
|
||||||
|
this.loadDirentList(dirPath);
|
||||||
|
|
||||||
|
// update location url
|
||||||
|
let fileUrl = siteRoot + 'published/' + slug + Utils.encodePath(dirPath);
|
||||||
|
window.history.pushState({url: fileUrl, path: dirPath}, dirPath, fileUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
showFile = (filePath) => {
|
||||||
|
this.setState({
|
||||||
|
isDataLoading: true,
|
||||||
|
isViewFile: true,
|
||||||
|
path: filePath,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.removePythonWrapper();
|
||||||
|
seafileAPI.getWikiFileContent(slug, filePath).then(res => {
|
||||||
|
let data = res.data;
|
||||||
|
this.setState({
|
||||||
|
isDataLoading: false,
|
||||||
|
content: data.content,
|
||||||
|
permission: data.permission,
|
||||||
|
lastModified: moment.unix(data.last_modified).fromNow(),
|
||||||
|
latestContributor: data.latest_contributor,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const hash = window.location.hash;
|
||||||
|
let fileUrl = siteRoot + 'published/' + slug + Utils.encodePath(filePath) + hash;
|
||||||
|
if (filePath === '/home.md') {
|
||||||
|
window.history.replaceState({url: fileUrl, path: filePath}, filePath, fileUrl);
|
||||||
|
} else {
|
||||||
|
window.history.pushState({url: fileUrl, path: filePath}, filePath, fileUrl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadDirentList = (dirPath) => {
|
||||||
|
this.setState({isDataLoading: true});
|
||||||
|
seafileAPI.listWikiDir(slug, dirPath).then(res => {
|
||||||
|
let direntList = res.data.dirent_list.map(item => {
|
||||||
|
let dirent = new Dirent(item);
|
||||||
|
return dirent;
|
||||||
|
});
|
||||||
|
if (dirPath === '/') {
|
||||||
|
direntList = direntList.filter(item => {
|
||||||
|
if (item.type === 'dir') {
|
||||||
|
let name = item.name.toLowerCase();
|
||||||
|
return name !== 'drafts' && name !== 'images' && name !== 'downloads';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
direntList = Utils.sortDirents(direntList, 'name', 'asc');
|
||||||
|
this.setState({
|
||||||
|
path: dirPath,
|
||||||
|
isViewFile: false,
|
||||||
|
direntList: direntList,
|
||||||
|
isDataLoading: false,
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
this.setState({isLoadFailed: true});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loadTreeNodeByPath = (path) => {
|
||||||
|
let tree = this.state.treeData.clone();
|
||||||
|
let node = tree.getNodeByPath(path);
|
||||||
|
if (!node.isLoaded) {
|
||||||
|
seafileAPI.listWikiDir(slug, node.path).then(res => {
|
||||||
|
this.addResponseListToNode(res.data.dirent_list, node);
|
||||||
|
let parentNode = tree.getNodeByPath(node.parentNode.path);
|
||||||
|
parentNode.isExpanded = true;
|
||||||
|
this.setState({
|
||||||
|
treeData: tree,
|
||||||
|
currentNode: node
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let parentNode = tree.getNodeByPath(node.parentNode.path);
|
||||||
|
parentNode.isExpanded = true;
|
||||||
|
this.setState({treeData: tree, currentNode: node}); //tree
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadNodeAndParentsByPath = (path) => {
|
||||||
|
let tree = this.state.treeData.clone();
|
||||||
|
if (Utils.isMarkdownFile(path)) {
|
||||||
|
path = Utils.getDirName(path);
|
||||||
|
}
|
||||||
|
seafileAPI.listWikiDir(slug, path, true).then(res => {
|
||||||
|
let direntList = res.data.dirent_list;
|
||||||
|
let results = {};
|
||||||
|
for (let i = 0; i < direntList.length; i++) {
|
||||||
|
let object = direntList[i];
|
||||||
|
let key = object.parent_dir;
|
||||||
|
if (!results[key]) {
|
||||||
|
results[key] = [];
|
||||||
|
}
|
||||||
|
results[key].push(object);
|
||||||
|
}
|
||||||
|
for (let key in results) {
|
||||||
|
let node = tree.getNodeByPath(key);
|
||||||
|
if (!node.isLoaded && node.path === '/') {
|
||||||
|
this.addFirstResponseListToNode(results[key], node);
|
||||||
|
} else if (!node.isLoaded) {
|
||||||
|
this.addResponseListToNode(results[key], node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
isTreeDataLoading: false,
|
||||||
|
treeData: tree
|
||||||
|
});
|
||||||
|
}).catch(() => {
|
||||||
|
this.setState({isLoadFailed: true});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
removePythonWrapper = () => {
|
||||||
|
if (this.pythonWrapper) {
|
||||||
|
document.body.removeChild(this.pythonWrapper);
|
||||||
|
this.pythonWrapper = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onConentLinkClick = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
let link = '';
|
||||||
|
if (event.target.tagName !== 'A') {
|
||||||
|
let target = event.target.parentNode;
|
||||||
|
while (target.tagName !== 'A') {
|
||||||
|
target = target.parentNode;
|
||||||
|
}
|
||||||
|
link = target.href;
|
||||||
|
} else {
|
||||||
|
link = event.target.href;
|
||||||
|
}
|
||||||
|
this.onLinkClick(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
onLinkClick = (link) => {
|
||||||
|
const url = link;
|
||||||
|
if (Utils.isWikiInternalMarkdownLink(url, slug)) {
|
||||||
|
let path = Utils.getPathFromWikiInternalMarkdownLink(url, slug);
|
||||||
|
this.showFile(path);
|
||||||
|
} else if (Utils.isWikiInternalDirLink(url, slug)) {
|
||||||
|
let path = Utils.getPathFromWikiInternalDirLink(url, slug);
|
||||||
|
this.showDir(path);
|
||||||
|
} else {
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
if (!this.state.closeSideBar) {
|
||||||
|
this.setState({ closeSideBar: true });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onpopstate = (event) => {
|
||||||
|
if (event.state && event.state.path) {
|
||||||
|
let path = event.state.path;
|
||||||
|
if (Utils.isMarkdownFile(path)) {
|
||||||
|
this.showFile(path);
|
||||||
|
} else {
|
||||||
|
this.loadDirentList(path);
|
||||||
|
this.setState({
|
||||||
|
path: path,
|
||||||
|
isViewFile: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onSearchedClick = (item) => {
|
||||||
|
let path = item.is_dir ? item.path.slice(0, item.path.length - 1) : item.path;
|
||||||
|
if (this.state.currentPath === path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// load sidePanel
|
||||||
|
let index = -1;
|
||||||
|
let paths = Utils.getPaths(path);
|
||||||
|
for (let i = 0; i < paths.length; i++) {
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
let node = this.state.treeData.getNodeByPath(node);
|
||||||
|
if (!node) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index === -1) { // all the data has been loaded already.
|
||||||
|
let tree = this.state.treeData.clone();
|
||||||
|
let node = tree.getNodeByPath(item.path);
|
||||||
|
treeHelper.expandNode(node);
|
||||||
|
this.setState({treeData: tree});
|
||||||
|
} else {
|
||||||
|
this.loadNodeAndParentsByPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load mainPanel
|
||||||
|
if (item.is_dir) {
|
||||||
|
this.showDir(path);
|
||||||
|
} else {
|
||||||
|
if (Utils.isMarkdownFile(path)) {
|
||||||
|
this.showFile(path);
|
||||||
|
} else {
|
||||||
|
let url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(path);
|
||||||
|
let newWindow = window.open('about:blank');
|
||||||
|
newWindow.location.href = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMenuClick = () => {
|
||||||
|
this.setState({closeSideBar: !this.state.closeSideBar});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMainNavBarClick = (nodePath) => {
|
||||||
|
let tree = this.state.treeData.clone();
|
||||||
|
let node = tree.getNodeByPath(nodePath);
|
||||||
|
tree.expandNode(node);
|
||||||
|
this.setState({treeData: tree, currentNode: node});
|
||||||
|
this.showDir(node.path);
|
||||||
|
};
|
||||||
|
|
||||||
|
onDirentClick = (dirent) => {
|
||||||
|
let direntPath = Utils.joinPath(this.state.path, dirent.name);
|
||||||
|
if (dirent.isDir()) { // is dir
|
||||||
|
this.loadTreeNodeByPath(direntPath);
|
||||||
|
this.showDir(direntPath);
|
||||||
|
} else { // is file
|
||||||
|
if (Utils.isMarkdownFile(direntPath)) {
|
||||||
|
this.showFile(direntPath);
|
||||||
|
} else {
|
||||||
|
const w=window.open('about:blank');
|
||||||
|
const url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(direntPath);
|
||||||
|
w.location.href = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onCloseSide = () => {
|
||||||
|
this.setState({closeSideBar: !this.state.closeSideBar});
|
||||||
|
};
|
||||||
|
|
||||||
|
onNodeClick = (node) => {
|
||||||
|
if (!this.state.pathExist) {
|
||||||
|
this.setState({pathExist: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.object.isDir()) {
|
||||||
|
if (!node.isLoaded) {
|
||||||
|
let tree = this.state.treeData.clone();
|
||||||
|
node = tree.getNodeByPath(node.path);
|
||||||
|
seafileAPI.listWikiDir(slug, node.path).then(res => {
|
||||||
|
this.addResponseListToNode(res.data.dirent_list, node);
|
||||||
|
tree.collapseNode(node);
|
||||||
|
this.setState({treeData: tree});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (node.path === this.state.path) {
|
||||||
|
if (node.isExpanded) {
|
||||||
|
let tree = treeHelper.collapseNode(this.state.treeData, node);
|
||||||
|
this.setState({treeData: tree});
|
||||||
|
} else {
|
||||||
|
let tree = this.state.treeData.clone();
|
||||||
|
node = tree.getNodeByPath(node.path);
|
||||||
|
tree.expandNode(node);
|
||||||
|
this.setState({treeData: tree});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.path === this.state.path ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.object.isDir()) { // isDir
|
||||||
|
this.showDir(node.path);
|
||||||
|
} else {
|
||||||
|
if (Utils.isMarkdownFile(node.path)) {
|
||||||
|
if (node.path !== this.state.path) {
|
||||||
|
this.showFile(node.path);
|
||||||
|
}
|
||||||
|
this.onCloseSide();
|
||||||
|
} else {
|
||||||
|
const w = window.open('about:blank');
|
||||||
|
const url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(node.path);
|
||||||
|
w.location.href = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onNodeCollapse = (node) => {
|
||||||
|
let tree = treeHelper.collapseNode(this.state.treeData, node);
|
||||||
|
this.setState({treeData: tree});
|
||||||
|
};
|
||||||
|
|
||||||
|
onNodeExpanded = (node) => {
|
||||||
|
let tree = this.state.treeData.clone();
|
||||||
|
node = tree.getNodeByPath(node.path);
|
||||||
|
if (!node.isLoaded) {
|
||||||
|
seafileAPI.listWikiDir(slug, node.path).then(res => {
|
||||||
|
this.addResponseListToNode(res.data.dirent_list, node);
|
||||||
|
this.setState({treeData: tree});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
tree.expandNode(node);
|
||||||
|
this.setState({treeData: tree});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
addFirstResponseListToNode = (list, node) => {
|
||||||
|
node.isLoaded = true;
|
||||||
|
node.isExpanded = true;
|
||||||
|
let direntList = list.map(item => {
|
||||||
|
return new Dirent(item);
|
||||||
|
});
|
||||||
|
direntList = direntList.filter(item => {
|
||||||
|
if (item.type === 'dir') {
|
||||||
|
let name = item.name.toLowerCase();
|
||||||
|
return name !== 'drafts' && name !== 'images' && name !== 'downloads';
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
direntList = Utils.sortDirents(direntList, 'name', 'asc');
|
||||||
|
|
||||||
|
let nodeList = direntList.map(object => {
|
||||||
|
return new TreeNode({object});
|
||||||
|
});
|
||||||
|
node.addChildren(nodeList);
|
||||||
|
};
|
||||||
|
|
||||||
|
addResponseListToNode = (list, node) => {
|
||||||
|
node.isLoaded = true;
|
||||||
|
node.isExpanded = true;
|
||||||
|
let direntList = list.map(item => {
|
||||||
|
return new Dirent(item);
|
||||||
|
});
|
||||||
|
direntList = Utils.sortDirents(direntList, 'name', 'asc');
|
||||||
|
|
||||||
|
let nodeList = direntList.map(object => {
|
||||||
|
return new TreeNode({object});
|
||||||
|
});
|
||||||
|
node.addChildren(nodeList);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div id="main" className="wiki-main">
|
||||||
|
<SidePanel
|
||||||
|
isTreeDataLoading={this.state.isTreeDataLoading}
|
||||||
|
closeSideBar={this.state.closeSideBar}
|
||||||
|
currentPath={this.state.path}
|
||||||
|
treeData={this.state.treeData}
|
||||||
|
indexNode={this.state.indexNode}
|
||||||
|
indexContent={this.state.indexContent}
|
||||||
|
onCloseSide={this.onCloseSide}
|
||||||
|
onNodeClick={this.onNodeClick}
|
||||||
|
onNodeCollapse={this.onNodeCollapse}
|
||||||
|
onNodeExpanded={this.onNodeExpanded}
|
||||||
|
onLinkClick={this.onLinkClick}
|
||||||
|
/>
|
||||||
|
<MainPanel
|
||||||
|
path={this.state.path}
|
||||||
|
pathExist={this.state.pathExist}
|
||||||
|
isViewFile={this.state.isViewFile}
|
||||||
|
isDataLoading={this.state.isDataLoading}
|
||||||
|
content={this.state.content}
|
||||||
|
permission={this.state.permission}
|
||||||
|
lastModified={this.state.lastModified}
|
||||||
|
latestContributor={this.state.latestContributor}
|
||||||
|
direntList={this.state.direntList}
|
||||||
|
onLinkClick={this.onLinkClick}
|
||||||
|
onMenuClick={this.onMenuClick}
|
||||||
|
onSearchedClick={this.onSearchedClick}
|
||||||
|
onMainNavBarClick={this.onMainNavBarClick}
|
||||||
|
onDirentClick={this.onDirentClick}
|
||||||
|
/>
|
||||||
|
<MediaQuery query="(max-width: 767.8px)">
|
||||||
|
<Modal isOpen={!this.state.closeSideBar} toggle={this.onCloseSide} contentClassName="d-none"></Modal>
|
||||||
|
</MediaQuery>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Wiki;
|
@@ -1,10 +1,10 @@
|
|||||||
import React, { Component, Fragment } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { gettext, siteRoot, repoID, slug, username, permission } from '../../utils/constants';
|
import { gettext, siteRoot, repoID, slug, username, permission } from '../../utils/constants';
|
||||||
import Logo from '../../components/logo';
|
import Logo from '../../components/logo';
|
||||||
import Loading from '../../components/loading';
|
import Loading from '../../components/loading';
|
||||||
import TreeView from '../../components/tree-view/tree-view';
|
import TreeView from '../../components/tree-view/tree-view';
|
||||||
import IndexContentViewer from '../../components/index-viewer';
|
import IndexMdViewer from './index-md-viewer';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
closeSideBar: PropTypes.bool.isRequired,
|
closeSideBar: PropTypes.bool.isRequired,
|
||||||
@@ -29,21 +29,18 @@ class SidePanel extends Component {
|
|||||||
|
|
||||||
renderIndexView = () => {
|
renderIndexView = () => {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
|
||||||
<div className="wiki-pages-container">
|
<div className="wiki-pages-container">
|
||||||
<div style={{marginTop: '2px'}}></div>
|
<div style={{marginTop: '2px'}}></div>
|
||||||
<IndexContentViewer
|
<IndexMdViewer
|
||||||
indexContent={this.props.indexContent}
|
indexContent={this.props.indexContent}
|
||||||
onLinkClick={this.props.onLinkClick}
|
onLinkClick={this.props.onLinkClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
renderTreeView = () => {
|
renderTreeView = () => {
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
|
||||||
<div className="wiki-pages-container">
|
<div className="wiki-pages-container">
|
||||||
{this.props.treeData && (
|
{this.props.treeData && (
|
||||||
<TreeView
|
<TreeView
|
||||||
@@ -56,7 +53,6 @@ class SidePanel extends Component {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
91
frontend/src/pages/wiki/utils/generate-navs.js
Normal file
91
frontend/src/pages/wiki/utils/generate-navs.js
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
class TreeNode {
|
||||||
|
|
||||||
|
constructor({ name, href, parentNode }) {
|
||||||
|
this.name = name;
|
||||||
|
this.href = href;
|
||||||
|
this.parentNode = parentNode || null;
|
||||||
|
this.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
setParent(parentNode) {
|
||||||
|
this.parentNode = parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
addChildren(nodeList) {
|
||||||
|
// nodeList.forEach((node) => {
|
||||||
|
// node.setParent(this);
|
||||||
|
// });
|
||||||
|
this.children = nodeList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setNodePath = (node, parentNodePath) => {
|
||||||
|
let name = node.name;
|
||||||
|
let path = parentNodePath === '/' ? parentNodePath + name : parentNodePath + '/' + name;
|
||||||
|
node.path = path;
|
||||||
|
if (node.children.length > 0) {
|
||||||
|
node.children.forEach(child => {
|
||||||
|
setNodePath(child, path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// translate slate_paragraph_node to treeNode
|
||||||
|
const transParagraph = (paragraphNode) => {
|
||||||
|
let treeNode;
|
||||||
|
if (paragraphNode.children[1] && paragraphNode.children[1].type === 'link') {
|
||||||
|
// paragraph node is a link node
|
||||||
|
const linkNode = paragraphNode.children[1];
|
||||||
|
const textNode = linkNode.children[0];
|
||||||
|
const name = textNode ? textNode.text : '';
|
||||||
|
treeNode = new TreeNode({ name: name, href: linkNode.url });
|
||||||
|
} else if (paragraphNode.children[0]) {
|
||||||
|
// paragraph first child node is a text node, then get node name
|
||||||
|
const textNode = paragraphNode.children[0];
|
||||||
|
const name = textNode.text ? textNode.text : '';
|
||||||
|
treeNode = new TreeNode({ name: name, href: '' });
|
||||||
|
} else {
|
||||||
|
treeNode = new TreeNode({ name: '', href: '' });
|
||||||
|
}
|
||||||
|
return treeNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
// slateNodes is list items of an unordered list or ordered list, translate them to treeNode and add to parentTreeNode
|
||||||
|
const transSlateToTree = (slateNodes, parentTreeNode) => {
|
||||||
|
let treeNodes = slateNodes.map((slateNode) => {
|
||||||
|
// item has children(unordered list)
|
||||||
|
if (slateNode.children.length === 2 && (slateNode.children[1].type === 'unordered_list' || slateNode.children[1].type === 'ordered_list')) {
|
||||||
|
// slateNode.nodes[0] is paragraph, create TreeNode, set name and href
|
||||||
|
const paragraphNode = slateNode.children[0];
|
||||||
|
const treeNode = transParagraph(paragraphNode);
|
||||||
|
// slateNode.nodes[1] is list, set it as TreeNode's children
|
||||||
|
const listNode = slateNode.children[1];
|
||||||
|
// Add sub list items to the tree node
|
||||||
|
return transSlateToTree(listNode.children, treeNode);
|
||||||
|
} else {
|
||||||
|
// item doesn't have children list
|
||||||
|
if (slateNode.children[0] && (slateNode.children[0].type === 'paragraph')) {
|
||||||
|
return transParagraph(slateNode.children[0]);
|
||||||
|
} else {
|
||||||
|
// list item contain table/code_block/blockqupta
|
||||||
|
return new TreeNode({ name: '', href: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
parentTreeNode.addChildren(treeNodes);
|
||||||
|
return parentTreeNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const generateNavItems = (slateNodes) => {
|
||||||
|
let treeRoot = new TreeNode({ name: '', href: '' });
|
||||||
|
slateNodes.forEach((node) => {
|
||||||
|
if (node.type === 'unordered_list' || node.type === 'ordered_list') {
|
||||||
|
treeRoot = transSlateToTree(node.children, treeRoot);
|
||||||
|
setNodePath(treeRoot, '/');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return treeRoot;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
160
frontend/src/pages/wiki/wiki.css
Normal file
160
frontend/src/pages/wiki/wiki.css
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
.wiki-side-panel .panel-top {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.wiki-side-nav {
|
||||||
|
flex:auto;
|
||||||
|
display:flex;
|
||||||
|
flex-direction:column;
|
||||||
|
overflow:hidden; /* for ff */
|
||||||
|
border-right:1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-pages-heading {
|
||||||
|
position: relative;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: normal;
|
||||||
|
padding: 0.5rem 0 0.5rem 2rem;
|
||||||
|
border-bottom: 1px solid #e8e8e8;
|
||||||
|
line-height: 1.5;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.heading-icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 1rem;
|
||||||
|
top: 25%;
|
||||||
|
color: #888;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
}
|
||||||
|
.wiki-pages-container {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
.wiki-pages-container:hover {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
.wiki-pages-container .tree-view {
|
||||||
|
margin-left: -10px;
|
||||||
|
margin-top: 14px;
|
||||||
|
padding-left:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img[src=""] {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-side-panel {
|
||||||
|
flex: 0 0 20%;
|
||||||
|
display:flex;
|
||||||
|
flex-direction:column;
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.wiki-side-panel {
|
||||||
|
z-index: 1051;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-main-panel {
|
||||||
|
flex: 1 0 80%;
|
||||||
|
display:flex;
|
||||||
|
flex-direction:column;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-main-panel .main-panel-north {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cur-view-content .wiki-page-container {
|
||||||
|
margin: 0 -1rem -1.25rem;
|
||||||
|
padding: 30px 1rem 1.25rem;
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
padding-left: 30px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cur-view-content .wiki-page-content {
|
||||||
|
width: calc(100% - 200px);
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.cur-view-content .wiki-page-container {
|
||||||
|
padding: 0 14px;
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
.cur-view-content .wiki-page-content {
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .article {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .article h1 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .article span[data-url] {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .article .ml-2 {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .article .ml-2:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
color:#eb8205;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .outline-h2,
|
||||||
|
.wiki-page-container .outline-h3 {
|
||||||
|
height: 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #4d5156;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .outline-h2.active,
|
||||||
|
.wiki-page-container .outline-h3.active {
|
||||||
|
color: #eb8205;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .sf-slate-viewer-scroll-container {
|
||||||
|
background-color: #fff !important;
|
||||||
|
padding: 0px !important;
|
||||||
|
overflow: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .sf-slate-viewer-article-container {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .article {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wiki-page-container .sf-slate-viewer-outline {
|
||||||
|
top: 79px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.wiki-page-container .article {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#wiki-page-last-modified {
|
||||||
|
padding: 40px 10px;
|
||||||
|
font-size:12px;
|
||||||
|
color: #666;
|
||||||
|
}
|
@@ -65,13 +65,6 @@ class FileContent extends React.Component {
|
|||||||
return Utils.changeMarkdownNodes(value, this.changeImageURL);
|
return Utils.changeMarkdownNodes(value, this.changeImageURL);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateForNoOutline = () => {
|
|
||||||
const $outline = document.querySelector('.md-view .seafile-markdown-outline');
|
|
||||||
const $main = document.querySelector('.md-view .article');
|
|
||||||
$outline.className += ' d-none';
|
|
||||||
$main.className += ' article-no-outline';
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (err) {
|
if (err) {
|
||||||
return <SharedFileViewTip />;
|
return <SharedFileViewTip />;
|
||||||
@@ -82,21 +75,14 @@ class FileContent extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="shared-file-view-body">
|
<div className="shared-file-view-body md-view">
|
||||||
<div className="md-view">
|
|
||||||
<MarkdownViewer
|
<MarkdownViewer
|
||||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
value={this.state.markdownContent}
|
||||||
markdownContent={this.state.markdownContent}
|
isShowOutline={true}
|
||||||
showTOC={true}
|
mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||||
updateForNoOutline={this.updateForNoOutline}
|
beforeRenderCallback={this.modifyValueBeforeRender}
|
||||||
activeTitleIndex={''}
|
|
||||||
serviceURL={serviceURL}
|
|
||||||
sharedToken={sharedToken}
|
|
||||||
repoID={repoID}
|
|
||||||
modifyValueBeforeRender={this.modifyValueBeforeRender}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,56 +0,0 @@
|
|||||||
var unified = require('unified');
|
|
||||||
var markdown = require('remark-parse');
|
|
||||||
var slug = require('remark-slug');
|
|
||||||
var breaks = require('remark-breaks');
|
|
||||||
var remark2rehype = require('remark-rehype');
|
|
||||||
var format = require('rehype-format');
|
|
||||||
var raw = require('rehype-raw');
|
|
||||||
var xtend = require('xtend');
|
|
||||||
var toHTML = require('hast-util-to-html');
|
|
||||||
var sanitize = require('hast-util-sanitize');
|
|
||||||
var gh = require('hast-util-sanitize/lib/github');
|
|
||||||
var deepmerge = require('deepmerge').default;
|
|
||||||
|
|
||||||
function stringify(config) {
|
|
||||||
var settings = xtend(config, this.data('settings'));
|
|
||||||
var schema = deepmerge(gh, {
|
|
||||||
'attributes': {
|
|
||||||
'input': [
|
|
||||||
'type',
|
|
||||||
],
|
|
||||||
'li': [
|
|
||||||
'className'
|
|
||||||
],
|
|
||||||
'code': [
|
|
||||||
'className',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'tagNames': [
|
|
||||||
'input',
|
|
||||||
'code'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
this.Compiler = compiler;
|
|
||||||
|
|
||||||
function compiler(tree) {
|
|
||||||
// use sanity to remove dangerous html, the default is
|
|
||||||
var hast = sanitize(tree, schema);
|
|
||||||
return toHTML(hast, settings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// markdown -> mdast -> html AST -> html
|
|
||||||
var processor = unified()
|
|
||||||
.use(markdown, {commonmark: true})
|
|
||||||
.use(breaks)
|
|
||||||
.use(slug)
|
|
||||||
.use(remark2rehype, {allowDangerousHTML: true})
|
|
||||||
.use(raw)
|
|
||||||
.use(format)
|
|
||||||
.use(stringify);
|
|
||||||
|
|
||||||
var processorGetAST = unified()
|
|
||||||
.use(markdown, {commonmark: true})
|
|
||||||
.use(slug);
|
|
||||||
|
|
||||||
export { processor, processorGetAST };
|
|
@@ -1,512 +1,5 @@
|
|||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import ReactDom from 'react-dom';
|
import ReactDom from 'react-dom';
|
||||||
import moment from 'moment';
|
import Wiki from './pages/wiki';
|
||||||
import MediaQuery from 'react-responsive';
|
|
||||||
import { Modal } from 'reactstrap';
|
|
||||||
import { slug, siteRoot, initialPath, isDir, sharedToken, hasIndex } from './utils/constants';
|
|
||||||
import { Utils } from './utils/utils';
|
|
||||||
import { seafileAPI } from './utils/seafile-api';
|
|
||||||
import Dirent from './models/dirent';
|
|
||||||
import TreeNode from './components/tree-view/tree-node';
|
|
||||||
import treeHelper from './components/tree-view/tree-helper';
|
|
||||||
import SidePanel from './pages/wiki/side-panel';
|
|
||||||
import MainPanel from './pages/wiki/main-panel';
|
|
||||||
import { lang } from './utils/constants';
|
|
||||||
|
|
||||||
import './css/layout.css';
|
|
||||||
import './css/side-panel.css';
|
|
||||||
import './css/wiki.css';
|
|
||||||
import './css/toolbar.css';
|
|
||||||
import './css/search.css';
|
|
||||||
|
|
||||||
moment.locale(lang);
|
|
||||||
|
|
||||||
class Wiki extends Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
path: '',
|
|
||||||
pathExist: true,
|
|
||||||
closeSideBar: false,
|
|
||||||
isViewFile: true,
|
|
||||||
isDataLoading: false,
|
|
||||||
direntList: [],
|
|
||||||
content: '',
|
|
||||||
permission: '',
|
|
||||||
lastModified: '',
|
|
||||||
latestContributor: '',
|
|
||||||
isTreeDataLoading: true,
|
|
||||||
treeData: treeHelper.buildTree(),
|
|
||||||
currentNode: null,
|
|
||||||
indexNode: null,
|
|
||||||
indexContent: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
window.onpopstate = this.onpopstate;
|
|
||||||
this.indexPath = '/index.md';
|
|
||||||
this.homePath = '/home.md';
|
|
||||||
this.pythonWrapper = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
UNSAFE_componentWillMount() {
|
|
||||||
if (!Utils.isDesktop()) {
|
|
||||||
this.setState({ closeSideBar: true });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.loadSidePanel(initialPath);
|
|
||||||
this.loadWikiData(initialPath);
|
|
||||||
|
|
||||||
this.links = document.querySelectorAll('#wiki-file-content a');
|
|
||||||
this.links.forEach(link => link.addEventListener('click', this.onConentLinkClick));
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.links.forEach(link => link.removeEventListener('click', this.onConentLinkClick));
|
|
||||||
}
|
|
||||||
|
|
||||||
loadSidePanel = (initialPath) => {
|
|
||||||
if (hasIndex) {
|
|
||||||
this.loadIndexNode();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// load dir list
|
|
||||||
initialPath = isDir === 'None' ? '/' : initialPath;
|
|
||||||
this.loadNodeAndParentsByPath(initialPath);
|
|
||||||
};
|
|
||||||
|
|
||||||
loadWikiData = (initialPath) => {
|
|
||||||
this.pythonWrapper = document.getElementById('wiki-file-content');
|
|
||||||
if (isDir === 'False') {
|
|
||||||
// this.showFile(initialPath);
|
|
||||||
this.setState({path: initialPath});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if it is a file list, remove the template content provided by python
|
|
||||||
this.removePythonWrapper();
|
|
||||||
|
|
||||||
if (isDir === 'True') {
|
|
||||||
this.showDir(initialPath);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDir === 'None' && initialPath === '/home.md') {
|
|
||||||
this.showDir('/');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDir === 'None') {
|
|
||||||
this.setState({pathExist: false});
|
|
||||||
let fileUrl = siteRoot + 'published/' + slug + Utils.encodePath(initialPath);
|
|
||||||
window.history.pushState({url: fileUrl, path: initialPath}, initialPath, fileUrl);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loadIndexNode = () => {
|
|
||||||
seafileAPI.listWikiDir(slug, '/').then(res => {
|
|
||||||
let tree = this.state.treeData;
|
|
||||||
this.addFirstResponseListToNode(res.data.dirent_list, tree.root);
|
|
||||||
let indexNode = tree.getNodeByPath(this.indexPath);
|
|
||||||
seafileAPI.getWikiFileContent(slug, indexNode.path).then(res => {
|
|
||||||
this.setState({
|
|
||||||
treeData: tree,
|
|
||||||
indexNode: indexNode,
|
|
||||||
indexContent: res.data.content,
|
|
||||||
isTreeDataLoading: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}).catch(() => {
|
|
||||||
this.setState({isLoadFailed: true});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
showDir = (dirPath) => {
|
|
||||||
this.removePythonWrapper();
|
|
||||||
this.loadDirentList(dirPath);
|
|
||||||
|
|
||||||
// update location url
|
|
||||||
let fileUrl = siteRoot + 'published/' + slug + Utils.encodePath(dirPath);
|
|
||||||
window.history.pushState({url: fileUrl, path: dirPath}, dirPath, fileUrl);
|
|
||||||
};
|
|
||||||
|
|
||||||
showFile = (filePath) => {
|
|
||||||
this.setState({
|
|
||||||
isDataLoading: true,
|
|
||||||
isViewFile: true,
|
|
||||||
path: filePath,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.removePythonWrapper();
|
|
||||||
seafileAPI.getWikiFileContent(slug, filePath).then(res => {
|
|
||||||
let data = res.data;
|
|
||||||
this.setState({
|
|
||||||
isDataLoading: false,
|
|
||||||
content: data.content,
|
|
||||||
permission: data.permission,
|
|
||||||
lastModified: moment.unix(data.last_modified).fromNow(),
|
|
||||||
latestContributor: data.latest_contributor,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const hash = window.location.hash;
|
|
||||||
let fileUrl = siteRoot + 'published/' + slug + Utils.encodePath(filePath) + hash;
|
|
||||||
if (filePath === '/home.md') {
|
|
||||||
window.history.replaceState({url: fileUrl, path: filePath}, filePath, fileUrl);
|
|
||||||
} else {
|
|
||||||
window.history.pushState({url: fileUrl, path: filePath}, filePath, fileUrl);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loadDirentList = (dirPath) => {
|
|
||||||
this.setState({isDataLoading: true});
|
|
||||||
seafileAPI.listWikiDir(slug, dirPath).then(res => {
|
|
||||||
let direntList = res.data.dirent_list.map(item => {
|
|
||||||
let dirent = new Dirent(item);
|
|
||||||
return dirent;
|
|
||||||
});
|
|
||||||
if (dirPath === '/') {
|
|
||||||
direntList = direntList.filter(item => {
|
|
||||||
if (item.type === 'dir') {
|
|
||||||
let name = item.name.toLowerCase();
|
|
||||||
return name !== 'drafts' && name !== 'images' && name !== 'downloads';
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
direntList = Utils.sortDirents(direntList, 'name', 'asc');
|
|
||||||
this.setState({
|
|
||||||
path: dirPath,
|
|
||||||
isViewFile: false,
|
|
||||||
direntList: direntList,
|
|
||||||
isDataLoading: false,
|
|
||||||
});
|
|
||||||
}).catch(() => {
|
|
||||||
this.setState({isLoadFailed: true});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
loadTreeNodeByPath = (path) => {
|
|
||||||
let tree = this.state.treeData.clone();
|
|
||||||
let node = tree.getNodeByPath(path);
|
|
||||||
if (!node.isLoaded) {
|
|
||||||
seafileAPI.listWikiDir(slug, node.path).then(res => {
|
|
||||||
this.addResponseListToNode(res.data.dirent_list, node);
|
|
||||||
let parentNode = tree.getNodeByPath(node.parentNode.path);
|
|
||||||
parentNode.isExpanded = true;
|
|
||||||
this.setState({
|
|
||||||
treeData: tree,
|
|
||||||
currentNode: node
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
let parentNode = tree.getNodeByPath(node.parentNode.path);
|
|
||||||
parentNode.isExpanded = true;
|
|
||||||
this.setState({treeData: tree, currentNode: node}); //tree
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loadNodeAndParentsByPath = (path) => {
|
|
||||||
let tree = this.state.treeData.clone();
|
|
||||||
if (Utils.isMarkdownFile(path)) {
|
|
||||||
path = Utils.getDirName(path);
|
|
||||||
}
|
|
||||||
seafileAPI.listWikiDir(slug, path, true).then(res => {
|
|
||||||
let direntList = res.data.dirent_list;
|
|
||||||
let results = {};
|
|
||||||
for (let i = 0; i < direntList.length; i++) {
|
|
||||||
let object = direntList[i];
|
|
||||||
let key = object.parent_dir;
|
|
||||||
if (!results[key]) {
|
|
||||||
results[key] = [];
|
|
||||||
}
|
|
||||||
results[key].push(object);
|
|
||||||
}
|
|
||||||
for (let key in results) {
|
|
||||||
let node = tree.getNodeByPath(key);
|
|
||||||
if (!node.isLoaded && node.path === '/') {
|
|
||||||
this.addFirstResponseListToNode(results[key], node);
|
|
||||||
} else if (!node.isLoaded) {
|
|
||||||
this.addResponseListToNode(results[key], node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setState({
|
|
||||||
isTreeDataLoading: false,
|
|
||||||
treeData: tree
|
|
||||||
});
|
|
||||||
}).catch(() => {
|
|
||||||
this.setState({isLoadFailed: true});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
removePythonWrapper = () => {
|
|
||||||
if (this.pythonWrapper) {
|
|
||||||
document.body.removeChild(this.pythonWrapper);
|
|
||||||
this.pythonWrapper = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onConentLinkClick = (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
let link = '';
|
|
||||||
if (event.target.tagName !== 'A') {
|
|
||||||
let target = event.target.parentNode;
|
|
||||||
while (target.tagName !== 'A') {
|
|
||||||
target = target.parentNode;
|
|
||||||
}
|
|
||||||
link = target.href;
|
|
||||||
} else {
|
|
||||||
link = event.target.href;
|
|
||||||
}
|
|
||||||
this.onLinkClick(link);
|
|
||||||
};
|
|
||||||
|
|
||||||
onLinkClick = (link) => {
|
|
||||||
const url = link;
|
|
||||||
if (Utils.isWikiInternalMarkdownLink(url, slug)) {
|
|
||||||
let path = Utils.getPathFromWikiInternalMarkdownLink(url, slug);
|
|
||||||
this.showFile(path);
|
|
||||||
} else if (Utils.isWikiInternalDirLink(url, slug)) {
|
|
||||||
let path = Utils.getPathFromWikiInternalDirLink(url, slug);
|
|
||||||
this.showDir(path);
|
|
||||||
} else {
|
|
||||||
window.location.href = url;
|
|
||||||
}
|
|
||||||
if (!this.state.closeSideBar) {
|
|
||||||
this.setState({ closeSideBar: true });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onpopstate = (event) => {
|
|
||||||
if (event.state && event.state.path) {
|
|
||||||
let path = event.state.path;
|
|
||||||
if (Utils.isMarkdownFile(path)) {
|
|
||||||
this.showFile(path);
|
|
||||||
} else {
|
|
||||||
this.loadDirentList(path);
|
|
||||||
this.setState({
|
|
||||||
path: path,
|
|
||||||
isViewFile: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onSearchedClick = (item) => {
|
|
||||||
let path = item.is_dir ? item.path.slice(0, item.path.length - 1) : item.path;
|
|
||||||
if (this.state.currentPath === path) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// load sidePanel
|
|
||||||
let index = -1;
|
|
||||||
let paths = Utils.getPaths(path);
|
|
||||||
for (let i = 0; i < paths.length; i++) {
|
|
||||||
// eslint-disable-next-line no-use-before-define
|
|
||||||
let node = this.state.treeData.getNodeByPath(node);
|
|
||||||
if (!node) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (index === -1) { // all the data has been loaded already.
|
|
||||||
let tree = this.state.treeData.clone();
|
|
||||||
let node = tree.getNodeByPath(item.path);
|
|
||||||
treeHelper.expandNode(node);
|
|
||||||
this.setState({treeData: tree});
|
|
||||||
} else {
|
|
||||||
this.loadNodeAndParentsByPath(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load mainPanel
|
|
||||||
if (item.is_dir) {
|
|
||||||
this.showDir(path);
|
|
||||||
} else {
|
|
||||||
if (Utils.isMarkdownFile(path)) {
|
|
||||||
this.showFile(path);
|
|
||||||
} else {
|
|
||||||
let url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(path);
|
|
||||||
let newWindow = window.open('about:blank');
|
|
||||||
newWindow.location.href = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMenuClick = () => {
|
|
||||||
this.setState({closeSideBar: !this.state.closeSideBar});
|
|
||||||
};
|
|
||||||
|
|
||||||
onMainNavBarClick = (nodePath) => {
|
|
||||||
let tree = this.state.treeData.clone();
|
|
||||||
let node = tree.getNodeByPath(nodePath);
|
|
||||||
tree.expandNode(node);
|
|
||||||
this.setState({treeData: tree, currentNode: node});
|
|
||||||
this.showDir(node.path);
|
|
||||||
};
|
|
||||||
|
|
||||||
onDirentClick = (dirent) => {
|
|
||||||
let direntPath = Utils.joinPath(this.state.path, dirent.name);
|
|
||||||
if (dirent.isDir()) { // is dir
|
|
||||||
this.loadTreeNodeByPath(direntPath);
|
|
||||||
this.showDir(direntPath);
|
|
||||||
} else { // is file
|
|
||||||
if (Utils.isMarkdownFile(direntPath)) {
|
|
||||||
this.showFile(direntPath);
|
|
||||||
} else {
|
|
||||||
const w=window.open('about:blank');
|
|
||||||
const url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(direntPath);
|
|
||||||
w.location.href = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onCloseSide = () => {
|
|
||||||
this.setState({closeSideBar: !this.state.closeSideBar});
|
|
||||||
};
|
|
||||||
|
|
||||||
onNodeClick = (node) => {
|
|
||||||
if (!this.state.pathExist) {
|
|
||||||
this.setState({pathExist: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.object.isDir()) {
|
|
||||||
if (!node.isLoaded) {
|
|
||||||
let tree = this.state.treeData.clone();
|
|
||||||
node = tree.getNodeByPath(node.path);
|
|
||||||
seafileAPI.listWikiDir(slug, node.path).then(res => {
|
|
||||||
this.addResponseListToNode(res.data.dirent_list, node);
|
|
||||||
tree.collapseNode(node);
|
|
||||||
this.setState({treeData: tree});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (node.path === this.state.path) {
|
|
||||||
if (node.isExpanded) {
|
|
||||||
let tree = treeHelper.collapseNode(this.state.treeData, node);
|
|
||||||
this.setState({treeData: tree});
|
|
||||||
} else {
|
|
||||||
let tree = this.state.treeData.clone();
|
|
||||||
node = tree.getNodeByPath(node.path);
|
|
||||||
tree.expandNode(node);
|
|
||||||
this.setState({treeData: tree});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.path === this.state.path ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.object.isDir()) { // isDir
|
|
||||||
this.showDir(node.path);
|
|
||||||
} else {
|
|
||||||
if (Utils.isMarkdownFile(node.path)) {
|
|
||||||
if (node.path !== this.state.path) {
|
|
||||||
this.showFile(node.path);
|
|
||||||
}
|
|
||||||
this.onCloseSide();
|
|
||||||
} else {
|
|
||||||
const w = window.open('about:blank');
|
|
||||||
const url = siteRoot + 'd/' + sharedToken + '/files/?p=' + Utils.encodePath(node.path);
|
|
||||||
w.location.href = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onNodeCollapse = (node) => {
|
|
||||||
let tree = treeHelper.collapseNode(this.state.treeData, node);
|
|
||||||
this.setState({treeData: tree});
|
|
||||||
};
|
|
||||||
|
|
||||||
onNodeExpanded = (node) => {
|
|
||||||
let tree = this.state.treeData.clone();
|
|
||||||
node = tree.getNodeByPath(node.path);
|
|
||||||
if (!node.isLoaded) {
|
|
||||||
seafileAPI.listWikiDir(slug, node.path).then(res => {
|
|
||||||
this.addResponseListToNode(res.data.dirent_list, node);
|
|
||||||
this.setState({treeData: tree});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
tree.expandNode(node);
|
|
||||||
this.setState({treeData: tree});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
addFirstResponseListToNode = (list, node) => {
|
|
||||||
node.isLoaded = true;
|
|
||||||
node.isExpanded = true;
|
|
||||||
let direntList = list.map(item => {
|
|
||||||
return new Dirent(item);
|
|
||||||
});
|
|
||||||
direntList = direntList.filter(item => {
|
|
||||||
if (item.type === 'dir') {
|
|
||||||
let name = item.name.toLowerCase();
|
|
||||||
return name !== 'drafts' && name !== 'images' && name !== 'downloads';
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
direntList = Utils.sortDirents(direntList, 'name', 'asc');
|
|
||||||
|
|
||||||
let nodeList = direntList.map(object => {
|
|
||||||
return new TreeNode({object});
|
|
||||||
});
|
|
||||||
node.addChildren(nodeList);
|
|
||||||
};
|
|
||||||
|
|
||||||
addResponseListToNode = (list, node) => {
|
|
||||||
node.isLoaded = true;
|
|
||||||
node.isExpanded = true;
|
|
||||||
let direntList = list.map(item => {
|
|
||||||
return new Dirent(item);
|
|
||||||
});
|
|
||||||
direntList = Utils.sortDirents(direntList, 'name', 'asc');
|
|
||||||
|
|
||||||
let nodeList = direntList.map(object => {
|
|
||||||
return new TreeNode({object});
|
|
||||||
});
|
|
||||||
node.addChildren(nodeList);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div id="main" className="wiki-main">
|
|
||||||
<SidePanel
|
|
||||||
isTreeDataLoading={this.state.isTreeDataLoading}
|
|
||||||
closeSideBar={this.state.closeSideBar}
|
|
||||||
currentPath={this.state.path}
|
|
||||||
treeData={this.state.treeData}
|
|
||||||
indexNode={this.state.indexNode}
|
|
||||||
indexContent={this.state.indexContent}
|
|
||||||
onCloseSide={this.onCloseSide}
|
|
||||||
onNodeClick={this.onNodeClick}
|
|
||||||
onNodeCollapse={this.onNodeCollapse}
|
|
||||||
onNodeExpanded={this.onNodeExpanded}
|
|
||||||
onLinkClick={this.onLinkClick}
|
|
||||||
/>
|
|
||||||
<MainPanel
|
|
||||||
path={this.state.path}
|
|
||||||
pathExist={this.state.pathExist}
|
|
||||||
isViewFile={this.state.isViewFile}
|
|
||||||
isDataLoading={this.state.isDataLoading}
|
|
||||||
content={this.state.content}
|
|
||||||
permission={this.state.permission}
|
|
||||||
lastModified={this.state.lastModified}
|
|
||||||
latestContributor={this.state.latestContributor}
|
|
||||||
direntList={this.state.direntList}
|
|
||||||
onLinkClick={this.onLinkClick}
|
|
||||||
onMenuClick={this.onMenuClick}
|
|
||||||
onSearchedClick={this.onSearchedClick}
|
|
||||||
onMainNavBarClick={this.onMainNavBarClick}
|
|
||||||
onDirentClick={this.onDirentClick}
|
|
||||||
/>
|
|
||||||
<MediaQuery query="(max-width: 767.8px)">
|
|
||||||
<Modal isOpen={!this.state.closeSideBar} toggle={this.onCloseSide} contentClassName="d-none"></Modal>
|
|
||||||
</MediaQuery>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReactDom.render(<Wiki />, document.getElementById('wrapper'));
|
ReactDom.render(<Wiki />, document.getElementById('wrapper'));
|
||||||
|
@@ -1,126 +1,126 @@
|
|||||||
{
|
{
|
||||||
"bold": "Tučně",
|
"Bold": "Tučně",
|
||||||
"italic": "Kurzíva",
|
"Italic": "Kurzíva",
|
||||||
"inline_code": "Kód",
|
"Inline_code": "Kód",
|
||||||
"header_one": "Záhlaví 1",
|
"Header_one": "Záhlaví 1",
|
||||||
"header_two": "Záhlaví 2",
|
"Header_two": "Záhlaví 2",
|
||||||
"header_three": "Záhlaví 3",
|
"Header_three": "Záhlaví 3",
|
||||||
"header_four": "Záhlaví 4",
|
"Header_four": "Záhlaví 4",
|
||||||
"header_five": "Záhlaví 5",
|
"Header_five": "Záhlaví 5",
|
||||||
"header_six": "Záhlaví 6",
|
"Header_six": "Záhlaví 6",
|
||||||
"paragraph": "Odstavec",
|
"Paragraph": "Odstavec",
|
||||||
"quote": "Citace",
|
"Quote": "Citace",
|
||||||
"ordered_list": "Číslovaný seznam",
|
"Ordered_list": "Číslovaný seznam",
|
||||||
"unordered_list": "Nečíslovaný seznam",
|
"Unordered_list": "Nečíslovaný seznam",
|
||||||
"check_list_item": "Zkontrolovat položku seznamu",
|
"Check_list_item": "Zkontrolovat položku seznamu",
|
||||||
"insert_image": "Vložit obrázek",
|
"Insert_image": "Vložit obrázek",
|
||||||
"insert_formula": "Insert Formula",
|
"Insert_formula": "Insert Formula",
|
||||||
"formula": "Formula",
|
"Formula": "Formula",
|
||||||
"insert_file": "Vložit soubor",
|
"Insert_file": "Vložit soubor",
|
||||||
"code": "Řádkový kód",
|
"Code": "Řádkový kód",
|
||||||
"code_block": "Blok kódu",
|
"Code_block": "Blok kódu",
|
||||||
"insert_link": "Vložit odkaz",
|
"Insert_link": "Vložit odkaz",
|
||||||
"insert_table": "Vložit tabulku",
|
"Insert_table": "Vložit tabulku",
|
||||||
"save": "Uložit",
|
"Save": "Uložit",
|
||||||
"more": "Více",
|
"More": "Více",
|
||||||
"invalid_url": "Chybná URL",
|
"Invalid_url": "Chybná URL",
|
||||||
"link_address": "Adresa odkazu",
|
"Link_address": "Adresa odkazu",
|
||||||
"image_address": "Adresa obrázku",
|
"Image_address": "Adresa obrázku",
|
||||||
"submit": "Odeslat",
|
"Submit": "Odeslat",
|
||||||
"cancel": "Storno",
|
"Cancel": "Storno",
|
||||||
"switch_to_plain_text_editor": "Přepnout do textového editoru",
|
"Switch_to_plain_text_editor": "Přepnout do textového editoru",
|
||||||
"switch_to_rich_text_editor": "Přepnout do rozšířeného textového editoru",
|
"Switch_to_rich_text_editor": "Přepnout do rozšířeného textového editoru",
|
||||||
"switch_to_viewer": "Přepnout do značkovacího prohlížeče",
|
"Switch_to_viewer": "Přepnout do značkovacího prohlížeče",
|
||||||
"help": "Pomoc",
|
"Help": "Pomoc",
|
||||||
"remove_table": "Odebrat tabulku",
|
"Remove_table": "Odebrat tabulku",
|
||||||
"column": "Sloupec",
|
"Column": "Sloupec",
|
||||||
"row": "Řádek",
|
"Row": "Řádek",
|
||||||
"Insert_Row_Before": "Vložit řádku před",
|
"Insert_row_before": "Insert row before",
|
||||||
"Insert_Row_After": "Vložit řádek za",
|
"Insert_row_after": "Insert row after",
|
||||||
"Insert_Column_Before": "Vložit sloupec před",
|
"Insert_column_before": "Insert column before",
|
||||||
"Insert_Column_After": "Vložit sloupec za",
|
"Insert_column_after": "Insert column after",
|
||||||
"Remove_Row": "Odstranit řádek",
|
"Remove_row": "Remove row",
|
||||||
"Remove_Column": "Odstranit sloupec",
|
"Remove_column": "Remove column",
|
||||||
"Insert_Row": "Vložit řádek",
|
"Insert_row": "Insert row",
|
||||||
"Insert_Column": "Vložit sloupec",
|
"Insert_column": "Insert column",
|
||||||
"set_align": "Nastavit zarovnání",
|
"Set_align": "Nastavit zarovnání",
|
||||||
"left": "Vlevo",
|
"Left": "Vlevo",
|
||||||
"center": "Střed",
|
"Center": "Střed",
|
||||||
"right": "Vpravo",
|
"Right": "Vpravo",
|
||||||
"file_saved": "Soubor uložen",
|
"File_saved": "Soubor uložen",
|
||||||
"file_failed_to_save": "Soubor nebyl uložen",
|
"File_failed_to_save": "Soubor nebyl uložen",
|
||||||
"star": "Přidat hvězdičku",
|
"Star": "Přidat hvězdičku",
|
||||||
"unstar": "Odebrat hvězdičku",
|
"Unstar": "Odebrat hvězdičku",
|
||||||
"back_to_parent_directory":"Zpět do nadřazeného adresáře",
|
"Back_to_parent_directory": "Zpět do nadřazeného adresáře",
|
||||||
"edit": "Upravit",
|
"Edit": "Upravit",
|
||||||
"copy": "Kopírovat",
|
"Copy": "Kopírovat",
|
||||||
"copied": "Zkopírováno",
|
"Copied": "Zkopírováno",
|
||||||
"internal_link": "Interní odkaz",
|
"Internal_link": "Interní odkaz",
|
||||||
"copy_internal_link": "Interní odkaz byl zkopírován do schránky",
|
"Copy_internal_link": "Interní odkaz byl zkopírován do schránky",
|
||||||
"internal_link_desc": "Interní odkaz směřuje na soubor nebo složku u které má uživatel oprávnění ke čtení.",
|
"Internal_link_desc": "Interní odkaz směřuje na soubor nebo složku u které má uživatel oprávnění ke čtení.",
|
||||||
"share": "Sdílet",
|
"Share": "Sdílet",
|
||||||
"share_link": "Veřejný odkaz",
|
"Share_link": "Veřejný odkaz",
|
||||||
"generate": "Generovat",
|
"Generate": "Generovat",
|
||||||
"add_password_protection": "Přidat ochranu heslem",
|
"Add_password_protection": "Přidat ochranu heslem",
|
||||||
"password": "Heslo",
|
"Password": "Heslo",
|
||||||
"at_least_8_characters": "nejméně 8 znaků",
|
"At_least_8_characters": "nejméně 8 znaků",
|
||||||
"password_again": "Heslo znovu",
|
"Password_again": "Heslo znovu",
|
||||||
"add_auto_expiration": "Přidat automatickou expiraci",
|
"Add_auto_expiration": "Přidat automatickou expiraci",
|
||||||
"days": "dní",
|
"Days": "dní",
|
||||||
"please_enter_password": "Zadejte heslo",
|
"Please_enter_password": "Zadejte heslo",
|
||||||
"greater_than_or_equal_to": "Vyšší nebo rovno",
|
"Greater_than_or_equal_to": "Vyšší nebo rovno",
|
||||||
"less_than_or_equal_to": "Nižší nebo rovno",
|
"Less_than_or_equal_to": "Nižší nebo rovno",
|
||||||
"set_permission": "Nastavit oprávnění",
|
"Set_permission": "Nastavit oprávnění",
|
||||||
"preview_and_download": "Zobrazit a stáhnout",
|
"Preview_and_download": "Zobrazit a stáhnout",
|
||||||
"preview_only": "Pouze zobrazit",
|
"Preview_only": "Pouze zobrazit",
|
||||||
"please_enter_valid_days": "Zadejte platné dny",
|
"Please_enter_valid_days": "Zadejte platné dny",
|
||||||
"please_enter_a_non-negative_integer": "Vložte prosím nezáporné celé číslo",
|
"Please_enter_a_non-negative_integer": "Vložte prosím nezáporné celé číslo",
|
||||||
"please_enter_days": "Prosím zadejte dny",
|
"Please_enter_days": "Prosím zadejte dny",
|
||||||
"password_is_too_short": "Heslo je příliš krátké.",
|
"Password_is_too_short": "Heslo je příliš krátké.",
|
||||||
"passwords_do_not_match": "Hesla nesouhlasí",
|
"Passwords_do_not_match": "Hesla nesouhlasí",
|
||||||
"return_to_wiki_page": "Návrat na stránku Wiki",
|
"Return_to_wiki_page": "Návrat na stránku Wiki",
|
||||||
"insert_network_image": "Vložit síťový obrázek",
|
"Insert_network_image": "Vložit síťový obrázek",
|
||||||
"upload_local_image": "Nahrát lokální obrázek",
|
"Upload_local_image": "Nahrát lokální obrázek",
|
||||||
"add_link": "Přidat odkaz",
|
"Add_link": "Přidat odkaz",
|
||||||
"file_history": "Historie souboru",
|
"File_history": "Historie souboru",
|
||||||
"history_version": "Historie verzí",
|
"History_version": "Historie verzí",
|
||||||
"back_to_viewer": "Zpět na prohlížeč",
|
"Back_to_viewer": "Zpět na prohlížeč",
|
||||||
"link_title": "Název odkazu",
|
"Link_title": "Název odkazu",
|
||||||
"local_draft": "Místní koncept",
|
"Local_draft": "Místní koncept",
|
||||||
"use_draft": "Použít koncept",
|
"Use_draft": "Použít koncept",
|
||||||
"delete_draft": "Smazat koncept",
|
"Delete_draft": "Smazat koncept",
|
||||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "Máte neuložený koncept. Chcete ho použít?",
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "Máte neuložený koncept. Chcete ho použít?",
|
||||||
"local_draft_saved": "Místní koncept byl uložen",
|
"Local_draft_saved": "Místní koncept byl uložen",
|
||||||
"new_draft": "Nový návrh",
|
"New_draft": "Nový návrh",
|
||||||
"view_draft": "Zobrazit koncept",
|
"View_draft": "Zobrazit koncept",
|
||||||
"publish": "Zveřejnit",
|
"Publish": "Zveřejnit",
|
||||||
"this_file_has_a_draft": "Tento soubor má koncept.",
|
"This_file_has_a_draft": "Tento soubor má koncept.",
|
||||||
"delete": "Smazat",
|
"Delete": "Smazat",
|
||||||
"comments": "Komentáře",
|
"Comments": "Komentáře",
|
||||||
"add_a_comment": "Přidat komentář…",
|
"Add_a_comment": "Přidat komentář…",
|
||||||
"no_comment_yet": "Žádné komentáře",
|
"No_comment_yet": "Žádné komentáře",
|
||||||
"Mark_as_Resolved": "Označit jako vyřešené",
|
"Mark_as_Resolved": "Označit jako vyřešené",
|
||||||
"ask_for_review": "Požádat o kontrolu",
|
"Ask_for_review": "Požádat o kontrolu",
|
||||||
"review_already_exists": "Kontrola již existuje. ",
|
"Review_already_exists": "Kontrola již existuje. ",
|
||||||
"view_review": "Zobrazit kontrolu",
|
"View_review": "Zobrazit kontrolu",
|
||||||
"there_is_an_associated_review_with_this_file": "K tomuto souboru je přiřazená kontrola",
|
"There_is_an_associated_review_with_this_file": "K tomuto souboru je přiřazená kontrola",
|
||||||
"start_review": "Začít kontrolu",
|
"Start_review": "Začít kontrolu",
|
||||||
"this_file_is_in_draft_stage": "Tento soubor je ve fázi návrhu.",
|
"This_file_is_in_draft_stage": "Tento soubor je ve fázi návrhu.",
|
||||||
"this_file_is_in_review_stage": "Tento soubor je ve fázi kontroly.",
|
"This_file_is_in_review_stage": "Tento soubor je ve fázi kontroly.",
|
||||||
"this_file_has_been_updated": "Tento soubor byl aktualizován.",
|
"This_file_has_been_updated": "Tento soubor byl aktualizován.",
|
||||||
"refresh": "Obnovit",
|
"Refresh": "Obnovit",
|
||||||
"related_files": "související soubory",
|
"Related_files": "související soubory",
|
||||||
"related_file": "související soubor",
|
"Related_file": "související soubor",
|
||||||
"no_tags": "Žádné značky",
|
"No_tags": "Žádné značky",
|
||||||
"Date": "Datum",
|
"Date": "Datum",
|
||||||
"Participants": "Účastníci",
|
"Participants": "Účastníci",
|
||||||
"Meeting_note": "Poznámky ze schůzky",
|
"Meeting_note": "Poznámky ze schůzky",
|
||||||
"Chooser_document_type": "Výběr typu dokumentu",
|
"Chooser_document_type": "Výběr typu dokumentu",
|
||||||
"Empty": "Prázdný",
|
"Empty": "Prázdný",
|
||||||
"no_related_files": "Žádné související soubory",
|
"No_related_files": "Žádné související soubory",
|
||||||
"no_out_line": "Bez obrysu",
|
"No_out_line": "Bez obrysu",
|
||||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Úpravy souborů v tomto prohlížeči mohou způsobit malé problémy se zobrazením.",
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Úpravy souborů v tomto prohlížeči mohou způsobit malé problémy se zobrazením.",
|
||||||
"no_document_improvement_suggestion": "Žádný návrh na zlepšení dokumentu",
|
"No_document_improvement_suggestion": "Žádný návrh na zlepšení dokumentu",
|
||||||
"Hide_side_panel": "Skrýt postranní panel",
|
"Hide_side_panel": "Skrýt postranní panel",
|
||||||
"Show_side_panel": "Zobrazit postranní panel",
|
"Show_side_panel": "Zobrazit postranní panel",
|
||||||
"Show_resolved_comments": "Zobrazit vyřešené komentáře",
|
"Show_resolved_comments": "Zobrazit vyřešené komentáře",
|
||||||
@@ -131,25 +131,16 @@
|
|||||||
"Insert_library_image": "Vložit obrázek knihovny",
|
"Insert_library_image": "Vložit obrázek knihovny",
|
||||||
"Size": "Velikost",
|
"Size": "Velikost",
|
||||||
"Location": "Umístění",
|
"Location": "Umístění",
|
||||||
"Last_Update": "Poslední aktualizace",
|
"Last_update": "Last update",
|
||||||
"Tags": "Štítky",
|
"Tags": "Štítky",
|
||||||
"Related_Files": "Související soubory",
|
|
||||||
"Add_participants": "Přidat účastníky",
|
"Add_participants": "Přidat účastníky",
|
||||||
"markdownLint": {
|
"Clear_format": "Clear format",
|
||||||
"missing_h1": {
|
"Image_address_invalid": "Image address invalid",
|
||||||
"description": "V dokumentu není žádný h1",
|
|
||||||
"issue" : "Chybí h1"
|
|
||||||
},
|
|
||||||
"heading_end_with_colon": {
|
|
||||||
"description": "Koncová interpunkce v záhlaví by neměla být dvojtečka",
|
|
||||||
"issue": "Záhlaví končí dvojtečkou"
|
|
||||||
},
|
|
||||||
"heading_increase_irregular": {
|
|
||||||
"description": "Úrovně nadpisů by se měly zvyšovat vždy pouze o jednu úroveň",
|
|
||||||
"issue": "Problém s úrovní nadpisu"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shortcut_help": "Shortcut help",
|
"Shortcut_help": "Shortcut help",
|
||||||
|
"Link_address_required": "Link address required",
|
||||||
|
"Link_address_invalid": "Link address invalid",
|
||||||
|
"Link_title_required": "Link title required",
|
||||||
|
"Blank_title_not_allowed": "Blank title not allowed",
|
||||||
"userHelp": {
|
"userHelp": {
|
||||||
"title": "Klávesové zkratky",
|
"title": "Klávesové zkratky",
|
||||||
"userHelpData": [
|
"userHelpData": [
|
||||||
@@ -162,7 +153,8 @@
|
|||||||
"Insert_child_in_item": "Vložit podpoložku",
|
"Insert_child_in_item": "Vložit podpoložku",
|
||||||
"Increase_depth": "Zvýšit hloubku"
|
"Increase_depth": "Zvýšit hloubku"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Zkratky záhlaví",
|
"shortcutType": "Zkratky záhlaví",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Heading_1": "Záhlaví 1",
|
"Heading_1": "Záhlaví 1",
|
||||||
@@ -172,7 +164,8 @@
|
|||||||
"Heading_5": "Záhlaví 5",
|
"Heading_5": "Záhlaví 5",
|
||||||
"Heading_6": "Záhlaví 6"
|
"Heading_6": "Záhlaví 6"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Zkratky bloků kódu",
|
"shortcutType": "Zkratky bloků kódu",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_code_block": "Vytvořit blok kódu",
|
"Make_code_block": "Vytvořit blok kódu",
|
||||||
@@ -180,37 +173,43 @@
|
|||||||
"Escape_code_block": "Opustit blok kódu",
|
"Escape_code_block": "Opustit blok kódu",
|
||||||
"Insert_indent": "Vložit odrážku"
|
"Insert_indent": "Vložit odrážku"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Zkratky bloku citace",
|
"shortcutType": "Zkratky bloku citace",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_Block_quote": "Vytvořit blokovou citaci",
|
"Make_block_quote": "Make block quote",
|
||||||
"Escape_Block_quote": "Opustit blokovou citaci"
|
"Escape_block_quote": "Escape block quote"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Zkratky tabulky",
|
"shortcutType": "Zkratky tabulky",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Table_Row": "Vložit řádku tabulky",
|
"Insert_table_row": "Insert table tow",
|
||||||
"Escape_table": "Opustit tabulku"
|
"Escape_table": "Opustit tabulku"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Zkratky vzorečku",
|
"shortcutType": "Zkratky vzorečku",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Formula": "Insert Formula"
|
"Insert_formula": "Insert formula"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Řádkové zkratky",
|
"shortcutType": "Řádkové zkratky",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Bold": "Tučně",
|
"Bold": "Tučně",
|
||||||
"Italic": "Kurzíva",
|
"Italic": "Kurzíva",
|
||||||
"Italic_Bold": "Tučná kurzíva",
|
"Italic_bold": "Italic bold",
|
||||||
"Inline_code": "Řádkový kód"
|
"Inline_code": "Řádkový kód"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Uložit zkratky",
|
"shortcutType": "Uložit zkratky",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Save_file": "Uložit soubor"
|
"Save_file": "Uložit soubor"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Zkratky obrázku",
|
"shortcutType": "Zkratky obrázku",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Paste_screen_shot": "Vložit snímek obrazovky",
|
"Paste_screen_shot": "Vložit snímek obrazovky",
|
||||||
@@ -218,5 +217,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
}
|
}
|
||||||
|
@@ -1,126 +1,126 @@
|
|||||||
{
|
{
|
||||||
"bold": "Fett",
|
"Bold": "Fett",
|
||||||
"italic": "Kursiv",
|
"Italic": "Kursiv",
|
||||||
"inline_code": "Code",
|
"Inline_code": "Code",
|
||||||
"header_one": "Überschrift 1",
|
"Header_one": "Überschrift 1",
|
||||||
"header_two": "Überschrift 2",
|
"Header_two": "Überschrift 2",
|
||||||
"header_three": "Überschrift 3",
|
"Header_three": "Überschrift 3",
|
||||||
"header_four": "Überschrift 4",
|
"Header_four": "Überschrift 4",
|
||||||
"header_five": "Überschrift 5",
|
"Header_five": "Überschrift 5",
|
||||||
"header_six": "Überschrift 6",
|
"Header_six": "Überschrift 6",
|
||||||
"paragraph": "Absatz",
|
"Paragraph": "Absatz",
|
||||||
"quote": "Blockquote",
|
"Quote": "Blockquote",
|
||||||
"ordered_list": "Nummerierte Liste",
|
"Ordered_list": "Nummerierte Liste",
|
||||||
"unordered_list": "Ungeordnete Liste",
|
"Unordered_list": "Ungeordnete Liste",
|
||||||
"check_list_item": "Checkbox Liste",
|
"Check_list_item": "Checkbox Liste",
|
||||||
"insert_image": "Bild",
|
"Insert_image": "Bild",
|
||||||
"insert_formula": "Formel einfügen",
|
"Insert_formula": "Formel einfügen",
|
||||||
"formula": "Formel",
|
"Formula": "Formel",
|
||||||
"insert_file": "Datei",
|
"Insert_file": "Datei",
|
||||||
"code": "Inline-Code",
|
"Code": "Inline-Code",
|
||||||
"code_block": "Codeblock",
|
"Code_block": "Codeblock",
|
||||||
"insert_link": "Link",
|
"Insert_link": "Link",
|
||||||
"insert_table": "Tabelle",
|
"Insert_table": "Tabelle",
|
||||||
"save": "Speichern",
|
"Save": "Speichern",
|
||||||
"more": "Mehr",
|
"More": "Mehr",
|
||||||
"invalid_url": "Ungültige Adresse",
|
"Invalid_url": "Ungültige Adresse",
|
||||||
"link_address": "Link-URL",
|
"Link_address": "Link-URL",
|
||||||
"image_address": "Bild-URL",
|
"Image_address": "Bild-URL",
|
||||||
"submit": "Absenden",
|
"Submit": "Speichern",
|
||||||
"cancel": "Abbrechen",
|
"Cancel": "Abbrechen",
|
||||||
"switch_to_plain_text_editor": "Zum Plain Text Editor wechseln",
|
"Switch_to_plain_text_editor": "Zum Plain Text Editor wechseln",
|
||||||
"switch_to_rich_text_editor": "Zum Rich Text Editor wechseln",
|
"Switch_to_rich_text_editor": "Zum Rich Text Editor wechseln",
|
||||||
"switch_to_viewer": "Zur Markdown-Vorschau wechseln",
|
"Switch_to_viewer": "Zur Markdown-Vorschau wechseln",
|
||||||
"help": "Hilfe",
|
"Help": "Hilfe",
|
||||||
"remove_table": "Tabelle entfernen",
|
"Remove_table": "Tabelle entfernen",
|
||||||
"column": "Spalte",
|
"Column": "Spalte",
|
||||||
"row": "Zeile",
|
"Row": "Zeile",
|
||||||
"Insert_Row_Before": "Zeile darüber einfügen",
|
"Insert_row_before": "Insert row before",
|
||||||
"Insert_Row_After": "Zeile darunter einfügen",
|
"Insert_row_after": "Insert row after",
|
||||||
"Insert_Column_Before": "Spalte links einfügen",
|
"Insert_column_before": "Insert column before",
|
||||||
"Insert_Column_After": "Spalte rechts einfügen",
|
"Insert_column_after": "Insert column after",
|
||||||
"Remove_Row": "Zeile entfernen",
|
"Remove_row": "Remove row",
|
||||||
"Remove_Column": "Spalte entfernen",
|
"Remove_column": "Remove column",
|
||||||
"Insert_Row": "Zeile einfügen",
|
"Insert_row": "Insert row",
|
||||||
"Insert_Column": "Spalte einfügen",
|
"Insert_column": "Insert column",
|
||||||
"set_align": "Ausrichtung festlegen",
|
"Set_align": "Ausrichtung festlegen",
|
||||||
"left": "Links",
|
"Left": "Links",
|
||||||
"center": "Zentrieren",
|
"Center": "Zentrieren",
|
||||||
"right": "Rechts",
|
"Right": "Rechts",
|
||||||
"file_saved": "Die Datei wurde gespeichert.",
|
"File_saved": "Die Datei wurde gespeichert.",
|
||||||
"file_failed_to_save": "Die Datei konnte nicht gespeichert werden.",
|
"File_failed_to_save": "Die Datei konnte nicht gespeichert werden.",
|
||||||
"star": "Zu Favoriten hinzufügen",
|
"Star": "Zu Favoriten hinzufügen",
|
||||||
"unstar": "Aus Favoriten entfernen",
|
"Unstar": "Aus Favoriten entfernen",
|
||||||
"back_to_parent_directory":"Zurück zum übergeordneten Verzeichnis",
|
"Back_to_parent_directory": "Zurück zum übergeordneten Verzeichnis",
|
||||||
"edit": "Bearbeiten",
|
"Edit": "Bearbeiten",
|
||||||
"copy": "Kopieren",
|
"Copy": "Kopieren",
|
||||||
"copied": "Kopiert",
|
"Copied": "Kopiert",
|
||||||
"internal_link": "Internen Link anzeigen",
|
"Internal_link": "Internen Link anzeigen",
|
||||||
"copy_internal_link": "Der interne Link wurde in die Zwischenablage kopiert.",
|
"Copy_internal_link": "Der interne Link wurde in den Zwischenspeicher kopiert.",
|
||||||
"internal_link_desc": "Interne Links sind Verweise auf Dateien bzw. Ordner, die nur von Benutzer/innen mit mindestens Leserechten für die Dateien bzw. Ordner genutzt werden können. Interne Links eignen sich insbesondere für die interne Kommunikation in Ticket-/CRM-Systemen sowie E-Mails und Chats.",
|
"Internal_link_desc": "Interne Links sind Verweise auf Dateien bzw. Ordner, die nur von Benutzer/innen mit mindestens Leserechten für die Dateien bzw. Ordner genutzt werden können. Interne Links eignen sich insbesondere für die interne Kommunikation in Ticket-/CRM-Systemen sowie E-Mails und Chats.",
|
||||||
"share": "Freigeben",
|
"Share": "Freigeben",
|
||||||
"share_link": "Download-Link",
|
"Share_link": "Download-Link",
|
||||||
"generate": "Erstellen",
|
"Generate": "Erstellen",
|
||||||
"add_password_protection": "Passwort hinzufügen",
|
"Add_password_protection": "Passwort hinzufügen",
|
||||||
"password": "Passwort",
|
"Password": "Passwort",
|
||||||
"at_least_8_characters": "mindestens 8 Zeichen",
|
"At_least_8_characters": "mindestens 8 Zeichen",
|
||||||
"password_again": "Passwort erneut eingeben",
|
"Password_again": "Passwort erneut eingeben",
|
||||||
"add_auto_expiration": "Befristung hinzufügen",
|
"Add_auto_expiration": "Befristung hinzufügen",
|
||||||
"days": "Tage",
|
"Days": "Tage",
|
||||||
"please_enter_password": "Bitte geben Sie ein Passwort ein",
|
"Please_enter_password": "Bitte geben Sie ein Passwort ein",
|
||||||
"greater_than_or_equal_to": "Größer oder gleich",
|
"Greater_than_or_equal_to": "Größer oder gleich",
|
||||||
"less_than_or_equal_to": "Weniger oder gleich",
|
"Less_than_or_equal_to": "Weniger oder gleich",
|
||||||
"set_permission": "Rechte festlegen",
|
"Set_permission": "Berechtigung festlegen",
|
||||||
"preview_and_download": "Vorschau und Herunterladen",
|
"Preview_and_download": "Vorschau und Herunterladen",
|
||||||
"preview_only": "Nur Vorschau erlaubt",
|
"Preview_only": "Nur Vorschau erlaubt",
|
||||||
"please_enter_valid_days": "Bitte geben Sie eine gültige Anzahl von Tagen ein",
|
"Please_enter_valid_days": "Bitte geben Sie eine gültige Anzahl von Tagen ein",
|
||||||
"please_enter_a_non-negative_integer": "Bitte geben Sie eine Zahl größer oder gleich Null ein",
|
"Please_enter_a_non-negative_integer": "Bitte geben Sie eine Zahl größer oder gleich Null ein",
|
||||||
"please_enter_days": "Bitte geben Sie Tage ein",
|
"Please_enter_days": "Bitte geben Sie Tage ein",
|
||||||
"password_is_too_short": "Passwort ist zu kurz",
|
"Password_is_too_short": "Das Passwort ist zu kurz",
|
||||||
"passwords_do_not_match": "Passwörter stimmen nicht überein",
|
"Passwords_do_not_match": "Passwörter stimmen nicht überein",
|
||||||
"return_to_wiki_page": "Zurück zur Wiki-Seite",
|
"Return_to_wiki_page": "Zurück zur Wiki-Seite",
|
||||||
"insert_network_image": "Bild per URL einfügen",
|
"Insert_network_image": "Bild per URL einfügen",
|
||||||
"upload_local_image": "Bild hochladen und einfügen",
|
"Upload_local_image": "Bild hochladen und einfügen",
|
||||||
"add_link": "Link hinzufügen",
|
"Add_link": "Link hinzufügen",
|
||||||
"file_history": "Dateiversionen",
|
"File_history": "Dateiversionen",
|
||||||
"history_version": "Versionen",
|
"History_version": "Versionen",
|
||||||
"back_to_viewer": "Zurück zur Vorschau",
|
"Back_to_viewer": "Zurück zur Vorschau",
|
||||||
"link_title": "Linktext",
|
"Link_title": "Linktext",
|
||||||
"local_draft": "Lokaler Entwurf",
|
"Local_draft": "Lokaler Entwurf",
|
||||||
"use_draft": "Entwurf verwenden",
|
"Use_draft": "Entwurf verwenden",
|
||||||
"delete_draft": "Entwurf löschen",
|
"Delete_draft": "Entwurf löschen",
|
||||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "Es gibt einen ungespeicherten Entwurf. Möchten Sie ihn verwenden?",
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "Es gibt einen ungespeicherten Entwurf. Möchten Sie ihn verwenden?",
|
||||||
"local_draft_saved": "Lokaler Entwurf gespeichert",
|
"Local_draft_saved": "Lokaler Entwurf gespeichert",
|
||||||
"new_draft": "Neuer Entwurf",
|
"New_draft": "Neuer Entwurf",
|
||||||
"view_draft": "Entwurf anzeigen",
|
"View_draft": "Entwurf anzeigen",
|
||||||
"publish": "Veröffentlichen",
|
"Publish": "Veröffentlichen",
|
||||||
"this_file_has_a_draft": "Zu dieser Datei gibt es einen Entwurf.",
|
"This_file_has_a_draft": "Zu dieser Datei gibt es einen Entwurf.",
|
||||||
"delete": "Löschen",
|
"Delete": "Löschen",
|
||||||
"comments": "Kommentare",
|
"Comments": "Kommentare",
|
||||||
"add_a_comment": "Kommentar einfügen",
|
"Add_a_comment": "Kommentar einfügen",
|
||||||
"no_comment_yet": "Keine Kommentare vorhanden",
|
"No_comment_yet": "Keine Kommentare vorhanden",
|
||||||
"Mark_as_Resolved": "Als erledigt markieren",
|
"Mark_as_Resolved": "Als erledigt markieren",
|
||||||
"ask_for_review": "Um ein Review bitten",
|
"Ask_for_review": "Um ein Review bitten",
|
||||||
"review_already_exists": "Es gibt bereits ein Review.",
|
"Review_already_exists": "Es gibt bereits ein Review.",
|
||||||
"view_review": "Review anzeigen",
|
"View_review": "Review anzeigen",
|
||||||
"there_is_an_associated_review_with_this_file": "Es gibt ein Review zu dieser Datei.",
|
"There_is_an_associated_review_with_this_file": "Es gibt ein Review zu dieser Datei.",
|
||||||
"start_review": "Review schreiben",
|
"Start_review": "Review schreiben",
|
||||||
"this_file_is_in_draft_stage": "Die Datei hat den Status Entwurf",
|
"This_file_is_in_draft_stage": "Die Datei hat den Status Entwurf",
|
||||||
"this_file_is_in_review_stage": "Die Datei hat den Status Review.",
|
"This_file_is_in_review_stage": "Die Datei hat den Status Review.",
|
||||||
"this_file_has_been_updated": "Die Datei wurde aktualisiert.",
|
"This_file_has_been_updated": "Die Datei wurde aktualisiert.",
|
||||||
"refresh": "Aktualisieren",
|
"Refresh": "Aktualisieren",
|
||||||
"related_files": "Zugehörige Dateien",
|
"Related_files": "Zugehörige Dateien",
|
||||||
"related_file": "Zugehörige Datei",
|
"Related_file": "Zugehörige Datei",
|
||||||
"no_tags": "Keine Tags",
|
"No_tags": "Keine Tags",
|
||||||
"Date": "Datum",
|
"Date": "Datum",
|
||||||
"Participants": "Teilnehmer",
|
"Participants": "Teilnehmer",
|
||||||
"Meeting_note": "Besprechungsnotiz",
|
"Meeting_note": "Besprechungsnotiz",
|
||||||
"Chooser_document_type": "Auswahl Dokumenttyp",
|
"Chooser_document_type": "Auswahl Dokumenttyp",
|
||||||
"Empty": "Leer",
|
"Empty": "Leer",
|
||||||
"no_related_files": "Keine zugehörigen Dateien",
|
"No_related_files": "Keine zugehörigen Dateien",
|
||||||
"no_out_line": "Keine Gliederung",
|
"No_out_line": "Keine Gliederung",
|
||||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Beim Bearbeiten von Dateien in diesem Browser können leichte Probleme bei der Anzeige auftreten.",
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Beim Bearbeiten von Dateien in diesem Browser können leichte Probleme bei der Anzeige auftreten.",
|
||||||
"no_document_improvement_suggestion": "Keine Vorschläge zur Verbesserung des Dokuments",
|
"No_document_improvement_suggestion": "Keine Vorschläge zur Verbesserung des Dokuments",
|
||||||
"Hide_side_panel": "Seitenleiste verbergen",
|
"Hide_side_panel": "Seitenleiste verbergen",
|
||||||
"Show_side_panel": "Seitenleiste anzeigen",
|
"Show_side_panel": "Seitenleiste anzeigen",
|
||||||
"Show_resolved_comments": "Erledigte Kommentare anzeigen",
|
"Show_resolved_comments": "Erledigte Kommentare anzeigen",
|
||||||
@@ -131,25 +131,16 @@
|
|||||||
"Insert_library_image": "Bild aus Bibliothek einfügen",
|
"Insert_library_image": "Bild aus Bibliothek einfügen",
|
||||||
"Size": "Größe",
|
"Size": "Größe",
|
||||||
"Location": "Ort",
|
"Location": "Ort",
|
||||||
"Last_Update": "Letzte Änderung",
|
"Last_update": "Last update",
|
||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Related_Files": "Zugehörige Dateien",
|
|
||||||
"Add_participants": "Teilnehmer hinzufügen",
|
"Add_participants": "Teilnehmer hinzufügen",
|
||||||
"markdownLint": {
|
"Clear_format": "Clear format",
|
||||||
"missing_h1": {
|
"Image_address_invalid": "Image address invalid",
|
||||||
"description": "Es gibt keine Hauptüberschrift (h1) in dem Text",
|
|
||||||
"issue" : "Hauptüberschrift (h1) fehlt"
|
|
||||||
},
|
|
||||||
"heading_end_with_colon": {
|
|
||||||
"description": "Überschriften dürfen nicht mit einem Doppelpunkt enden.",
|
|
||||||
"issue": "Überschrift endet mit einem Doppelpunkt"
|
|
||||||
},
|
|
||||||
"heading_increase_irregular": {
|
|
||||||
"description": "Überschriften sollten in aufeinander folgenden Stufen angelegt werden",
|
|
||||||
"issue": "Stufe der Überschrift überprüfen"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shortcut_help": "Hilfe Tastenkombinationen",
|
"Shortcut_help": "Hilfe Tastenkombinationen",
|
||||||
|
"Link_address_required": "Link address required",
|
||||||
|
"Link_address_invalid": "Link address invalid",
|
||||||
|
"Link_title_required": "Link title required",
|
||||||
|
"Blank_title_not_allowed": "Blank title not allowed",
|
||||||
"userHelp": {
|
"userHelp": {
|
||||||
"title": "Tastenkombinationen",
|
"title": "Tastenkombinationen",
|
||||||
"userHelpData": [
|
"userHelpData": [
|
||||||
@@ -162,7 +153,8 @@
|
|||||||
"Insert_child_in_item": "Textzeile einfügen",
|
"Insert_child_in_item": "Textzeile einfügen",
|
||||||
"Increase_depth": "Einzug erhöhen"
|
"Increase_depth": "Einzug erhöhen"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Überschriften",
|
"shortcutType": "Überschriften",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Heading_1": "Überschrift 1",
|
"Heading_1": "Überschrift 1",
|
||||||
@@ -172,7 +164,8 @@
|
|||||||
"Heading_5": "Überschrift 5",
|
"Heading_5": "Überschrift 5",
|
||||||
"Heading_6": "Überschrift 6"
|
"Heading_6": "Überschrift 6"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Codeblock",
|
"shortcutType": "Codeblock",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_code_block": "Codeblock anlegen",
|
"Make_code_block": "Codeblock anlegen",
|
||||||
@@ -180,37 +173,43 @@
|
|||||||
"Escape_code_block": "Codeblock beenden",
|
"Escape_code_block": "Codeblock beenden",
|
||||||
"Insert_indent": "Einzug erhöhen"
|
"Insert_indent": "Einzug erhöhen"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Blockquote",
|
"shortcutType": "Blockquote",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_Block_quote": "Blockquote einfügen",
|
"Make_block_quote": "Make block quote",
|
||||||
"Escape_Block_quote": "Blockquote beenden"
|
"Escape_block_quote": "Escape block quote"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Tabellen",
|
"shortcutType": "Tabellen",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Table_Row": "Tabellenzeile einfügen",
|
"Insert_table_row": "Insert table tow",
|
||||||
"Escape_table": "Tabelle beenden"
|
"Escape_table": "Tabelle beenden"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Formeln",
|
"shortcutType": "Formeln",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Formula": "Formel einfügen"
|
"Insert_formula": "Insert formula"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Textformatierung",
|
"shortcutType": "Textformatierung",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Bold": "Fett",
|
"Bold": "Fett",
|
||||||
"Italic": "Kursiv",
|
"Italic": "Kursiv",
|
||||||
"Italic_Bold": "Kursiv fett",
|
"Italic_bold": "Italic bold",
|
||||||
"Inline_code": "Inline-Code"
|
"Inline_code": "Inline-Code"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Speichern",
|
"shortcutType": "Speichern",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Save_file": "Datei speichern"
|
"Save_file": "Datei speichern"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Bilder",
|
"shortcutType": "Bilder",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Paste_screen_shot": "Bild aus Zwischenablage einfügen",
|
"Paste_screen_shot": "Bild aus Zwischenablage einfügen",
|
||||||
@@ -218,5 +217,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
}
|
}
|
||||||
|
@@ -1,126 +1,126 @@
|
|||||||
{
|
{
|
||||||
"bold": "Bold",
|
"Bold": "Bold",
|
||||||
"italic": "Italic",
|
"Italic": "Italic",
|
||||||
"inline_code": "Code",
|
"Inline_code": "Code",
|
||||||
"header_one": "Heading 1",
|
"Header_one": "Heading 1",
|
||||||
"header_two": "Heading 2",
|
"Header_two": "Heading 2",
|
||||||
"header_three": "Heading 3",
|
"Header_three": "Heading 3",
|
||||||
"header_four": "Heading 4",
|
"Header_four": "Heading 4",
|
||||||
"header_five": "Heading 5",
|
"Header_five": "Heading 5",
|
||||||
"header_six": "Heading 6",
|
"Header_six": "Heading 6",
|
||||||
"paragraph": "Paragraph",
|
"Paragraph": "Paragraph",
|
||||||
"quote": "Quote",
|
"Quote": "Quote",
|
||||||
"ordered_list": "Ordered List",
|
"Ordered_list": "Ordered List",
|
||||||
"unordered_list": "Unordered List",
|
"Unordered_list": "Unordered List",
|
||||||
"check_list_item": "Check List Item",
|
"Check_list_item": "Check List Item",
|
||||||
"insert_image": "Insert Image",
|
"Insert_image": "Insert Image",
|
||||||
"insert_formula": "Insert Formula",
|
"Insert_formula": "Insert Formula",
|
||||||
"formula": "Formula",
|
"Formula": "Formula",
|
||||||
"insert_file": "Insert File",
|
"Insert_file": "Insert File",
|
||||||
"code": "Inline Code",
|
"Code": "Inline Code",
|
||||||
"code_block": "Code Block",
|
"Code_block": "Code Block",
|
||||||
"insert_link": "Insert Link",
|
"Insert_link": "Insert Link",
|
||||||
"insert_table": "Insert Table",
|
"Insert_table": "Insert Table",
|
||||||
"save": "Save",
|
"Save": "Save",
|
||||||
"more": "More",
|
"More": "More",
|
||||||
"invalid_url": "Invalid URL",
|
"Invalid_url": "Invalid URL",
|
||||||
"link_address": "Link address",
|
"Link_address": "Link address",
|
||||||
"image_address": "Image address",
|
"Image_address": "Image address",
|
||||||
"submit": "Submit",
|
"Submit": "Submit",
|
||||||
"cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
"switch_to_plain_text_editor": "Switch to Plain Text Editor",
|
"Switch_to_plain_text_editor": "Switch to Plain Text Editor",
|
||||||
"switch_to_rich_text_editor": "Switch to Rich Text Editor",
|
"Switch_to_rich_text_editor": "Switch to Rich Text Editor",
|
||||||
"switch_to_viewer": "Switch to Markdown Viewer",
|
"Switch_to_viewer": "Switch to Markdown Viewer",
|
||||||
"help": "Help",
|
"Help": "Help",
|
||||||
"remove_table": "Remove Table",
|
"Remove_table": "Remove Table",
|
||||||
"column": "Column",
|
"Column": "Column",
|
||||||
"row": "Row",
|
"Row": "Row",
|
||||||
"Insert_Row_Before": "Insert Row Before",
|
"Insert_row_before": "Insert row before",
|
||||||
"Insert_Row_After": "Insert Row After",
|
"Insert_row_after": "Insert row after",
|
||||||
"Insert_Column_Before": "Insert Column Before",
|
"Insert_column_before": "Insert column before",
|
||||||
"Insert_Column_After": "Insert Column After",
|
"Insert_column_after": "Insert column after",
|
||||||
"Remove_Row": "Remove Row",
|
"Remove_row": "Remove row",
|
||||||
"Remove_Column": "Remove Column",
|
"Remove_column": "Remove column",
|
||||||
"Insert_Row": "Insert Row",
|
"Insert_row": "Insert row",
|
||||||
"Insert_Column": "Insert Column",
|
"Insert_column": "Insert column",
|
||||||
"set_align": "Set align",
|
"Set_align": "Set align",
|
||||||
"left": "Left",
|
"Left": "Left",
|
||||||
"center": "Center",
|
"Center": "Center",
|
||||||
"right": "Right",
|
"Right": "Right",
|
||||||
"file_saved": "File saved.",
|
"File_saved": "File saved.",
|
||||||
"file_failed_to_save": "File failed to save.",
|
"File_failed_to_save": "File failed to save.",
|
||||||
"star": "Add star",
|
"Star": "Add star",
|
||||||
"unstar": "Remove star",
|
"Unstar": "Remove star",
|
||||||
"back_to_parent_directory":"Back to parent directory",
|
"Back_to_parent_directory": "Back to parent directory",
|
||||||
"edit": "Edit",
|
"Edit": "Edit",
|
||||||
"copy": "Copy",
|
"Copy": "Copy",
|
||||||
"copied": "Copied",
|
"Copied": "Copied",
|
||||||
"internal_link": "Internal Link",
|
"Internal_link": "Internal Link",
|
||||||
"copy_internal_link": "Internal link has been copied to clipboard",
|
"Copy_internal_link": "Internal link has been copied to clipboard",
|
||||||
"internal_link_desc": "An internal link is a link to a file or folder that can be accessed by users with read permission to the file or folder.",
|
"Internal_link_desc": "An internal link is a link to a file or folder that can be accessed by users with read permission to the file or folder.",
|
||||||
"share": "Share",
|
"Share": "Share",
|
||||||
"share_link": "Share Link",
|
"Share_link": "Share Link",
|
||||||
"generate": "Generate",
|
"Generate": "Generate",
|
||||||
"add_password_protection": "Add password protection",
|
"Add_password_protection": "Add password protection",
|
||||||
"password": "Password",
|
"Password": "Password",
|
||||||
"at_least_8_characters": "at least 8 characters",
|
"At_least_8_characters": "at least 8 characters",
|
||||||
"password_again": "Password again",
|
"Password_again": "Password again",
|
||||||
"add_auto_expiration": "Add auto expiration",
|
"Add_auto_expiration": "Add auto expiration",
|
||||||
"days": "days",
|
"Days": "days",
|
||||||
"please_enter_password": "Please enter password",
|
"Please_enter_password": "Please enter password",
|
||||||
"greater_than_or_equal_to": "Greater than or equal to",
|
"Greater_than_or_equal_to": "Greater than or equal to",
|
||||||
"less_than_or_equal_to": "Less than or equal to",
|
"Less_than_or_equal_to": "Less than or equal to",
|
||||||
"set_permission": "Set permission",
|
"Set_permission": "Set permission",
|
||||||
"preview_and_download": "Preview and download",
|
"Preview_and_download": "Preview and download",
|
||||||
"preview_only": "Preview only",
|
"Preview_only": "Preview only",
|
||||||
"please_enter_valid_days": "Please enter valid days",
|
"Please_enter_valid_days": "Please enter valid days",
|
||||||
"please_enter_a_non-negative_integer": "Please enter a non-negative integer",
|
"Please_enter_a_non-negative_integer": "Please enter a non-negative integer",
|
||||||
"please_enter_days": "Please enter days",
|
"Please_enter_days": "Please enter days",
|
||||||
"password_is_too_short": "Password is too short",
|
"Password_is_too_short": "Password is too short",
|
||||||
"passwords_do_not_match": "Passwords do not match",
|
"Passwords_do_not_match": "Passwords do not match",
|
||||||
"return_to_wiki_page": "Return to Wiki Page",
|
"Return_to_wiki_page": "Return to Wiki Page",
|
||||||
"insert_network_image": "Insert network image",
|
"Insert_network_image": "Insert network image",
|
||||||
"upload_local_image": "Upload local image",
|
"Upload_local_image": "Upload local image",
|
||||||
"add_link": "Add link",
|
"Add_link": "Add link",
|
||||||
"file_history": "File History",
|
"File_history": "File History",
|
||||||
"history_version": "History Versions",
|
"History_version": "History Versions",
|
||||||
"back_to_viewer": "Back To Viewer",
|
"Back_to_viewer": "Back To Viewer",
|
||||||
"link_title": "Link title",
|
"Link_title": "Link title",
|
||||||
"local_draft": "Local draft",
|
"Local_draft": "Local draft",
|
||||||
"use_draft": "Use draft",
|
"Use_draft": "Use draft",
|
||||||
"delete_draft": "Delete draft",
|
"Delete_draft": "Delete draft",
|
||||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "You have an unsaved draft. Do you like to use it?",
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "You have an unsaved draft. Do you like to use it?",
|
||||||
"local_draft_saved": "Local draft saved",
|
"Local_draft_saved": "Local draft saved",
|
||||||
"new_draft": "New Draft",
|
"New_draft": "New Draft",
|
||||||
"view_draft": "View Draft",
|
"View_draft": "View Draft",
|
||||||
"publish": "Publish",
|
"Publish": "Publish",
|
||||||
"this_file_has_a_draft": "This file has a draft.",
|
"This_file_has_a_draft": "This file has a draft.",
|
||||||
"delete": "Delete",
|
"Delete": "Delete",
|
||||||
"comments": "Comments",
|
"Comments": "Comments",
|
||||||
"add_a_comment": "Add a comment...",
|
"Add_a_comment": "Add a comment...",
|
||||||
"no_comment_yet": "No comment yet.",
|
"No_comment_yet": "No comment yet.",
|
||||||
"Mark_as_Resolved": "Mark as Resolved",
|
"Mark_as_Resolved": "Mark as Resolved",
|
||||||
"ask_for_review": "Ask for review",
|
"Ask_for_review": "Ask for review",
|
||||||
"review_already_exists": "Review already exists",
|
"Review_already_exists": "Review already exists",
|
||||||
"view_review": "View review",
|
"View_review": "View review",
|
||||||
"there_is_an_associated_review_with_this_file": "There is an associated review with this file.",
|
"There_is_an_associated_review_with_this_file": "There is an associated review with this file.",
|
||||||
"start_review": "Start Review",
|
"Start_review": "Start Review",
|
||||||
"this_file_is_in_draft_stage": "This file is in draft stage.",
|
"This_file_is_in_draft_stage": "This file is in draft stage.",
|
||||||
"this_file_is_in_review_stage": "This file is in review stage.",
|
"This_file_is_in_review_stage": "This file is in review stage.",
|
||||||
"this_file_has_been_updated": "This file has been updated.",
|
"This_file_has_been_updated": "This file has been updated.",
|
||||||
"refresh": "Refresh",
|
"Refresh": "Refresh",
|
||||||
"related_files": "related files",
|
"Related_files": "related files",
|
||||||
"related_file": "related file",
|
"Related_file": "related file",
|
||||||
"no_tags": "No tags",
|
"No_tags": "No tags",
|
||||||
"Date": "Date",
|
"Date": "Date",
|
||||||
"Participants": "Participants",
|
"Participants": "Participants",
|
||||||
"Meeting_note": "Meeting note",
|
"Meeting_note": "Meeting note",
|
||||||
"Chooser_document_type": "Chooser document type",
|
"Chooser_document_type": "Chooser document type",
|
||||||
"Empty": "Empty",
|
"Empty": "Empty",
|
||||||
"no_related_files": "No related files",
|
"No_related_files": "No related files",
|
||||||
"no_out_line": "No outline",
|
"No_out_line": "No outline",
|
||||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Editing files in this browser can lead to slight display problems.",
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Editing files in this browser can lead to slight display problems.",
|
||||||
"no_document_improvement_suggestion": "No document improvement suggestion",
|
"No_document_improvement_suggestion": "No document improvement suggestion",
|
||||||
"Hide_side_panel": "Hide side panel",
|
"Hide_side_panel": "Hide side panel",
|
||||||
"Show_side_panel": "Show side panel",
|
"Show_side_panel": "Show side panel",
|
||||||
"Show_resolved_comments": "Show resolved comments",
|
"Show_resolved_comments": "Show resolved comments",
|
||||||
@@ -131,25 +131,16 @@
|
|||||||
"Insert_library_image": "Insert library image",
|
"Insert_library_image": "Insert library image",
|
||||||
"Size": "Size",
|
"Size": "Size",
|
||||||
"Location": "Location",
|
"Location": "Location",
|
||||||
"Last_Update": "Last Update",
|
"Last_update": "Last update",
|
||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Related_Files": "Related Files",
|
|
||||||
"Add_participants": "Add participants",
|
"Add_participants": "Add participants",
|
||||||
"markdownLint": {
|
"Clear_format": "Clear format",
|
||||||
"missing_h1": {
|
"Image_address_invalid": "Image address invalid",
|
||||||
"description": "There is no h1 in the document",
|
|
||||||
"issue" : "Missing h1"
|
|
||||||
},
|
|
||||||
"heading_end_with_colon": {
|
|
||||||
"description": "Trailing punctuation in heading should not be a colon",
|
|
||||||
"issue": "Heading ends width colon"
|
|
||||||
},
|
|
||||||
"heading_increase_irregular": {
|
|
||||||
"description": "Heading levels should only increment by one level at a time",
|
|
||||||
"issue": "Heading level issue"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shortcut_help": "Shortcut help",
|
"Shortcut_help": "Shortcut help",
|
||||||
|
"Link_address_required": "Link address required",
|
||||||
|
"Link_address_invalid": "Link address invalid",
|
||||||
|
"Link_title_required": "Link title required",
|
||||||
|
"Blank_title_not_allowed": "Blank title not allowed",
|
||||||
"userHelp": {
|
"userHelp": {
|
||||||
"title": "Keyboard shortcuts",
|
"title": "Keyboard shortcuts",
|
||||||
"userHelpData": [
|
"userHelpData": [
|
||||||
@@ -162,7 +153,8 @@
|
|||||||
"Insert_child_in_item": "Insert child in item",
|
"Insert_child_in_item": "Insert child in item",
|
||||||
"Increase_depth": "Increase depth"
|
"Increase_depth": "Increase depth"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Head shortcuts",
|
"shortcutType": "Head shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Heading_1": "Heading 1",
|
"Heading_1": "Heading 1",
|
||||||
@@ -172,7 +164,8 @@
|
|||||||
"Heading_5": "Heading 5",
|
"Heading_5": "Heading 5",
|
||||||
"Heading_6": "Heading 6"
|
"Heading_6": "Heading 6"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Code block shortcuts",
|
"shortcutType": "Code block shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_code_block": "Make code block",
|
"Make_code_block": "Make code block",
|
||||||
@@ -180,37 +173,43 @@
|
|||||||
"Escape_code_block": "Escape code block",
|
"Escape_code_block": "Escape code block",
|
||||||
"Insert_indent": "Insert indent"
|
"Insert_indent": "Insert indent"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Block quote shortcuts",
|
"shortcutType": "Block quote shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_Block_quote": "Make Block quote",
|
"Make_block_quote": "Make block quote",
|
||||||
"Escape_Block_quote": "Escape Block quote"
|
"Escape_block_quote": "Escape block quote"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Table shortcuts",
|
"shortcutType": "Table shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Table_Row": "Insert Table Row",
|
"Insert_table_row": "Insert table tow",
|
||||||
"Escape_table": "Escape table"
|
"Escape_table": "Escape table"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Formula shortcuts",
|
"shortcutType": "Formula shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Formula": "Insert Formula"
|
"Insert_formula": "Insert formula"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Inline shortcuts",
|
"shortcutType": "Inline shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Bold": "Bold",
|
"Bold": "Bold",
|
||||||
"Italic": "Italic",
|
"Italic": "Italic",
|
||||||
"Italic_Bold": "Italic Bold",
|
"Italic_bold": "Italic bold",
|
||||||
"Inline_code": "Inline code"
|
"Inline_code": "Inline code"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Save shortcuts",
|
"shortcutType": "Save shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Save_file": "Save file"
|
"Save_file": "Save file"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Image shortcuts",
|
"shortcutType": "Image shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Paste_screen_shot": "Paste screen shot",
|
"Paste_screen_shot": "Paste screen shot",
|
||||||
@@ -218,5 +217,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
}
|
}
|
||||||
|
@@ -1,126 +1,126 @@
|
|||||||
{
|
{
|
||||||
"bold": "Negrita",
|
"Bold": "Negrita",
|
||||||
"italic": "Itálica",
|
"Italic": "Itálica",
|
||||||
"inline_code": "Código",
|
"Inline_code": "Código",
|
||||||
"header_one": "Encabezado 1",
|
"Header_one": "Encabezado 1",
|
||||||
"header_two": "Encabezado 2",
|
"Header_two": "Encabezado 2",
|
||||||
"header_three": "Encabezado 3",
|
"Header_three": "Encabezado 3",
|
||||||
"header_four": "Encabezado 4",
|
"Header_four": "Encabezado 4",
|
||||||
"header_five": "Encabezado 5",
|
"Header_five": "Encabezado 5",
|
||||||
"header_six": "Encabezado 6",
|
"Header_six": "Encabezado 6",
|
||||||
"paragraph": "Párrafo",
|
"Paragraph": "Párrafo",
|
||||||
"quote": "Cita",
|
"Quote": "Cita",
|
||||||
"ordered_list": "Lista Ordenada",
|
"Ordered_list": "Lista Ordenada",
|
||||||
"unordered_list": "Lista Desordenada",
|
"Unordered_list": "Lista Desordenada",
|
||||||
"check_list_item": "Check List Item",
|
"Check_list_item": "Check List Item",
|
||||||
"insert_image": "Insertar Imagen",
|
"Insert_image": "Insertar Imagen",
|
||||||
"insert_formula": "Insertar Fórmula",
|
"Insert_formula": "Insertar Fórmula",
|
||||||
"formula": "Fórmula",
|
"Formula": "Fórmula",
|
||||||
"insert_file": "Insertar Archivo",
|
"Insert_file": "Insertar Archivo",
|
||||||
"code": "Inline Code",
|
"Code": "Inline Code",
|
||||||
"code_block": "Bloque de Código",
|
"Code_block": "Bloque de Código",
|
||||||
"insert_link": "Insertar Enlace",
|
"Insert_link": "Insertar Enlace",
|
||||||
"insert_table": "Insertar Tabla",
|
"Insert_table": "Insertar Tabla",
|
||||||
"save": "Guardar",
|
"Save": "Guardar",
|
||||||
"more": "Más",
|
"More": "Más",
|
||||||
"invalid_url": "URL Inválida",
|
"Invalid_url": "URL Inválida",
|
||||||
"link_address": "Dirección del enlace",
|
"Link_address": "Dirección del enlace",
|
||||||
"image_address": "Dirección de la imagen",
|
"Image_address": "Dirección de la imagen",
|
||||||
"submit": "Enviar",
|
"Submit": "Enviar",
|
||||||
"cancel": "Cancelar",
|
"Cancel": "Cancelar",
|
||||||
"switch_to_plain_text_editor": "Cambiar a editor de texto sin formato",
|
"Switch_to_plain_text_editor": "Cambiar a editor de texto sin formato",
|
||||||
"switch_to_rich_text_editor": "Cambiar a editor de texto enriquecido",
|
"Switch_to_rich_text_editor": "Cambiar a editor de texto enriquecido",
|
||||||
"switch_to_viewer": "Cambiar a visualizador Markdown",
|
"Switch_to_viewer": "Cambiar a visualizador Markdown",
|
||||||
"help": "Ayuda",
|
"Help": "Ayuda",
|
||||||
"remove_table": "Eliminar tabla",
|
"Remove_table": "Eliminar tabla",
|
||||||
"column": "Columna",
|
"Column": "Columna",
|
||||||
"row": "Fila",
|
"Row": "Fila",
|
||||||
"Insert_Row_Before": "Insertar Línea Antes",
|
"Insert_row_before": "Insert row before",
|
||||||
"Insert_Row_After": "Insertar Línea Después",
|
"Insert_row_after": "Insert row after",
|
||||||
"Insert_Column_Before": "Insertar Columna Antes",
|
"Insert_column_before": "Insert column before",
|
||||||
"Insert_Column_After": "Insertar Columna Después",
|
"Insert_column_after": "Insert column after",
|
||||||
"Remove_Row": "Eliminar Fila",
|
"Remove_row": "Remove row",
|
||||||
"Remove_Column": "Eliminar Columna",
|
"Remove_column": "Remove column",
|
||||||
"Insert_Row": "Insertar Fila",
|
"Insert_row": "Insert row",
|
||||||
"Insert_Column": "Insertar Columna",
|
"Insert_column": "Insert column",
|
||||||
"set_align": "Establecer alineación",
|
"Set_align": "Establecer alineación",
|
||||||
"left": "Izquierda",
|
"Left": "Izquierda",
|
||||||
"center": "Centrar",
|
"Center": "Centrar",
|
||||||
"right": "derecha",
|
"Right": "derecha",
|
||||||
"file_saved": "Archivo guardado",
|
"File_saved": "Archivo guardado",
|
||||||
"file_failed_to_save": "Fallo al guardar archivo",
|
"File_failed_to_save": "Fallo al guardar archivo",
|
||||||
"star": "Add star",
|
"Star": "Add star",
|
||||||
"unstar": "Remove star",
|
"Unstar": "Remove star",
|
||||||
"back_to_parent_directory":"Volver a la carpeta superior",
|
"Back_to_parent_directory": "Volver a la carpeta superior",
|
||||||
"edit": "Editar",
|
"Edit": "Editar",
|
||||||
"copy": "Copiar",
|
"Copy": "Copiar",
|
||||||
"copied": "Copiado",
|
"Copied": "Copiado",
|
||||||
"internal_link": "Enlace interno",
|
"Internal_link": "Enlace interno",
|
||||||
"copy_internal_link": "El enlace interno ha sido copiado al portapapeles",
|
"Copy_internal_link": "El enlace interno ha sido copiado al portapapeles",
|
||||||
"internal_link_desc": "Un enlace interno es un enlace a un archivo o carpeta que puede ser accedido por usuarios con permiso de lectura al archivo o carpeta. ",
|
"Internal_link_desc": "Un enlace interno es un enlace a un archivo o carpeta que puede ser accedido por usuarios con permiso de lectura al archivo o carpeta. ",
|
||||||
"share": "Compartir",
|
"Share": "Compartir",
|
||||||
"share_link": "Compartir enlace",
|
"Share_link": "Compartir enlace",
|
||||||
"generate": "Generar",
|
"Generate": "Generar",
|
||||||
"add_password_protection": "Agregar protección por contraseña",
|
"Add_password_protection": "Agregar protección por contraseña",
|
||||||
"password": "Contraseña ",
|
"Password": "Contraseña ",
|
||||||
"at_least_8_characters": "al menos 8 caracteres",
|
"At_least_8_characters": "al menos 8 caracteres",
|
||||||
"password_again": "Repetir contraseña",
|
"Password_again": "Repetir contraseña",
|
||||||
"add_auto_expiration": "Agregar vencimiento automático",
|
"Add_auto_expiration": "Agregar vencimiento automático",
|
||||||
"days": "días",
|
"Days": "días",
|
||||||
"please_enter_password": "Ingresa una contraseña",
|
"Please_enter_password": "Ingresa una contraseña",
|
||||||
"greater_than_or_equal_to": "Mayor o igual que",
|
"Greater_than_or_equal_to": "Mayor o igual que",
|
||||||
"less_than_or_equal_to": "Menor o igual que",
|
"Less_than_or_equal_to": "Menor o igual que",
|
||||||
"set_permission": "Establecer permiso",
|
"Set_permission": "Establecer permiso",
|
||||||
"preview_and_download": "Vista previa y descargar",
|
"Preview_and_download": "Vista previa y descargar",
|
||||||
"preview_only": "Vista previa solamente",
|
"Preview_only": "Vista previa solamente",
|
||||||
"please_enter_valid_days": "Ingresa cantidad válida de días",
|
"Please_enter_valid_days": "Ingresa cantidad válida de días",
|
||||||
"please_enter_a_non-negative_integer": "Por favor, ingrese un número entero no negativo",
|
"Please_enter_a_non-negative_integer": "Por favor, ingrese un número entero no negativo",
|
||||||
"please_enter_days": "Ingresa cantidad de días",
|
"Please_enter_days": "Ingresa cantidad de días",
|
||||||
"password_is_too_short": "Contraseña demasiado corta",
|
"Password_is_too_short": "Contraseña demasiado corta",
|
||||||
"passwords_do_not_match": "Las contraseñas no concuerdan",
|
"Passwords_do_not_match": "Las contraseñas no concuerdan",
|
||||||
"return_to_wiki_page": "Volver a la página del Wiki",
|
"Return_to_wiki_page": "Volver a la página del Wiki",
|
||||||
"insert_network_image": "Insertar imágen desde la red",
|
"Insert_network_image": "Insertar imágen desde la red",
|
||||||
"upload_local_image": "Subir imagen local",
|
"Upload_local_image": "Subir imagen local",
|
||||||
"add_link": "Agregar enlace",
|
"Add_link": "Agregar enlace",
|
||||||
"file_history": "Historial del Archivo",
|
"File_history": "Historial del Archivo",
|
||||||
"history_version": "Historial de Versiones",
|
"History_version": "Historial de Versiones",
|
||||||
"back_to_viewer": "Volver al Visualizador",
|
"Back_to_viewer": "Volver al Visualizador",
|
||||||
"link_title": "Título del enlace",
|
"Link_title": "Título del enlace",
|
||||||
"local_draft": "Borrador local",
|
"Local_draft": "Borrador local",
|
||||||
"use_draft": "Usar borrador",
|
"Use_draft": "Usar borrador",
|
||||||
"delete_draft": "Eliminar borrador",
|
"Delete_draft": "Eliminar borrador",
|
||||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "Tienes un borrador sin guardar. ¿Deseas utilizarlo?",
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "Tienes un borrador sin guardar. ¿Deseas utilizarlo?",
|
||||||
"local_draft_saved": "Borrador local guardado",
|
"Local_draft_saved": "Borrador local guardado",
|
||||||
"new_draft": "Nuevo Borrador",
|
"New_draft": "Nuevo Borrador",
|
||||||
"view_draft": "Ver Borrador",
|
"View_draft": "Ver Borrador",
|
||||||
"publish": "Publicar",
|
"Publish": "Publicar",
|
||||||
"this_file_has_a_draft": "Este archivo tiene un borrador",
|
"This_file_has_a_draft": "Este archivo tiene un borrador",
|
||||||
"delete": "Borrar",
|
"Delete": "Borrar",
|
||||||
"comments": "Comentarios",
|
"Comments": "Comentarios",
|
||||||
"add_a_comment": "Agregar un comentario...",
|
"Add_a_comment": "Agregar un comentario...",
|
||||||
"no_comment_yet": "No hay comentarios.",
|
"No_comment_yet": "No hay comentarios.",
|
||||||
"Mark_as_Resolved": "Marcar como Resuelto",
|
"Mark_as_Resolved": "Marcar como Resuelto",
|
||||||
"ask_for_review": "Solicitar revisión",
|
"Ask_for_review": "Solicitar revisión",
|
||||||
"review_already_exists": "La revisión ya existe",
|
"Review_already_exists": "La revisión ya existe",
|
||||||
"view_review": "Ver revisión",
|
"View_review": "Ver revisión",
|
||||||
"there_is_an_associated_review_with_this_file": "Hay una revisión asociada con este archivo",
|
"There_is_an_associated_review_with_this_file": "Hay una revisión asociada con este archivo",
|
||||||
"start_review": "Iniciar revisión",
|
"Start_review": "Iniciar revisión",
|
||||||
"this_file_is_in_draft_stage": "Este archivo está en la etapa de borrador",
|
"This_file_is_in_draft_stage": "Este archivo está en la etapa de borrador",
|
||||||
"this_file_is_in_review_stage": "Este archivo está en estado de revisión.",
|
"This_file_is_in_review_stage": "Este archivo está en estado de revisión.",
|
||||||
"this_file_has_been_updated": "Este archivo ha sido actualizado.",
|
"This_file_has_been_updated": "Este archivo ha sido actualizado.",
|
||||||
"refresh": "Refrescar",
|
"Refresh": "Refrescar",
|
||||||
"related_files": "archivos relacionados",
|
"Related_files": "archivos relacionados",
|
||||||
"related_file": "archivo relacionado",
|
"Related_file": "archivo relacionado",
|
||||||
"no_tags": "Sin etiquetas",
|
"No_tags": "Sin etiquetas",
|
||||||
"Date": "Fecha",
|
"Date": "Fecha",
|
||||||
"Participants": "Participantes",
|
"Participants": "Participantes",
|
||||||
"Meeting_note": "Nota de la reunión",
|
"Meeting_note": "Nota de la reunión",
|
||||||
"Chooser_document_type": "Elija el tipo de documento",
|
"Chooser_document_type": "Elija el tipo de documento",
|
||||||
"Empty": "Vacío",
|
"Empty": "Vacío",
|
||||||
"no_related_files": "Sin archivos relacionados",
|
"No_related_files": "Sin archivos relacionados",
|
||||||
"no_out_line": "No hay esquema",
|
"No_out_line": "No hay esquema",
|
||||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Editar archivos en este navegador puede producir algunos problemas en el display.",
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Editar archivos en este navegador puede producir algunos problemas en el display.",
|
||||||
"no_document_improvement_suggestion": "No hay sugerencias para mejorar el documento",
|
"No_document_improvement_suggestion": "No hay sugerencias para mejorar el documento",
|
||||||
"Hide_side_panel": "Ocultar panel lateral",
|
"Hide_side_panel": "Ocultar panel lateral",
|
||||||
"Show_side_panel": "Mostrar panel lateral",
|
"Show_side_panel": "Mostrar panel lateral",
|
||||||
"Show_resolved_comments": "Mostrar comentarios resueltos",
|
"Show_resolved_comments": "Mostrar comentarios resueltos",
|
||||||
@@ -131,25 +131,16 @@
|
|||||||
"Insert_library_image": "Insertar imagen desde la biblioteca",
|
"Insert_library_image": "Insertar imagen desde la biblioteca",
|
||||||
"Size": "Tamaño",
|
"Size": "Tamaño",
|
||||||
"Location": "Ubicación",
|
"Location": "Ubicación",
|
||||||
"Last_Update": "Última actualización",
|
"Last_update": "Last update",
|
||||||
"Tags": "Rótulos",
|
"Tags": "Rótulos",
|
||||||
"Related_Files": "Archivos Relacionados",
|
|
||||||
"Add_participants": "Agregar participantes",
|
"Add_participants": "Agregar participantes",
|
||||||
"markdownLint": {
|
"Clear_format": "Clear format",
|
||||||
"missing_h1": {
|
"Image_address_invalid": "Image address invalid",
|
||||||
"description": "No hay h1 en el documento",
|
|
||||||
"issue" : "Falta h1"
|
|
||||||
},
|
|
||||||
"heading_end_with_colon": {
|
|
||||||
"description": "Un encabezado no debe finalizar con el signo Dos Puntos",
|
|
||||||
"issue": "El encabezado finaliza con el signo Dos Puntos"
|
|
||||||
},
|
|
||||||
"heading_increase_irregular": {
|
|
||||||
"description": "Los niveles del encabezado sólo deben incrementarse de a uno por vez",
|
|
||||||
"issue": "Problema con nivel de encabezado"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shortcut_help": "Ayuda de atajos",
|
"Shortcut_help": "Ayuda de atajos",
|
||||||
|
"Link_address_required": "Link address required",
|
||||||
|
"Link_address_invalid": "Link address invalid",
|
||||||
|
"Link_title_required": "Link title required",
|
||||||
|
"Blank_title_not_allowed": "Blank title not allowed",
|
||||||
"userHelp": {
|
"userHelp": {
|
||||||
"title": "Atajos de teclado",
|
"title": "Atajos de teclado",
|
||||||
"userHelpData": [
|
"userHelpData": [
|
||||||
@@ -162,7 +153,8 @@
|
|||||||
"Insert_child_in_item": "Insert child in item",
|
"Insert_child_in_item": "Insert child in item",
|
||||||
"Increase_depth": "Increase depth"
|
"Increase_depth": "Increase depth"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Head shortcuts",
|
"shortcutType": "Head shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Heading_1": "Encabezado 1",
|
"Heading_1": "Encabezado 1",
|
||||||
@@ -172,7 +164,8 @@
|
|||||||
"Heading_5": "Encabezado 5",
|
"Heading_5": "Encabezado 5",
|
||||||
"Heading_6": "Encabezado 6"
|
"Heading_6": "Encabezado 6"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Code block shortcuts",
|
"shortcutType": "Code block shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_code_block": "Crear bloque de código",
|
"Make_code_block": "Crear bloque de código",
|
||||||
@@ -180,37 +173,43 @@
|
|||||||
"Escape_code_block": "Escape code block",
|
"Escape_code_block": "Escape code block",
|
||||||
"Insert_indent": "Insert indent"
|
"Insert_indent": "Insert indent"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Block quote shortcuts",
|
"shortcutType": "Block quote shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_Block_quote": "Make Block quote",
|
"Make_block_quote": "Make block quote",
|
||||||
"Escape_Block_quote": "Escape Block quote"
|
"Escape_block_quote": "Escape block quote"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Atajos de tabla",
|
"shortcutType": "Atajos de tabla",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Table_Row": "Insertar fila de tabla",
|
"Insert_table_row": "Insert table tow",
|
||||||
"Escape_table": "Escape table"
|
"Escape_table": "Escape table"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Atajos de fórmula",
|
"shortcutType": "Atajos de fórmula",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Formula": "Insertar Fórmula"
|
"Insert_formula": "Insert formula"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Inline shortcuts",
|
"shortcutType": "Inline shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Bold": "Negrita",
|
"Bold": "Negrita",
|
||||||
"Italic": "Itálica",
|
"Italic": "Itálica",
|
||||||
"Italic_Bold": "Negrita itálica",
|
"Italic_bold": "Italic bold",
|
||||||
"Inline_code": "Inline code"
|
"Inline_code": "Inline code"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Guardar atajos",
|
"shortcutType": "Guardar atajos",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Save_file": "Guardar archivo"
|
"Save_file": "Guardar archivo"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Atajos de imagen",
|
"shortcutType": "Atajos de imagen",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Paste_screen_shot": "Pegar captura de pantalla",
|
"Paste_screen_shot": "Pegar captura de pantalla",
|
||||||
@@ -218,5 +217,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
}
|
}
|
||||||
|
@@ -1,126 +1,126 @@
|
|||||||
{
|
{
|
||||||
"bold": "Gras",
|
"Bold": "Gras",
|
||||||
"italic": "Italique",
|
"Italic": "Italique",
|
||||||
"inline_code": "Code",
|
"Inline_code": "Code",
|
||||||
"header_one": "Titre 1",
|
"Header_one": "Titre 1",
|
||||||
"header_two": "Titre 2",
|
"Header_two": "Titre 2",
|
||||||
"header_three": "Titre 3",
|
"Header_three": "Titre 3",
|
||||||
"header_four": "Titre 4",
|
"Header_four": "Titre 4",
|
||||||
"header_five": "Titre 5",
|
"Header_five": "Titre 5",
|
||||||
"header_six": "Titre 6",
|
"Header_six": "Titre 6",
|
||||||
"paragraph": "Paragraphe",
|
"Paragraph": "Paragraphe",
|
||||||
"quote": "Blockquote",
|
"Quote": "Blockquote",
|
||||||
"ordered_list": "Numérotation",
|
"Ordered_list": "Liste ordonée",
|
||||||
"unordered_list": "Enumeration",
|
"Unordered_list": "Liste non-ordonée",
|
||||||
"check_list_item": "Case à chocher",
|
"Check_list_item": "Liste à chocher",
|
||||||
"insert_image": "Image",
|
"Insert_image": "Image",
|
||||||
"insert_formula": "Insérer formule",
|
"Insert_formula": "Insérer formule",
|
||||||
"formula": "Formule",
|
"Formula": "Formule",
|
||||||
"insert_file": "Fichier",
|
"Insert_file": "Fichier",
|
||||||
"code": "Ligne de code",
|
"Code": "Ligne de code",
|
||||||
"code_block": "Bloc de code",
|
"Code_block": "Bloc de code",
|
||||||
"insert_link": "Lien",
|
"Insert_link": "Lien",
|
||||||
"insert_table": "Tableau",
|
"Insert_table": "Tableau",
|
||||||
"save": "Sauvegarder",
|
"Save": "Sauvegarder",
|
||||||
"more": "Plus",
|
"More": "Plus",
|
||||||
"invalid_url": "L'adresse n'est pas valide",
|
"Invalid_url": "L'adresse n'est pas valide.",
|
||||||
"link_address": "Adresse du lien",
|
"Link_address": "Adresse du lien",
|
||||||
"image_address": "Adresse de l'image",
|
"Image_address": "Adresse de l'image",
|
||||||
"submit": "Soumettre",
|
"Submit": "Soummettre",
|
||||||
"cancel": "Annuler",
|
"Cancel": "Annuler",
|
||||||
"switch_to_plain_text_editor": "Basculer en éditeur de texte plein",
|
"Switch_to_plain_text_editor": "Basculer en éditeur de texte plein",
|
||||||
"switch_to_rich_text_editor": "Basculer en éditeur de texte riche",
|
"Switch_to_rich_text_editor": "Basculer en éditeur de texte riche",
|
||||||
"switch_to_viewer": "Basculer en visualiseur Markdown",
|
"Switch_to_viewer": "Basculer en visualiseur Markdown",
|
||||||
"help": "Aide",
|
"Help": "Aide",
|
||||||
"remove_table": "Supprimer le tableau",
|
"Remove_table": "Supprimer le tableau",
|
||||||
"column": "Colonne",
|
"Column": "Colonne",
|
||||||
"row": "ligne",
|
"Row": "Ligne",
|
||||||
"Insert_Row_Before": "Insérer au-dessus",
|
"Insert_row_before": "Insert row before",
|
||||||
"Insert_Row_After": "Insérer en-dessous",
|
"Insert_row_after": "Insert row after",
|
||||||
"Insert_Column_Before": "Insérer à gauche",
|
"Insert_column_before": "Insert column before",
|
||||||
"Insert_Column_After": "Insérer à droite",
|
"Insert_column_after": "Insert column after",
|
||||||
"Remove_Row": "Supprimer la ligne",
|
"Remove_row": "Remove row",
|
||||||
"Remove_Column": "Supprimer la colonne",
|
"Remove_column": "Remove column",
|
||||||
"Insert_Row": "Insérer une ligne",
|
"Insert_row": "Insérer une ligne",
|
||||||
"Insert_Column": "Insérer une colonne",
|
"Insert_column": "Insérer une colonne",
|
||||||
"set_align": "Ajuster l'alignement",
|
"Set_align": "Ajuster l'alignement",
|
||||||
"left": "Gauche",
|
"Left": "Gauche",
|
||||||
"center": "Centrer",
|
"Center": "Centrer",
|
||||||
"right": "Droite",
|
"Right": "Droite",
|
||||||
"file_saved": "Le fichier a été sauvegardé.",
|
"File_saved": "Le fichier a été sauvegardé.",
|
||||||
"file_failed_to_save": "Échec de la sauvegarde du fichier",
|
"File_failed_to_save": "Échec de la sauvegarde du fichier",
|
||||||
"star": "Ajouter à favoris",
|
"Star": "Ajouter à favoris",
|
||||||
"unstar": "Enlever des favoris",
|
"Unstar": "Enlever des favoris",
|
||||||
"back_to_parent_directory":"Retour au répertoire parent",
|
"Back_to_parent_directory": "Retour au répertoire parent",
|
||||||
"edit": "Modifier",
|
"Edit": "Modifier",
|
||||||
"copy": "Copier",
|
"Copy": "Copier",
|
||||||
"copied": "Copié",
|
"Copied": "Copié",
|
||||||
"internal_link": "Afficher le lien interne",
|
"Internal_link": "Afficher le lien interne",
|
||||||
"copy_internal_link": "Le lien interne a été copié dans le presse-papiers.",
|
"Copy_internal_link": "Le lien interne a été copié dans le presse-papiers.",
|
||||||
"internal_link_desc": "Un lien interne est un lien vers un fichier ou un dossier accessible en lecture par un utilisateur.",
|
"Internal_link_desc": "Un lien interne est un lien vers un fichier ou un dossier accessible en lecture par un utilisateur.",
|
||||||
"share": "Partager",
|
"Share": "Partager",
|
||||||
"share_link": "Lien de téléchargement",
|
"Share_link": "Lien de téléchargement",
|
||||||
"generate": "Créer",
|
"Generate": "Créer",
|
||||||
"add_password_protection": "Ajouter un mot de passe",
|
"Add_password_protection": "Ajouter un mot de passe",
|
||||||
"password": "Mot de passe",
|
"Password": "Mot de passe",
|
||||||
"at_least_8_characters": "Au moins 8 caractères",
|
"At_least_8_characters": "Au moins 8 caractères",
|
||||||
"password_again": "Mot de passe (à nouveau)",
|
"Password_again": "Mot de passe (à nouveau)",
|
||||||
"add_auto_expiration": "Ajouter une date d'expiration",
|
"Add_auto_expiration": "Ajouter une date d'expiration",
|
||||||
"days": "jours",
|
"Days": "jours",
|
||||||
"please_enter_password": "Entrez un mot de passe",
|
"Please_enter_password": "Entrez un mot de passe",
|
||||||
"greater_than_or_equal_to": "Plus grand ou égale à",
|
"Greater_than_or_equal_to": "Plus grand ou égale à",
|
||||||
"less_than_or_equal_to": "Plus petit ou égal à",
|
"Less_than_or_equal_to": "Plus petit ou égal à",
|
||||||
"set_permission": "Définir la permission",
|
"Set_permission": "Définir la permission",
|
||||||
"preview_and_download": "Prévisualiser et télécharger",
|
"Preview_and_download": "Prévisualiser et télécharger",
|
||||||
"preview_only": "Aperçu uniquement",
|
"Preview_only": "Aperçu uniquement",
|
||||||
"please_enter_valid_days": "Saisissez un nombre de jours valide",
|
"Please_enter_valid_days": "Saisissez un nombre de jours valide.",
|
||||||
"please_enter_a_non-negative_integer": "Veuillez introduire un intégrateur non-négatif",
|
"Please_enter_a_non-negative_integer": "Veuillez introduire un intégrateur non-négatif.",
|
||||||
"please_enter_days": "Veuillez entrer un nombre de jours",
|
"Please_enter_days": "Veuillez entrer un nombre de jours.",
|
||||||
"password_is_too_short": "Le mot de passe est trop court",
|
"Password_is_too_short": "Le mot de passe est trop court.",
|
||||||
"passwords_do_not_match": "Les mots de passe ne correspondent pas.",
|
"Passwords_do_not_match": "Les mots de passe ne correspondent pas.",
|
||||||
"return_to_wiki_page": "Retour à la page du Wiki",
|
"Return_to_wiki_page": "Retour à la page du Wiki",
|
||||||
"insert_network_image": "Insérer une image du réseau",
|
"Insert_network_image": "Insérer une image du réseau",
|
||||||
"upload_local_image": "Insérer une image locale",
|
"Upload_local_image": "Insérer une image locale",
|
||||||
"add_link": "Ajouter un lien",
|
"Add_link": "Ajouter un lien",
|
||||||
"file_history": "Historique du fichier",
|
"File_history": "Voir historique",
|
||||||
"history_version": "Historique des versions",
|
"History_version": "Historique des versions",
|
||||||
"back_to_viewer": "Retour au visualiseur",
|
"Back_to_viewer": "Retour au visualiseur",
|
||||||
"link_title": "Titre du lien",
|
"Link_title": "Titre du lien",
|
||||||
"local_draft": "Brouillon local",
|
"Local_draft": "Brouillon local",
|
||||||
"use_draft": "Utiliser le brouillon",
|
"Use_draft": "Utiliser le brouillon",
|
||||||
"delete_draft": "Supprimer le brouillon",
|
"Delete_draft": "Supprimer le brouillon",
|
||||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "Vous avez un brouillon qui n'est pas sauvegardé. Voulez-vous l'utiliser ?",
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "Vous avez un brouillon qui n'est pas sauvegardé. Voulez-vous l'utiliser ?",
|
||||||
"local_draft_saved": "Brouillon local sauvegardé",
|
"Local_draft_saved": "Brouillon local sauvegardé",
|
||||||
"new_draft": "Nouveau brouillon",
|
"New_draft": "Nouveau brouillon",
|
||||||
"view_draft": "Voir le brouillon",
|
"View_draft": "Voir le brouillon",
|
||||||
"publish": "Publier",
|
"Publish": "Publier",
|
||||||
"this_file_has_a_draft": "Ce fichier possède un brouillon.",
|
"This_file_has_a_draft": "Ce fichier possède un brouillon.",
|
||||||
"delete": "Supprimer",
|
"Delete": "Supprimer",
|
||||||
"comments": "Commentaires",
|
"Comments": "Commentaires",
|
||||||
"add_a_comment": "Ajouter un commentaire",
|
"Add_a_comment": "Ajouter un commentaire",
|
||||||
"no_comment_yet": "Aucun commentaire disponible",
|
"No_comment_yet": "Aucun commentaire disponible",
|
||||||
"Mark_as_Resolved": "Marquer com pris en compte",
|
"Mark_as_Resolved": "Marquer com pris en compte",
|
||||||
"ask_for_review": "Demande d'un avis",
|
"Ask_for_review": "Demande d'un avis",
|
||||||
"review_already_exists": "Un avis existe déjà",
|
"Review_already_exists": "Un avis existe déjà.",
|
||||||
"view_review": "Voir l'avis",
|
"View_review": "Voir l'avis",
|
||||||
"there_is_an_associated_review_with_this_file": "Il y a un avis associé à ce fichier.",
|
"There_is_an_associated_review_with_this_file": "Il y a un avis associé à ce fichier.",
|
||||||
"start_review": "Commencer l'avis",
|
"Start_review": "Commencer l'avis",
|
||||||
"this_file_is_in_draft_stage": "Ce fichier est à l'état de brouillon.",
|
"This_file_is_in_draft_stage": "Ce fichier est à l'état de brouillon.",
|
||||||
"this_file_is_in_review_stage": "Ce fichier est à l'état d'avis.",
|
"This_file_is_in_review_stage": "Ce fichier est à l'état d'avis.",
|
||||||
"this_file_has_been_updated": "Ce fichier à été mis à jour.",
|
"This_file_has_been_updated": "Ce fichier à été mis à jour.",
|
||||||
"refresh": "Rafraichir",
|
"Refresh": "Rafraichir",
|
||||||
"related_files": "Fichiers relatifs",
|
"Related_files": "Fichiers relatifs",
|
||||||
"related_file": "Fichier relatif",
|
"Related_file": "Fichier relatif",
|
||||||
"no_tags": "Pas de tag",
|
"No_tags": "Pas de tag",
|
||||||
"Date": "Date",
|
"Date": "Date",
|
||||||
"Participants": "Participants",
|
"Participants": "Participants",
|
||||||
"Meeting_note": "Note de réunion",
|
"Meeting_note": "Note de réunion",
|
||||||
"Chooser_document_type": "Choisir un type de document",
|
"Chooser_document_type": "Choisir un type de document",
|
||||||
"Empty": "Vide",
|
"Empty": "Vide",
|
||||||
"no_related_files": "Aucun fichier relatif",
|
"No_related_files": "Aucun fichier relatif",
|
||||||
"no_out_line": "Pas de contour",
|
"No_out_line": "Pas de contour",
|
||||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "L'édition de fichiers dans ce navigateur peut entraîner de légers problèmes d'affichage.",
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "L'édition de fichiers dans ce navigateur peut entraîner de légers problèmes d'affichage.",
|
||||||
"no_document_improvement_suggestion": "Aucune proposition pour améliorer le document",
|
"No_document_improvement_suggestion": "Aucune proposition pour améliorer le document",
|
||||||
"Hide_side_panel": "Fermer",
|
"Hide_side_panel": "Fermer",
|
||||||
"Show_side_panel": "Afficher détails",
|
"Show_side_panel": "Afficher détails",
|
||||||
"Show_resolved_comments": "Voir les commentaires pris en compte",
|
"Show_resolved_comments": "Voir les commentaires pris en compte",
|
||||||
@@ -131,25 +131,16 @@
|
|||||||
"Insert_library_image": "Insérer une image d‘une bibliothèque",
|
"Insert_library_image": "Insérer une image d‘une bibliothèque",
|
||||||
"Size": "Taille",
|
"Size": "Taille",
|
||||||
"Location": "Emplacement",
|
"Location": "Emplacement",
|
||||||
"Last_Update": "Mise à jour",
|
"Last_update": "Dernière mise à jour",
|
||||||
"Tags": "Tags",
|
"Tags": "Tags",
|
||||||
"Related_Files": "Fichiers relatifs",
|
|
||||||
"Add_participants": "Ajouter des participants",
|
"Add_participants": "Ajouter des participants",
|
||||||
"markdownLint": {
|
"Clear_format": "Sans formatage",
|
||||||
"missing_h1": {
|
"Image_address_invalid": "Image address invalid",
|
||||||
"description": "Il n'y a pas de h1 dans le document",
|
|
||||||
"issue" : "h1 manquant"
|
|
||||||
},
|
|
||||||
"heading_end_with_colon": {
|
|
||||||
"description": "La ponctuation de fin de titre ne doit pas être deux points",
|
|
||||||
"issue": "Fin du titre largeur de colonne"
|
|
||||||
},
|
|
||||||
"heading_increase_irregular": {
|
|
||||||
"description": "Le niveau des titres ne doit être augmenté que d'un niveau à la fois.",
|
|
||||||
"issue": "Problème niveau de titre"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shortcut_help": "Aide raccourcis",
|
"Shortcut_help": "Aide raccourcis",
|
||||||
|
"Link_address_required": "Link address required",
|
||||||
|
"Link_address_invalid": "Link address invalid",
|
||||||
|
"Link_title_required": "Link title required",
|
||||||
|
"Blank_title_not_allowed": "Blank title not allowed",
|
||||||
"userHelp": {
|
"userHelp": {
|
||||||
"title": "Raccourcis clavier",
|
"title": "Raccourcis clavier",
|
||||||
"userHelpData": [
|
"userHelpData": [
|
||||||
@@ -162,7 +153,8 @@
|
|||||||
"Insert_child_in_item": "Insérer enfant dans l'élément",
|
"Insert_child_in_item": "Insérer enfant dans l'élément",
|
||||||
"Increase_depth": "Améliorer la profondeur"
|
"Increase_depth": "Améliorer la profondeur"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Raccourcis en-tête",
|
"shortcutType": "Raccourcis en-tête",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Heading_1": "Titre 1",
|
"Heading_1": "Titre 1",
|
||||||
@@ -172,7 +164,8 @@
|
|||||||
"Heading_5": "Titre 5",
|
"Heading_5": "Titre 5",
|
||||||
"Heading_6": "Titre 6"
|
"Heading_6": "Titre 6"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Raccourcis de blocs de code",
|
"shortcutType": "Raccourcis de blocs de code",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_code_block": "Faire un bloc de code",
|
"Make_code_block": "Faire un bloc de code",
|
||||||
@@ -180,37 +173,43 @@
|
|||||||
"Escape_code_block": "Sortir du bloc de code",
|
"Escape_code_block": "Sortir du bloc de code",
|
||||||
"Insert_indent": "Insérer un espace"
|
"Insert_indent": "Insérer un espace"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Raccourcis blocs de citation",
|
"shortcutType": "Raccourcis blocs de citation",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_Block_quote": "Faire un bloc de citation",
|
"Make_block_quote": "Make block quote",
|
||||||
"Escape_Block_quote": "Sortir du bloc de citation"
|
"Escape_block_quote": "Escape block quote"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Raccourcis tableau",
|
"shortcutType": "Raccourcis tableau",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Table_Row": "Insérer une ligne à la table",
|
"Insert_table_row": "Insert table tow",
|
||||||
"Escape_table": "Sortir de la table"
|
"Escape_table": "Sortir de la table"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Raccourcis formule",
|
"shortcutType": "Raccourcis formule",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Formula": "Insérer formule"
|
"Insert_formula": "Insérer formule"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Raccourcis en ligne",
|
"shortcutType": "Raccourcis en ligne",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Bold": "Gras",
|
"Bold": "Gras",
|
||||||
"Italic": "Italique",
|
"Italic": "Italique",
|
||||||
"Italic_Bold": "Italique Gras",
|
"Italic_bold": "Italic bold",
|
||||||
"Inline_code": "Ligne de code"
|
"Inline_code": "Ligne de code"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Raccourcis sauvegarde",
|
"shortcutType": "Raccourcis sauvegarde",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Save_file": "Sauvegarder le fichier"
|
"Save_file": "Sauvegarder le fichier"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Raccourcis image",
|
"shortcutType": "Raccourcis image",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Paste_screen_shot": "Coller la capture d'écran",
|
"Paste_screen_shot": "Coller la capture d'écran",
|
||||||
@@ -218,5 +217,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
}
|
}
|
||||||
|
@@ -1,126 +1,126 @@
|
|||||||
{
|
{
|
||||||
"bold": "Grassetto",
|
"Bold": "Grassetto",
|
||||||
"italic": "Corsivo",
|
"Italic": "Corsivo",
|
||||||
"inline_code": "Codice",
|
"Inline_code": "Codice",
|
||||||
"header_one": "Titolo 1",
|
"Header_one": "Titolo 1",
|
||||||
"header_two": "Titolo 2",
|
"Header_two": "Titolo 2",
|
||||||
"header_three": "Titolo 3",
|
"Header_three": "Titolo 3",
|
||||||
"header_four": "Titolo 4",
|
"Header_four": "Titolo 4",
|
||||||
"header_five": "Intestazione 5",
|
"Header_five": "Intestazione 5",
|
||||||
"header_six": "Intestazione 6",
|
"Header_six": "Intestazione 6",
|
||||||
"paragraph": "Paragrafo",
|
"Paragraph": "Paragrafo",
|
||||||
"quote": "Citazione",
|
"Quote": "Citazione",
|
||||||
"ordered_list": "Lista ordinata",
|
"Ordered_list": "Lista ordinata",
|
||||||
"unordered_list": "Lista non ordinata",
|
"Unordered_list": "Lista non ordinata",
|
||||||
"check_list_item": "Controlla la voce dell'elenco",
|
"Check_list_item": "Controlla la voce dell'elenco",
|
||||||
"insert_image": "Inserisci Immagine",
|
"Insert_image": "Inserisci Immagine",
|
||||||
"insert_formula": "Insert Formula",
|
"Insert_formula": "Insert Formula",
|
||||||
"formula": "Formula",
|
"Formula": "Formula",
|
||||||
"insert_file": "Insert File",
|
"Insert_file": "Insert File",
|
||||||
"code": "Codice in linea",
|
"Code": "Codice in linea",
|
||||||
"code_block": "Codice",
|
"Code_block": "Codice",
|
||||||
"insert_link": "Inserisci Collegamento",
|
"Insert_link": "Inserisci Collegamento",
|
||||||
"insert_table": "Inserisci tabella",
|
"Insert_table": "Inserisci tabella",
|
||||||
"save": "Salvare",
|
"Save": "Salvare",
|
||||||
"more": "Altro",
|
"More": "Altro",
|
||||||
"invalid_url": "URL non valida",
|
"Invalid_url": "URL non valida",
|
||||||
"link_address": "Indirizzo collegamento",
|
"Link_address": "Indirizzo collegamento",
|
||||||
"image_address": "Indirizzo Immagine",
|
"Image_address": "Indirizzo Immagine",
|
||||||
"submit": "Invia",
|
"Submit": "Invia",
|
||||||
"cancel": "Annulla",
|
"Cancel": "Annulla",
|
||||||
"switch_to_plain_text_editor": "Passa all'Editor di testo semplice",
|
"Switch_to_plain_text_editor": "Passa all'Editor di testo semplice",
|
||||||
"switch_to_rich_text_editor": "Passa all'Editor di testo formattato",
|
"Switch_to_rich_text_editor": "Passa all'Editor di testo formattato",
|
||||||
"switch_to_viewer": "Passa alla vista di tipo Markdown",
|
"Switch_to_viewer": "Passa alla vista di tipo Markdown",
|
||||||
"help": "Aiuto",
|
"Help": "Aiuto",
|
||||||
"remove_table": "Rimuovere Tabella",
|
"Remove_table": "Rimuovere Tabella",
|
||||||
"column": "Colonna",
|
"Column": "Colonna",
|
||||||
"row": "Riga",
|
"Row": "Riga",
|
||||||
"Insert_Row_Before": "Insert Row Before",
|
"Insert_row_before": "Insert row before",
|
||||||
"Insert_Row_After": "Insert Row After",
|
"Insert_row_after": "Insert row after",
|
||||||
"Insert_Column_Before": "Insert Column Before",
|
"Insert_column_before": "Insert column before",
|
||||||
"Insert_Column_After": "Insert Column After",
|
"Insert_column_after": "Insert column after",
|
||||||
"Remove_Row": "Remove Row",
|
"Remove_row": "Remove row",
|
||||||
"Remove_Column": "Remove Column",
|
"Remove_column": "Remove column",
|
||||||
"Insert_Row": "Insert Row",
|
"Insert_row": "Insert row",
|
||||||
"Insert_Column": "Insert Column",
|
"Insert_column": "Insert column",
|
||||||
"set_align": "Imposta allineamento",
|
"Set_align": "Imposta allineamento",
|
||||||
"left": "Sinistra",
|
"Left": "Sinistra",
|
||||||
"center": "Centrato",
|
"Center": "Centrato",
|
||||||
"right": "Destra",
|
"Right": "Destra",
|
||||||
"file_saved": "File salvato.",
|
"File_saved": "File salvato.",
|
||||||
"file_failed_to_save": "Errore salvataggio file.",
|
"File_failed_to_save": "Errore salvataggio file.",
|
||||||
"star": "Aggiungi asterisco",
|
"Star": "Aggiungi asterisco",
|
||||||
"unstar": "Rimozione asterisco",
|
"Unstar": "Rimozione asterisco",
|
||||||
"back_to_parent_directory":"Torna alla cartella precedente",
|
"Back_to_parent_directory": "Torna alla cartella precedente",
|
||||||
"edit": "Modifica",
|
"Edit": "Modifica",
|
||||||
"copy": "Copia",
|
"Copy": "Copia",
|
||||||
"copied": "Copiato",
|
"Copied": "Copiato",
|
||||||
"internal_link": "Collegamento interno",
|
"Internal_link": "Collegamento interno",
|
||||||
"copy_internal_link": "Il collegamento interno è stato copiato negli appunti",
|
"Copy_internal_link": "Il collegamento interno è stato copiato negli appunti",
|
||||||
"internal_link_desc": "Un collegamento interno è un collegamento a un file o una cartella a cui gli utenti possono accedere con autorizzazione di lettura al file o alla cartella.",
|
"Internal_link_desc": "Un collegamento interno è un collegamento a un file o una cartella a cui gli utenti possono accedere con autorizzazione di lettura al file o alla cartella.",
|
||||||
"share": "Condividi",
|
"Share": "Condividi",
|
||||||
"share_link": "Condividi Collegamento",
|
"Share_link": "Condividi Collegamento",
|
||||||
"generate": "Generare",
|
"Generate": "Generare",
|
||||||
"add_password_protection": "Aggiungi la protezione password",
|
"Add_password_protection": "Aggiungi la protezione password",
|
||||||
"password": "Password",
|
"Password": "Password",
|
||||||
"at_least_8_characters": "almeno 8 caratteri",
|
"At_least_8_characters": "almeno 8 caratteri",
|
||||||
"password_again": "Ridigita password",
|
"Password_again": "Ridigita password",
|
||||||
"add_auto_expiration": "Aggiungi la scadenza automatica",
|
"Add_auto_expiration": "Aggiungi la scadenza automatica",
|
||||||
"days": "giorni",
|
"Days": "giorni",
|
||||||
"please_enter_password": "Per favore, inserisci la password",
|
"Please_enter_password": "Per favore, inserisci la password",
|
||||||
"greater_than_or_equal_to": "Maggiore o uguale a ",
|
"Greater_than_or_equal_to": "Maggiore o uguale a ",
|
||||||
"less_than_or_equal_to": "Minore o uguale a",
|
"Less_than_or_equal_to": "Minore o uguale a",
|
||||||
"set_permission": "Imposta permessi",
|
"Set_permission": "Imposta permessi",
|
||||||
"preview_and_download": "Anteprima e scarica",
|
"Preview_and_download": "Anteprima e download",
|
||||||
"preview_only": "Solo Anteprima",
|
"Preview_only": "Solo Anteprima",
|
||||||
"please_enter_valid_days": "Si prega di inserire giorni validi",
|
"Please_enter_valid_days": "Si prega di inserire giorni validi",
|
||||||
"please_enter_a_non-negative_integer": "Prego inserire un intero non negativo",
|
"Please_enter_a_non-negative_integer": "Prego inserire un intero non negativo",
|
||||||
"please_enter_days": "Prego inserire i giorni",
|
"Please_enter_days": "Prego inserire i giorni",
|
||||||
"password_is_too_short": "La password è troppo corta",
|
"Password_is_too_short": "La password è troppo corta",
|
||||||
"passwords_do_not_match": "Le password non corrispondono",
|
"Passwords_do_not_match": "Le password non corrispondono",
|
||||||
"return_to_wiki_page": "Torna alla pagina Wiki",
|
"Return_to_wiki_page": "Torna alla pagina Wiki",
|
||||||
"insert_network_image": "Inserisci immagine di rete",
|
"Insert_network_image": "Inserisci immagine di rete",
|
||||||
"upload_local_image": "Inserisci immagine locale",
|
"Upload_local_image": "Inserisci immagine locale",
|
||||||
"add_link": "Aggiungi collegamento",
|
"Add_link": "Aggiungi collegamento",
|
||||||
"file_history": "Cronologia dei file",
|
"File_history": "Cronologia dei file",
|
||||||
"history_version": "Versioni cronologia",
|
"History_version": "Versioni cronologia",
|
||||||
"back_to_viewer": "Torma alla vista",
|
"Back_to_viewer": "Torma alla vista",
|
||||||
"link_title": "Link al titolo",
|
"Link_title": "Link al titolo",
|
||||||
"local_draft": "Bozza locale",
|
"Local_draft": "Bozza locale",
|
||||||
"use_draft": "Usa bozza",
|
"Use_draft": "Usa bozza",
|
||||||
"delete_draft": "Rimuovi Bozza",
|
"Delete_draft": "Rimuovi Bozza",
|
||||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "Hai una bozza non salvata. La vuoi utilizzare?",
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "Hai una bozza non salvata. La vuoi utilizzare?",
|
||||||
"local_draft_saved": "Bozza salvata in locale",
|
"Local_draft_saved": "Bozza salvata in locale",
|
||||||
"new_draft": "Nuova Bozza",
|
"New_draft": "Nuova Bozza",
|
||||||
"view_draft": "Bozza",
|
"View_draft": "Bozza",
|
||||||
"publish": "Pubblica",
|
"Publish": "Pubblica",
|
||||||
"this_file_has_a_draft": "Questo file è una bozza",
|
"This_file_has_a_draft": "Questo file è una bozza",
|
||||||
"delete": "Elimina",
|
"Delete": "Elimina",
|
||||||
"comments": "Commenti",
|
"Comments": "Commenti",
|
||||||
"add_a_comment": "Aggiungi un commento...",
|
"Add_a_comment": "Aggiungi un commento...",
|
||||||
"no_comment_yet": "Ancora nessun commento.",
|
"No_comment_yet": "Ancora nessun commento.",
|
||||||
"Mark_as_Resolved": "Mark as Resolved",
|
"Mark_as_Resolved": "Mark as Resolved",
|
||||||
"ask_for_review": "Richiedi una revisione",
|
"Ask_for_review": "Richiedi una revisione",
|
||||||
"review_already_exists": "Revisione già esistente",
|
"Review_already_exists": "Revisione già esistente",
|
||||||
"view_review": "Visualizza revisione",
|
"View_review": "Visualizza revisione",
|
||||||
"there_is_an_associated_review_with_this_file": "C'è una recensione associata con questo file.",
|
"There_is_an_associated_review_with_this_file": "C'è una recensione associata con questo file.",
|
||||||
"start_review": "Inizia Revisione",
|
"Start_review": "Inizia Revisione",
|
||||||
"this_file_is_in_draft_stage": "Questo file è in fase di bozza.",
|
"This_file_is_in_draft_stage": "Questo file è in fase di bozza.",
|
||||||
"this_file_is_in_review_stage": "Questo file è in fase di revisione.",
|
"This_file_is_in_review_stage": "Questo file è in fase di revisione.",
|
||||||
"this_file_has_been_updated": "Questo file è stato aggiornato.",
|
"This_file_has_been_updated": "Questo file è stato aggiornato.",
|
||||||
"refresh": "Aggiornare",
|
"Refresh": "Aggiornare",
|
||||||
"related_files": "file correlati",
|
"Related_files": "file correlati",
|
||||||
"related_file": "file correlato",
|
"Related_file": "file correlato",
|
||||||
"no_tags": "Nessun tag",
|
"No_tags": "Nessun tag",
|
||||||
"Date": "Data",
|
"Date": "Data",
|
||||||
"Participants": "Participants",
|
"Participants": "Participants",
|
||||||
"Meeting_note": "Meeting note",
|
"Meeting_note": "Meeting note",
|
||||||
"Chooser_document_type": "Chooser document type",
|
"Chooser_document_type": "Chooser document type",
|
||||||
"Empty": "Vuoto",
|
"Empty": "Vuoto",
|
||||||
"no_related_files": "Nessun file correlato",
|
"No_related_files": "Nessun file correlato",
|
||||||
"no_out_line": "No outline",
|
"No_out_line": "No outline",
|
||||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Editing files in this browser can lead to slight display problems.",
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Editing files in this browser can lead to slight display problems.",
|
||||||
"no_document_improvement_suggestion": "No document improvement suggestion",
|
"No_document_improvement_suggestion": "No document improvement suggestion",
|
||||||
"Hide_side_panel": "Hide side panel",
|
"Hide_side_panel": "Hide side panel",
|
||||||
"Show_side_panel": "Show side panel",
|
"Show_side_panel": "Show side panel",
|
||||||
"Show_resolved_comments": "Mostra commenti risolti",
|
"Show_resolved_comments": "Mostra commenti risolti",
|
||||||
@@ -131,25 +131,16 @@
|
|||||||
"Insert_library_image": "Insert library image",
|
"Insert_library_image": "Insert library image",
|
||||||
"Size": "Dimensione",
|
"Size": "Dimensione",
|
||||||
"Location": "Posizione",
|
"Location": "Posizione",
|
||||||
"Last_Update": "Ultimo aggiornamento",
|
"Last_update": "Last update",
|
||||||
"Tags": "Tag",
|
"Tags": "Tag",
|
||||||
"Related_Files": "File correlati",
|
|
||||||
"Add_participants": "Add participants",
|
"Add_participants": "Add participants",
|
||||||
"markdownLint": {
|
"Clear_format": "Clear format",
|
||||||
"missing_h1": {
|
"Image_address_invalid": "Image address invalid",
|
||||||
"description": "There is no h1 in the document",
|
|
||||||
"issue" : "Missing h1"
|
|
||||||
},
|
|
||||||
"heading_end_with_colon": {
|
|
||||||
"description": "Trailing punctuation in heading should not be a colon",
|
|
||||||
"issue": "Heading ends width colon"
|
|
||||||
},
|
|
||||||
"heading_increase_irregular": {
|
|
||||||
"description": "Heading levels should only increment by one level at a time",
|
|
||||||
"issue": "Heading level issue"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shortcut_help": "Shortcut help",
|
"Shortcut_help": "Shortcut help",
|
||||||
|
"Link_address_required": "Link address required",
|
||||||
|
"Link_address_invalid": "Link address invalid",
|
||||||
|
"Link_title_required": "Link title required",
|
||||||
|
"Blank_title_not_allowed": "Blank title not allowed",
|
||||||
"userHelp": {
|
"userHelp": {
|
||||||
"title": "Tasti rapidi",
|
"title": "Tasti rapidi",
|
||||||
"userHelpData": [
|
"userHelpData": [
|
||||||
@@ -162,7 +153,8 @@
|
|||||||
"Insert_child_in_item": "Inserisci un elemento figlio sotto questo elemento",
|
"Insert_child_in_item": "Inserisci un elemento figlio sotto questo elemento",
|
||||||
"Increase_depth": "Aumenta la profondità"
|
"Increase_depth": "Aumenta la profondità"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Scorciatoie principali",
|
"shortcutType": "Scorciatoie principali",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Heading_1": "Titolo 1",
|
"Heading_1": "Titolo 1",
|
||||||
@@ -172,7 +164,8 @@
|
|||||||
"Heading_5": "Intestazione 5",
|
"Heading_5": "Intestazione 5",
|
||||||
"Heading_6": "Intestazione 6"
|
"Heading_6": "Intestazione 6"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Scorciatoie di codice",
|
"shortcutType": "Scorciatoie di codice",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_code_block": "Crea un blocco di codice",
|
"Make_code_block": "Crea un blocco di codice",
|
||||||
@@ -180,37 +173,43 @@
|
|||||||
"Escape_code_block": "Codice di escape",
|
"Escape_code_block": "Codice di escape",
|
||||||
"Insert_indent": "Inserisci indentazione"
|
"Insert_indent": "Inserisci indentazione"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Blocco scorciatoie di citazione",
|
"shortcutType": "Blocco scorciatoie di citazione",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_Block_quote": "Crea blocco citazioni",
|
"Make_block_quote": "Make block quote",
|
||||||
"Escape_Block_quote": "Escape Blocco Codice"
|
"Escape_block_quote": "Escape block quote"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Scorciatoie Tabella",
|
"shortcutType": "Scorciatoie Tabella",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Table_Row": "Inserisci riga nella tabella",
|
"Insert_table_row": "Insert table tow",
|
||||||
"Escape_table": "Escape tabella"
|
"Escape_table": "Escape tabella"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Formula shortcuts",
|
"shortcutType": "Formula shortcuts",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Formula": "Insert Formula"
|
"Insert_formula": "Insert formula"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Scorciatoie in linea",
|
"shortcutType": "Scorciatoie in linea",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Bold": "Grassetto",
|
"Bold": "Grassetto",
|
||||||
"Italic": "Corsivo",
|
"Italic": "Corsivo",
|
||||||
"Italic_Bold": "Corsivo Grassetto",
|
"Italic_bold": "Italic bold",
|
||||||
"Inline_code": "Codice in linea"
|
"Inline_code": "Codice in linea"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Salva scorciatoie",
|
"shortcutType": "Salva scorciatoie",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Save_file": "Salva file"
|
"Save_file": "Salva file"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Scorciatoie per le immagini",
|
"shortcutType": "Scorciatoie per le immagini",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Paste_screen_shot": "Incolla la schermata",
|
"Paste_screen_shot": "Incolla la schermata",
|
||||||
@@ -218,5 +217,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
}
|
}
|
||||||
|
@@ -1,126 +1,126 @@
|
|||||||
{
|
{
|
||||||
"bold": "Полужирный",
|
"Bold": "Полужирный",
|
||||||
"italic": "Курсив",
|
"Italic": "Курсив",
|
||||||
"inline_code": "Код",
|
"Inline_code": "Код",
|
||||||
"header_one": "Заголовок 1",
|
"Header_one": "Заголовок 1",
|
||||||
"header_two": "Заголовок 2",
|
"Header_two": "Заголовок 2",
|
||||||
"header_three": "Заголовок 3",
|
"Header_three": "Заголовок 3",
|
||||||
"header_four": "Заголовок 4",
|
"Header_four": "Заголовок 4",
|
||||||
"header_five": "Заголовок 5",
|
"Header_five": "Заголовок 5",
|
||||||
"header_six": "Заголовок 6",
|
"Header_six": "Заголовок 6",
|
||||||
"paragraph": "Параграф",
|
"Paragraph": "Параграф",
|
||||||
"quote": "Цитата",
|
"Quote": "Цитата",
|
||||||
"ordered_list": "Нумерованный список",
|
"Ordered_list": "Нумерованный список",
|
||||||
"unordered_list": "Маркированный список",
|
"Unordered_list": "Маркированный список",
|
||||||
"check_list_item": "Проверка элемента списка",
|
"Check_list_item": "Проверка элемента списка",
|
||||||
"insert_image": "Вставить изображение",
|
"Insert_image": "Вставить изображение",
|
||||||
"insert_formula": "Вставить формулу",
|
"Insert_formula": "Вставить формулу",
|
||||||
"formula": "Формула",
|
"Formula": "Формула",
|
||||||
"insert_file": "Вставить файл",
|
"Insert_file": "Вставить файл",
|
||||||
"code": "Встроенный код",
|
"Code": "Встроенный код",
|
||||||
"code_block": "Блок кода",
|
"Code_block": "Блок кода",
|
||||||
"insert_link": "Вставить ссылку",
|
"Insert_link": "Вставить ссылку",
|
||||||
"insert_table": "Вставить таблицу",
|
"Insert_table": "Вставить таблицу",
|
||||||
"save": "Сохранить",
|
"Save": "Сохранить",
|
||||||
"more": "Подробнее",
|
"More": "Подробнее",
|
||||||
"invalid_url": "Недопустимый URL",
|
"Invalid_url": "Недопустимый URL",
|
||||||
"link_address": "Адрес ссылки",
|
"Link_address": "Адрес ссылки",
|
||||||
"image_address": "Адрес изображения",
|
"Image_address": "Адрес изображения",
|
||||||
"submit": "Отправить",
|
"Submit": "Отправить",
|
||||||
"cancel": "Отменить",
|
"Cancel": "Отменить",
|
||||||
"switch_to_plain_text_editor": "Переключиться на обычный текстовый редактор",
|
"Switch_to_plain_text_editor": "Переключиться на обычный текстовый редактор",
|
||||||
"switch_to_rich_text_editor": "Переключиться на визуальный редактор",
|
"Switch_to_rich_text_editor": "Переключиться на визуальный редактор",
|
||||||
"switch_to_viewer": "Переключиться на просмотр Markdown",
|
"Switch_to_viewer": "Переключиться на просмотр Markdown",
|
||||||
"help": "Помощь",
|
"Help": "Помощь",
|
||||||
"remove_table": "Удалить таблицу",
|
"Remove_table": "Удалить таблицу",
|
||||||
"column": "Столбец",
|
"Column": "Столбец",
|
||||||
"row": "Строка",
|
"Row": "Строка",
|
||||||
"Insert_Row_Before": "Вставить строку перед",
|
"Insert_row_before": "Insert row before",
|
||||||
"Insert_Row_After": "Вставить строку после",
|
"Insert_row_after": "Insert row after",
|
||||||
"Insert_Column_Before": "Вставить столбец перед",
|
"Insert_column_before": "Insert column before",
|
||||||
"Insert_Column_After": "Вставить столбец после",
|
"Insert_column_after": "Insert column after",
|
||||||
"Remove_Row": "Удалить строку",
|
"Remove_row": "Remove row",
|
||||||
"Remove_Column": "Удалить столбец",
|
"Remove_column": "Remove column",
|
||||||
"Insert_Row": "Вставить строку",
|
"Insert_row": "Вставить строку",
|
||||||
"Insert_Column": "Вставить столбец",
|
"Insert_column": "Вставить столбец",
|
||||||
"set_align": "Установить выравнивание",
|
"Set_align": "Установить выравнивание",
|
||||||
"left": "Слева",
|
"Left": "Слева",
|
||||||
"center": "По центру",
|
"Center": "По центру",
|
||||||
"right": "Справа",
|
"Right": "Справа",
|
||||||
"file_saved": "Файл сохранён.",
|
"File_saved": "Файл сохранён.",
|
||||||
"file_failed_to_save": "Не удалось сохранить файл.",
|
"File_failed_to_save": "Не удалось сохранить файл.",
|
||||||
"star": "Добавить пометку",
|
"Star": "Добавить пометку",
|
||||||
"unstar": "Удалить пометку",
|
"Unstar": "Удалить пометку",
|
||||||
"back_to_parent_directory":"Вернуться в родительский каталог",
|
"Back_to_parent_directory": "Вернуться в родительский каталог",
|
||||||
"edit": "Редактировать",
|
"Edit": "Редактировать",
|
||||||
"copy": "Копировать",
|
"Copy": "Копировать",
|
||||||
"copied": "Скопировано",
|
"Copied": "Скопировано",
|
||||||
"internal_link": "Внутренняя ссылка",
|
"Internal_link": "Внутренняя ссылка",
|
||||||
"copy_internal_link": "Внутренняя ссылка скопирована в буфер обмена",
|
"Copy_internal_link": "Внутренняя ссылка скопирована в буфер обмена",
|
||||||
"internal_link_desc": "Внутренняя ссылка - это ссылка на файл или папку, к которым могут обращаться пользователи с правами на чтение файла или папки.",
|
"Internal_link_desc": "Внутренняя ссылка - это ссылка на файл или папку, к которым могут обращаться пользователи с правами на чтение файла или папки.",
|
||||||
"share": "Общий доступ",
|
"Share": "Общий доступ",
|
||||||
"share_link": "Общедоступная ссылка",
|
"Share_link": "Общедоступная ссылка",
|
||||||
"generate": "Создать",
|
"Generate": "Создать",
|
||||||
"add_password_protection": "Защитить паролем",
|
"Add_password_protection": "Защитить паролем",
|
||||||
"password": "Пароль",
|
"Password": "Пароль",
|
||||||
"at_least_8_characters": "не менее 8 символов",
|
"At_least_8_characters": "не менее 8 символов",
|
||||||
"password_again": "Подтвердите пароль",
|
"Password_again": "Подтвердите пароль",
|
||||||
"add_auto_expiration": "Добавить автоистечение срока действия",
|
"Add_auto_expiration": "Добавить автоистечение срока действия",
|
||||||
"days": "дней",
|
"Days": "дней",
|
||||||
"please_enter_password": "Пожалуйста, введите пароль",
|
"Please_enter_password": "Пожалуйста, введите пароль",
|
||||||
"greater_than_or_equal_to": "Больше или равно",
|
"Greater_than_or_equal_to": "Больше или равно",
|
||||||
"less_than_or_equal_to": "Меньше или равно",
|
"Less_than_or_equal_to": "Меньше или равно",
|
||||||
"set_permission": "Установить разрешения",
|
"Set_permission": "Установить разрешения",
|
||||||
"preview_and_download": "Предпросмотр и скачивание",
|
"Preview_and_download": "Предпросмотр и скачивание",
|
||||||
"preview_only": "Только предпросмотр",
|
"Preview_only": "Только предпросмотр",
|
||||||
"please_enter_valid_days": "Пожалуйста, введите действительные дни",
|
"Please_enter_valid_days": "Пожалуйста, введите действительные дни",
|
||||||
"please_enter_a_non-negative_integer": "Пожалуйста, введите неотрицательное целое число",
|
"Please_enter_a_non-negative_integer": "Пожалуйста, введите неотрицательное целое число",
|
||||||
"please_enter_days": "Пожалуйста, введите дни",
|
"Please_enter_days": "Пожалуйста, введите дни",
|
||||||
"password_is_too_short": "Пароль слишком короткий",
|
"Password_is_too_short": "Пароль слишком короткий",
|
||||||
"passwords_do_not_match": "Пароли не совпадают",
|
"Passwords_do_not_match": "Пароли не совпадают",
|
||||||
"return_to_wiki_page": "Вернуться на страницу Вики",
|
"Return_to_wiki_page": "Вернуться на страницу Вики",
|
||||||
"insert_network_image": "Вставить удалённое изображение",
|
"Insert_network_image": "Вставить удалённое изображение",
|
||||||
"upload_local_image": "Загрузить локальное изображение",
|
"Upload_local_image": "Загрузить локальное изображение",
|
||||||
"add_link": "Добавить ссылку",
|
"Add_link": "Добавить ссылку",
|
||||||
"file_history": "История файла",
|
"File_history": "История файла",
|
||||||
"history_version": "История версий",
|
"History_version": "История версий",
|
||||||
"back_to_viewer": "Вернуться к просмотру",
|
"Back_to_viewer": "Вернуться к просмотру",
|
||||||
"link_title": "Название ссылки",
|
"Link_title": "Название ссылки",
|
||||||
"local_draft": "Локальный черновик",
|
"Local_draft": "Локальный черновик",
|
||||||
"use_draft": "Использовать черновик",
|
"Use_draft": "Использовать черновик",
|
||||||
"delete_draft": "Удалить черновик",
|
"Delete_draft": "Удалить черновик",
|
||||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "У вас есть несохранённый черновик. Хотите использовать его?",
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "У вас есть несохранённый черновик. Хотите использовать его?",
|
||||||
"local_draft_saved": "Локальный черновик сохранён",
|
"Local_draft_saved": "Локальный черновик сохранён",
|
||||||
"new_draft": "Новый черновик",
|
"New_draft": "Новый черновик",
|
||||||
"view_draft": "Просмотр черновика",
|
"View_draft": "Просмотр черновика",
|
||||||
"publish": "Опубликовать",
|
"Publish": "Опубликовать",
|
||||||
"this_file_has_a_draft": "Этот файл имеет черновик.",
|
"This_file_has_a_draft": "Этот файл имеет черновик.",
|
||||||
"delete": "Удалить",
|
"Delete": "Удалить",
|
||||||
"comments": "Комментарии",
|
"Comments": "Комментарии",
|
||||||
"add_a_comment": "Добавить комментарий...",
|
"Add_a_comment": "Добавить комментарий...",
|
||||||
"no_comment_yet": "Комментариев пока нет.",
|
"No_comment_yet": "Комментариев пока нет.",
|
||||||
"Mark_as_Resolved": "Отметить как решённый",
|
"Mark_as_Resolved": "Отметить как решённый",
|
||||||
"ask_for_review": "Спросить отзыв",
|
"Ask_for_review": "Спросить отзыв",
|
||||||
"review_already_exists": "Отзыв уже существует",
|
"Review_already_exists": "Отзыв уже существует",
|
||||||
"view_review": "Просмотр отзыва",
|
"View_review": "Просмотр отзыва",
|
||||||
"there_is_an_associated_review_with_this_file": "Есть связанный отзыв с этим файлом.",
|
"There_is_an_associated_review_with_this_file": "Есть связанный отзыв с этим файлом.",
|
||||||
"start_review": "Начать отзыв",
|
"Start_review": "Начать отзыв",
|
||||||
"this_file_is_in_draft_stage": "Этот файл находится в стадии черновика.",
|
"This_file_is_in_draft_stage": "Этот файл находится в стадии черновика.",
|
||||||
"this_file_is_in_review_stage": "Этот файл находится на стадии проверки.",
|
"This_file_is_in_review_stage": "Этот файл находится на стадии проверки.",
|
||||||
"this_file_has_been_updated": "Этот файл был обновлён.",
|
"This_file_has_been_updated": "Этот файл был обновлён.",
|
||||||
"refresh": "Обновить",
|
"Refresh": "Обновить",
|
||||||
"related_files": "связанные файлы",
|
"Related_files": "связанные файлы",
|
||||||
"related_file": "связанный файл",
|
"Related_file": "связанный файл",
|
||||||
"no_tags": "Нет меток",
|
"No_tags": "Нет меток",
|
||||||
"Date": "Дата",
|
"Date": "Дата",
|
||||||
"Participants": "Участники",
|
"Participants": "Участники",
|
||||||
"Meeting_note": "Заметка о встрече",
|
"Meeting_note": "Заметка о встрече",
|
||||||
"Chooser_document_type": "Выбор типа документа",
|
"Chooser_document_type": "Выбор типа документа",
|
||||||
"Empty": "Пусто",
|
"Empty": "Пусто",
|
||||||
"no_related_files": "Нет связанных файлов",
|
"No_related_files": "Нет связанных файлов",
|
||||||
"no_out_line": "Нет контура",
|
"No_out_line": "Нет контура",
|
||||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Изменение файлов в этом браузере может привести к небольшим проблемам с отображением.",
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Изменение файлов в этом браузере может привести к небольшим проблемам с отображением.",
|
||||||
"no_document_improvement_suggestion": "Нет предложений по улучшению документа",
|
"No_document_improvement_suggestion": "Нет предложений по улучшению документа",
|
||||||
"Hide_side_panel": "Скрыть боковую панель",
|
"Hide_side_panel": "Скрыть боковую панель",
|
||||||
"Show_side_panel": "Показать боковую панель",
|
"Show_side_panel": "Показать боковую панель",
|
||||||
"Show_resolved_comments": "Показать разрешённые комментарии",
|
"Show_resolved_comments": "Показать разрешённые комментарии",
|
||||||
@@ -131,25 +131,16 @@
|
|||||||
"Insert_library_image": "Вставить изображение библиотеки",
|
"Insert_library_image": "Вставить изображение библиотеки",
|
||||||
"Size": "Размер",
|
"Size": "Размер",
|
||||||
"Location": "Местонахождение",
|
"Location": "Местонахождение",
|
||||||
"Last_Update": "Последнее обновление",
|
"Last_update": "Последнее обновление",
|
||||||
"Tags": "Метки",
|
"Tags": "Метки",
|
||||||
"Related_Files": "Связанные файлы",
|
|
||||||
"Add_participants": "Добавить участников",
|
"Add_participants": "Добавить участников",
|
||||||
"markdownLint": {
|
"Clear_format": "Очистить формат",
|
||||||
"missing_h1": {
|
"Image_address_invalid": "Image address invalid",
|
||||||
"description": "В документе нет h1",
|
|
||||||
"issue" : "Отсутствует h1"
|
|
||||||
},
|
|
||||||
"heading_end_with_colon": {
|
|
||||||
"description": "Завершающая пунктуация в заголовке не должна быть двоеточием",
|
|
||||||
"issue": "Заголовок заканчивается двоеточием"
|
|
||||||
},
|
|
||||||
"heading_increase_irregular": {
|
|
||||||
"description": "Уровни заголовков должны увеличиваться только на один уровень за раз",
|
|
||||||
"issue": "Проблема уровня заголовка"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shortcut_help": "Справка по горячим клавишам",
|
"Shortcut_help": "Справка по горячим клавишам",
|
||||||
|
"Link_address_required": "Link address required",
|
||||||
|
"Link_address_invalid": "Link address invalid",
|
||||||
|
"Link_title_required": "Link title required",
|
||||||
|
"Blank_title_not_allowed": "Blank title not allowed",
|
||||||
"userHelp": {
|
"userHelp": {
|
||||||
"title": "Горячие клавиши",
|
"title": "Горячие клавиши",
|
||||||
"userHelpData": [
|
"userHelpData": [
|
||||||
@@ -162,7 +153,8 @@
|
|||||||
"Insert_child_in_item": "Вставить дочерний в элемент",
|
"Insert_child_in_item": "Вставить дочерний в элемент",
|
||||||
"Increase_depth": "Увеличить глубину"
|
"Increase_depth": "Увеличить глубину"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Горячие клавиши для заголовка",
|
"shortcutType": "Горячие клавиши для заголовка",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Heading_1": "Заголовок 1",
|
"Heading_1": "Заголовок 1",
|
||||||
@@ -172,7 +164,8 @@
|
|||||||
"Heading_5": "Заголовок 5",
|
"Heading_5": "Заголовок 5",
|
||||||
"Heading_6": "Заголовок 6"
|
"Heading_6": "Заголовок 6"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Горячие клавиши для кода",
|
"shortcutType": "Горячие клавиши для кода",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_code_block": "Создать блок кода",
|
"Make_code_block": "Создать блок кода",
|
||||||
@@ -180,37 +173,43 @@
|
|||||||
"Escape_code_block": "Выделить блок кода",
|
"Escape_code_block": "Выделить блок кода",
|
||||||
"Insert_indent": "Вставить отступ"
|
"Insert_indent": "Вставить отступ"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Горячие клавиши для блока цитаты",
|
"shortcutType": "Горячие клавиши для блока цитаты",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_Block_quote": "Создать блок цитаты",
|
"Make_block_quote": "Make block quote",
|
||||||
"Escape_Block_quote": "Выделить блок цитаты"
|
"Escape_block_quote": "Escape block quote"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Горячие клавиши для таблицы",
|
"shortcutType": "Горячие клавиши для таблицы",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Table_Row": "Вставить строку таблицы",
|
"Insert_table_row": "Insert table tow",
|
||||||
"Escape_table": "Выделить таблицу"
|
"Escape_table": "Выделить таблицу"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Горячие клавиши для формул",
|
"shortcutType": "Горячие клавиши для формул",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Formula": "Вставить формулу"
|
"Insert_formula": "Вставить формулу"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Встроенные горячие клавиши",
|
"shortcutType": "Встроенные горячие клавиши",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Bold": "Полужирный",
|
"Bold": "Полужирный",
|
||||||
"Italic": "Курсив",
|
"Italic": "Курсив",
|
||||||
"Italic_Bold": "Курсив полужирный",
|
"Italic_bold": "Italic bold",
|
||||||
"Inline_code": "Встроенный код"
|
"Inline_code": "Встроенный код"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Сохранить горячие клавиши",
|
"shortcutType": "Сохранить горячие клавиши",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Save_file": "Сохранить файл"
|
"Save_file": "Сохранить файл"
|
||||||
}
|
}
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"shortcutType": "Горячие клавиши для изображений",
|
"shortcutType": "Горячие клавиши для изображений",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Paste_screen_shot": "Вставить скриншот",
|
"Paste_screen_shot": "Вставить скриншот",
|
||||||
@@ -218,5 +217,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
}
|
}
|
||||||
|
@@ -1,121 +1,124 @@
|
|||||||
{
|
{
|
||||||
"bold": "粗体",
|
"Bold": "粗体",
|
||||||
"italic": "斜体",
|
"Italic": "斜体",
|
||||||
"inline_code": "代码",
|
"Inline_code": "代码",
|
||||||
"header_one": "一级标题",
|
"Header_one": "一级标题",
|
||||||
"header_two": "二级标题",
|
"Header_two": "二级标题",
|
||||||
"header_three": "三级标题",
|
"Header_three": "三级标题",
|
||||||
"header_four": "四级标题",
|
"Header_four": "四级标题",
|
||||||
"header_five": "五级标题",
|
"Header_five": "五级标题",
|
||||||
"header_six": "六级标题",
|
"Header_six": "六级标题",
|
||||||
"paragraph": "段落",
|
"Paragraph": "段落",
|
||||||
"quote": "引用",
|
"Quote": "引用",
|
||||||
"ordered_list": "有序列表",
|
"Ordered_list": "有序列表",
|
||||||
"unordered_list": "无序列表",
|
"Unordered_list": "无序列表",
|
||||||
"check_list_item": "任务列表",
|
"Check_list_item": "任务列表",
|
||||||
"insert_image": "插入图片",
|
"Insert_image": "插入图片",
|
||||||
"insert_formula": "插入公式",
|
"Insert_formula": "插入公式",
|
||||||
"formula": "公式",
|
"Formula": "公式",
|
||||||
"insert_file": "插入文件",
|
"Insert_file": "插入文件",
|
||||||
"code": "行内代码",
|
"Code": "行内代码",
|
||||||
"code_block": "代码块",
|
"Code_block": "代码块",
|
||||||
"insert_link": "添加链接",
|
"Insert_link": "添加链接",
|
||||||
"insert_table": "添加表格",
|
"Insert_table": "添加表格",
|
||||||
"save": "保存",
|
"Save": "保存",
|
||||||
"more": "更多",
|
"More": "更多",
|
||||||
"invalid_url": "无效链接",
|
"Invalid_url": "无效链接",
|
||||||
"link_address": "链接地址",
|
"Link_address": "链接地址",
|
||||||
"image_address": "图片地址",
|
"Image_address": "图片地址",
|
||||||
"submit": "提交",
|
"Submit": "提交",
|
||||||
"cancel": "取消",
|
"Cancel": "取消",
|
||||||
"switch_to_plain_text_editor": "切换至普通文本编辑器",
|
"Switch_to_plain_text_editor": "切换至普通文本编辑器",
|
||||||
"switch_to_rich_text_editor": "切换至富文本编辑器",
|
"Switch_to_rich_text_editor": "切换至富文本编辑器",
|
||||||
"switch_to_viewer": "切换到只读模式",
|
"Switch_to_viewer": "切换到只读模式",
|
||||||
"help": "帮助",
|
"Help": "帮助",
|
||||||
"remove_table": "删除表格",
|
"Remove_table": "删除表格",
|
||||||
"Insert_Row_Before": "上方插入行",
|
"Column": "列",
|
||||||
"Insert_Row_After": "下方插入行",
|
"Row": "行",
|
||||||
"Insert_Column_Before": "左边插入列",
|
"Insert_row_before": "上方插入行",
|
||||||
"Insert_Column_After": "右边插入列",
|
"Insert_row_after": "下方插入行",
|
||||||
"Remove_Row": "删除当前行",
|
"Insert_column_before": "左边插入列",
|
||||||
"Remove_Column": "删除当前列",
|
"Insert_column_after": "右边插入列",
|
||||||
"Insert_Row": "插入行",
|
"Remove_row": "删除当前行",
|
||||||
"Insert_Column": "插入列",
|
"Remove_column": "删除当前列",
|
||||||
"column": "列",
|
"Insert_row": "插入行",
|
||||||
"row": "行",
|
"Insert_column": "插入列",
|
||||||
"set_align": "对齐方式",
|
"Set_align": "对齐方式",
|
||||||
"left": "左对齐",
|
"Left": "左对齐",
|
||||||
"center": "居中",
|
"Center": "居中",
|
||||||
"right": "右对齐",
|
"Right": "右对齐",
|
||||||
"file_saved": "保存文件成功",
|
"File_saved": "保存文件成功",
|
||||||
"file_failed_to_save": "保存文件失败",
|
"File_failed_to_save": "保存文件失败",
|
||||||
"star": "添加星标",
|
"Star": "添加星标",
|
||||||
"unstar": "移除星标",
|
"Unstar": "移除星标",
|
||||||
"back_to_parent_directory":"返回上级目录",
|
"Back_to_parent_directory": "返回上级目录",
|
||||||
"edit":"编辑",
|
"Edit": "编辑",
|
||||||
"copy": "复制",
|
"Copy": "复制",
|
||||||
"copied": "已复制",
|
"Copied": "已复制",
|
||||||
"internal_link": "内部链接",
|
"Internal_link": "内部链接",
|
||||||
"copy_internal_link": "内部链接已复制到剪贴板",
|
"Copy_internal_link": "内部链接已复制到剪贴板",
|
||||||
"internal_link_desc": "内部链接是指向文件或目录的链接,只有对该文件或目录有访问权限的人可以访问。",
|
"Internal_link_desc": "内部链接是指向文件或目录的链接,只有对该文件或目录有访问权限的人可以访问。",
|
||||||
"share": "共享",
|
"Share": "共享",
|
||||||
"share_link": "共享链接",
|
"Share_link": "共享链接",
|
||||||
"generate": "生成链接",
|
"Generate": "生成链接",
|
||||||
"add_password_protection": "增加密码保护",
|
"Add_password_protection": "增加密码保护",
|
||||||
"password": "密码",
|
"Password": "密码",
|
||||||
"at_least_8_characters": "至少8个字符",
|
"At_least_8_characters": "至少8个字符",
|
||||||
"password_again": "请再次输入密码",
|
"Password_again": "请再次输入密码",
|
||||||
"add_auto_expiration": "增加自动过期",
|
"Add_auto_expiration": "增加自动过期",
|
||||||
"days": "天",
|
"Days": "天",
|
||||||
"please_enter_password": "请输入密码",
|
"Please_enter_password": "请输入密码",
|
||||||
"greater_than_or_equal_to": "大于或等于",
|
"Greater_than_or_equal_to": "大于或等于",
|
||||||
"less_than_or_equal_to": "小于或等于",
|
"Less_than_or_equal_to": "小于或等于",
|
||||||
"set_permission": "设置权限",
|
"Set_permission": "设置权限",
|
||||||
"preview_and_download": "预览与下载",
|
"Preview_and_download": "预览与下载",
|
||||||
"preview_only": "仅查看",
|
"Preview_only": "仅查看",
|
||||||
"please_enter_valid_days": "请输入有效的天数",
|
"Please_enter_valid_days": "请输入有效的天数",
|
||||||
"please_enter_a_non-negative_integer": "请输入一个非负整数",
|
"Please_enter_a_non-negative_integer": "请输入一个非负整数",
|
||||||
"please_enter_days": "请输入天数",
|
"Please_enter_days": "请输入天数",
|
||||||
"password_is_too_short": "密码长度太短",
|
"Password_is_too_short": "密码长度太短",
|
||||||
"passwords_do_not_match": "两次输入的密码不一致",
|
"Passwords_do_not_match": "两次输入的密码不一致",
|
||||||
"return_to_wiki_page": "返回维基页面",
|
"Return_to_wiki_page": "返回维基页面",
|
||||||
"insert_network_image": "插入网络图片",
|
"Insert_network_image": "插入网络图片",
|
||||||
"upload_local_image": "上传本地图片",
|
"Upload_local_image": "上传本地图片",
|
||||||
"add_link": "加入链接",
|
"Add_link": "加入链接",
|
||||||
"file_history": "文件历史",
|
"File_history": "文件历史",
|
||||||
"history_version": "历史版本",
|
"History_version": "历史版本",
|
||||||
"back_to_viewer": "返回查看页面",
|
"Back_to_viewer": "返回查看页面",
|
||||||
"link_title": "链接标题",
|
"Link_title": "链接标题",
|
||||||
"local_draft": "本地草稿",
|
"Local_draft": "本地草稿",
|
||||||
"use_draft": "使用草稿",
|
"Use_draft": "使用草稿",
|
||||||
"delete_draft": "删除草稿",
|
"Delete_draft": "删除草稿",
|
||||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "有未保存的草稿,使用草稿吗?",
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "有未保存的草稿,使用草稿吗?",
|
||||||
"local_draft_saved": "本地草稿已保存",
|
"Local_draft_saved": "本地草稿已保存",
|
||||||
"new_draft": "创建草稿",
|
"New_draft": "创建草稿",
|
||||||
"view_draft": "查看草稿",
|
"View_draft": "查看草稿",
|
||||||
"publish": "发布",
|
"Publish": "发布",
|
||||||
"this_file_has_a_draft": "这个文件有一个草稿.",
|
"This_file_has_a_draft": "这个文件有一个草稿.",
|
||||||
"delete": "删除",
|
"Delete": "删除",
|
||||||
"comments": "评论",
|
"Comments": "评论",
|
||||||
"add_a_comment": "增加评论",
|
"Add_a_comment": "增加评论",
|
||||||
"no_comment_yet": "还没有评论",
|
"No_comment_yet": "还没有评论",
|
||||||
"Mark_as_Resolved": "标记为已解决",
|
"Mark_as_Resolved": "标记为已解决",
|
||||||
"ask_for_review": "发起评审",
|
"Ask_for_review": "发起评审",
|
||||||
"review_already_exists": "评审已存在",
|
"Review_already_exists": "评审已存在",
|
||||||
"view_review": "查看评审",
|
"Ciew_review": "查看评审",
|
||||||
"there_is_an_associated_review_with_this_file": "有一个与此文件相关联的评审。",
|
"There_is_an_associated_review_with_this_file": "有一个与此文件相关联的评审。",
|
||||||
"start_review": "开始评审",
|
"Start_review": "开始评审",
|
||||||
"this_file_is_in_draft_stage": "该文件处于草稿阶段。",
|
"This_file_is_in_draft_stage": "该文件处于草稿阶段。",
|
||||||
"this_file_is_in_review_stage": "该文件处于评审阶段。",
|
"This_file_is_in_review_stage": "该文件处于评审阶段。",
|
||||||
"this_file_has_been_updated": "这个文件已被修改。",
|
"This_file_has_been_updated": "这个文件已被修改。",
|
||||||
"refresh": "刷新",
|
"Refresh": "刷新",
|
||||||
"related_files": "相关文件",
|
"Related_files": "相关文件",
|
||||||
"related_file": "相关文件",
|
"Related_file": "相关文件",
|
||||||
"no_tags": "没有标签",
|
"No_tags": "没有标签",
|
||||||
"date": "日期",
|
"Date": "日期",
|
||||||
"participants": "参与者",
|
"Participants": "参与人",
|
||||||
"no_related_files": "没有相关文件",
|
"Meeting_note": "会议记录",
|
||||||
"no_out_line": "没有大纲",
|
"Chooser_document_type": "选择文档类型",
|
||||||
|
"Empty": "空",
|
||||||
|
"No_related_files": "没有相关文件",
|
||||||
|
"No_out_line": "没有大纲",
|
||||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "在此浏览器中,编辑文件可能导致轻微的显示问题。",
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "在此浏览器中,编辑文件可能导致轻微的显示问题。",
|
||||||
"no_document_improvement_suggestion": "没有文档改进建议",
|
"no_document_improvement_suggestion": "没有文档改进建议",
|
||||||
"Hide_side_panel": "隐藏侧旁栏",
|
"Hide_side_panel": "隐藏侧旁栏",
|
||||||
@@ -128,24 +131,10 @@
|
|||||||
"Insert_library_image": "插入资料库图片",
|
"Insert_library_image": "插入资料库图片",
|
||||||
"Size": "大小",
|
"Size": "大小",
|
||||||
"Location": "位置",
|
"Location": "位置",
|
||||||
"Last_Update": "更新时间",
|
"Last_update": "更新时间",
|
||||||
"Tags": "标签",
|
"Tags": "标签",
|
||||||
"Related_Files": "相关文档",
|
"Related_Files": "相关文档",
|
||||||
"Add_participants": "增加文件参与人",
|
"Add_participants": "增加文件参与人",
|
||||||
"markdownLint": {
|
|
||||||
"missing_h1": {
|
|
||||||
"description": "文档缺少一级标题",
|
|
||||||
"issue" : "缺少一级标题"
|
|
||||||
},
|
|
||||||
"heading_end_with_colon": {
|
|
||||||
"description": "标题末尾的标点符号不应该是冒号",
|
|
||||||
"issue": "标题末尾是冒号"
|
|
||||||
},
|
|
||||||
"heading_increase_irregular": {
|
|
||||||
"description": "标题级别一次只能增加一级",
|
|
||||||
"issue": "标题级别不规范"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Shortcut_help": "快捷键帮助",
|
"Shortcut_help": "快捷键帮助",
|
||||||
"userHelp": {
|
"userHelp": {
|
||||||
"title": "键盘快捷键",
|
"title": "键盘快捷键",
|
||||||
@@ -180,40 +169,42 @@
|
|||||||
}, {
|
}, {
|
||||||
"shortcutType": "引用快捷键",
|
"shortcutType": "引用快捷键",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Make_Block_quote": "生成引用",
|
"Make_block_quote": "生成引用",
|
||||||
"Escape_Block_quote": "退出引用"
|
"Escape_block_quote": "退出引用"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"shortcutType": "表格快捷键",
|
"shortcutType": "表格快捷键",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Table_Row": "插入行",
|
"Insert_table_row": "插入行",
|
||||||
"Escape_table": "退出表格"
|
"Escape_table": "退出表格"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"shortcutType": "公式快捷键",
|
"shortcutType": "公式快捷键",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Insert_Formula": "插入公式"
|
"Insert_formula": "插入公式"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"shortcutType":"行级操作",
|
"shortcutType": "行内快捷键",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Bold": "粗体",
|
"Bold": "粗体",
|
||||||
"Italic": "斜体",
|
"Italic": "斜体",
|
||||||
"Italic_Bold": "斜体加粗",
|
"Italic_bold": "斜体粗体",
|
||||||
"Inline_code": "行内代码"
|
"Inline_code": "行内代码"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"shortcutType": "文件保存",
|
"shortcutType": "保存快捷键",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Save_file": "保存文件"
|
"Save_file": "保存文件"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"shortcutType": "图片操作",
|
"shortcutType": "图片快捷键",
|
||||||
"shortcutData": {
|
"shortcutData": {
|
||||||
"Paste_screen_shot": "上传截图",
|
"Paste_screen_shot": "粘贴屏幕截图",
|
||||||
"Drag_image_from_anywhere_to_upload_it": "拖拽任意图片上传"
|
"Drag_image_from_anywhere_to_upload_it": "从任意地方拖动图像以上传"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
}
|
}
|
||||||
|
210
media/locales/zh_CN /seafile-editor.json
Normal file
210
media/locales/zh_CN /seafile-editor.json
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
{
|
||||||
|
"Bold": "粗体",
|
||||||
|
"Italic": "斜体",
|
||||||
|
"Inline_code": "代码",
|
||||||
|
"Header_one": "一级标题",
|
||||||
|
"Header_two": "二级标题",
|
||||||
|
"Header_three": "三级标题",
|
||||||
|
"Header_four": "四级标题",
|
||||||
|
"Header_five": "五级标题",
|
||||||
|
"Header_six": "六级标题",
|
||||||
|
"Paragraph": "段落",
|
||||||
|
"Quote": "引用",
|
||||||
|
"Ordered_list": "有序列表",
|
||||||
|
"Unordered_list": "无序列表",
|
||||||
|
"Check_list_item": "任务列表",
|
||||||
|
"Insert_image": "插入图片",
|
||||||
|
"Insert_formula": "插入公式",
|
||||||
|
"Formula": "公式",
|
||||||
|
"Insert_file": "插入文件",
|
||||||
|
"Code": "行内代码",
|
||||||
|
"Code_block": "代码块",
|
||||||
|
"Insert_link": "添加链接",
|
||||||
|
"Insert_table": "添加表格",
|
||||||
|
"Save": "保存",
|
||||||
|
"More": "更多",
|
||||||
|
"Invalid_url": "无效链接",
|
||||||
|
"Link_address": "链接地址",
|
||||||
|
"Image_address": "图片地址",
|
||||||
|
"Submit": "提交",
|
||||||
|
"Cancel": "取消",
|
||||||
|
"Switch_to_plain_text_editor": "切换至普通文本编辑器",
|
||||||
|
"Switch_to_rich_text_editor": "切换至富文本编辑器",
|
||||||
|
"Switch_to_viewer": "切换到只读模式",
|
||||||
|
"Help": "帮助",
|
||||||
|
"Remove_table": "删除表格",
|
||||||
|
"Column": "列",
|
||||||
|
"Row": "行",
|
||||||
|
"Insert_row_before": "上方插入行",
|
||||||
|
"Insert_row_after": "下方插入行",
|
||||||
|
"Insert_column_before": "左边插入列",
|
||||||
|
"Insert_column_after": "右边插入列",
|
||||||
|
"Remove_row": "删除当前行",
|
||||||
|
"Remove_column": "删除当前列",
|
||||||
|
"Insert_row": "插入行",
|
||||||
|
"Insert_column": "插入列",
|
||||||
|
"Set_align": "对齐方式",
|
||||||
|
"Left": "左对齐",
|
||||||
|
"Center": "居中",
|
||||||
|
"Right": "右对齐",
|
||||||
|
"File_saved": "保存文件成功",
|
||||||
|
"File_failed_to_save": "保存文件失败",
|
||||||
|
"Star": "添加星标",
|
||||||
|
"Unstar": "移除星标",
|
||||||
|
"Back_to_parent_directory": "返回上级目录",
|
||||||
|
"Edit": "编辑",
|
||||||
|
"Copy": "复制",
|
||||||
|
"Copied": "已复制",
|
||||||
|
"Internal_link": "内部链接",
|
||||||
|
"Copy_internal_link": "内部链接已复制到剪贴板",
|
||||||
|
"Internal_link_desc": "内部链接是指向文件或目录的链接,只有对该文件或目录有访问权限的人可以访问。",
|
||||||
|
"Share": "共享",
|
||||||
|
"Share_link": "共享链接",
|
||||||
|
"Generate": "生成链接",
|
||||||
|
"Add_password_protection": "增加密码保护",
|
||||||
|
"Password": "密码",
|
||||||
|
"At_least_8_characters": "至少8个字符",
|
||||||
|
"Password_again": "请再次输入密码",
|
||||||
|
"Add_auto_expiration": "增加自动过期",
|
||||||
|
"Days": "天",
|
||||||
|
"Please_enter_password": "请输入密码",
|
||||||
|
"Greater_than_or_equal_to": "大于或等于",
|
||||||
|
"Less_than_or_equal_to": "小于或等于",
|
||||||
|
"Set_permission": "设置权限",
|
||||||
|
"Preview_and_download": "预览与下载",
|
||||||
|
"Preview_only": "仅查看",
|
||||||
|
"Please_enter_valid_days": "请输入有效的天数",
|
||||||
|
"Please_enter_a_non-negative_integer": "请输入一个非负整数",
|
||||||
|
"Please_enter_days": "请输入天数",
|
||||||
|
"Password_is_too_short": "密码长度太短",
|
||||||
|
"Passwords_do_not_match": "两次输入的密码不一致",
|
||||||
|
"Return_to_wiki_page": "返回维基页面",
|
||||||
|
"Insert_network_image": "插入网络图片",
|
||||||
|
"Upload_local_image": "上传本地图片",
|
||||||
|
"Add_link": "加入链接",
|
||||||
|
"File_history": "文件历史",
|
||||||
|
"History_version": "历史版本",
|
||||||
|
"Back_to_viewer": "返回查看页面",
|
||||||
|
"Link_title": "链接标题",
|
||||||
|
"Local_draft": "本地草稿",
|
||||||
|
"Use_draft": "使用草稿",
|
||||||
|
"Delete_draft": "删除草稿",
|
||||||
|
"You_have_an_unsaved_draft_do_you_like_to_use_it": "有未保存的草稿,使用草稿吗?",
|
||||||
|
"Local_draft_saved": "本地草稿已保存",
|
||||||
|
"New_draft": "创建草稿",
|
||||||
|
"View_draft": "查看草稿",
|
||||||
|
"Publish": "发布",
|
||||||
|
"This_file_has_a_draft": "这个文件有一个草稿.",
|
||||||
|
"Delete": "删除",
|
||||||
|
"Comments": "评论",
|
||||||
|
"Add_a_comment": "增加评论",
|
||||||
|
"No_comment_yet": "还没有评论",
|
||||||
|
"Mark_as_Resolved": "标记为已解决",
|
||||||
|
"Ask_for_review": "发起评审",
|
||||||
|
"Review_already_exists": "评审已存在",
|
||||||
|
"Ciew_review": "查看评审",
|
||||||
|
"There_is_an_associated_review_with_this_file": "有一个与此文件相关联的评审。",
|
||||||
|
"Start_review": "开始评审",
|
||||||
|
"This_file_is_in_draft_stage": "该文件处于草稿阶段。",
|
||||||
|
"This_file_is_in_review_stage": "该文件处于评审阶段。",
|
||||||
|
"This_file_has_been_updated": "这个文件已被修改。",
|
||||||
|
"Refresh": "刷新",
|
||||||
|
"Related_files": "相关文件",
|
||||||
|
"Related_file": "相关文件",
|
||||||
|
"No_tags": "没有标签",
|
||||||
|
"Date": "日期",
|
||||||
|
"Participants": "参与人",
|
||||||
|
"Meeting_note": "会议记录",
|
||||||
|
"Chooser_document_type": "选择文档类型",
|
||||||
|
"Empty": "空",
|
||||||
|
"No_related_files": "没有相关文件",
|
||||||
|
"No_out_line": "没有大纲",
|
||||||
|
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "在此浏览器中,编辑文件可能导致轻微的显示问题。",
|
||||||
|
"no_document_improvement_suggestion": "没有文档改进建议",
|
||||||
|
"Hide_side_panel": "隐藏侧旁栏",
|
||||||
|
"Show_side_panel": "显示侧旁栏",
|
||||||
|
"Show_resolved_comments": "显示已解决的评论",
|
||||||
|
"Update": "更新",
|
||||||
|
"Width": "宽度",
|
||||||
|
"Height": "高度",
|
||||||
|
"Full_screen": "全屏",
|
||||||
|
"Insert_library_image": "插入资料库图片",
|
||||||
|
"Size": "大小",
|
||||||
|
"Location": "位置",
|
||||||
|
"Last_update": "更新时间",
|
||||||
|
"Tags": "标签",
|
||||||
|
"Related_Files": "相关文档",
|
||||||
|
"Add_participants": "增加文件参与人",
|
||||||
|
"Shortcut_help": "快捷键帮助",
|
||||||
|
"userHelp": {
|
||||||
|
"title": "键盘快捷键",
|
||||||
|
"userHelpData": [
|
||||||
|
{
|
||||||
|
"shortcutType": "列表快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Make_list": "生成列表",
|
||||||
|
"Make_ordered_list": "生成有序列表",
|
||||||
|
"Insert_new_item": "插入列表项",
|
||||||
|
"Insert_child_in_item": "插入新段落",
|
||||||
|
"Increase_depth": "增加列表项深度"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"shortcutType": "标题快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Heading_1": "一级标题",
|
||||||
|
"Heading_2": "二级标题",
|
||||||
|
"Heading_3": "三级标题",
|
||||||
|
"Heading_4": "四级标题",
|
||||||
|
"Heading_5": "五级标题",
|
||||||
|
"Heading_6": "六级标题"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"shortcutType": "代码块快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Make_code_block": "生成代码块",
|
||||||
|
"Insert_new_line": "插入行",
|
||||||
|
"Escape_code_block": "退出代码块",
|
||||||
|
"Insert_indent": "缩进"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"shortcutType": "引用快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Make_block_quote": "生成引用",
|
||||||
|
"Escape_block_quote": "退出引用"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"shortcutType": "表格快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Insert_table_row": "插入行",
|
||||||
|
"Escape_table": "退出表格"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"shortcutType": "公式快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Insert_formula": "插入公式"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"shortcutType": "行内快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Bold": "粗体",
|
||||||
|
"Italic": "斜体",
|
||||||
|
"Italic_bold": "斜体粗体",
|
||||||
|
"Inline_code": "行内代码"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"shortcutType": "保存快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Save_file": "保存文件"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"shortcutType": "图片快捷键",
|
||||||
|
"shortcutData": {
|
||||||
|
"Paste_screen_shot": "粘贴屏幕截图",
|
||||||
|
"Drag_image_from_anywhere_to_upload_it": "从任意地方拖动图像以上传"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Select_field": "Select field",
|
||||||
|
"Font_style": "Font style"
|
||||||
|
}
|
Reference in New Issue
Block a user