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';
|
||||
|
||||
const fs = require('fs');
|
||||
@@ -20,7 +21,7 @@ const getClientEnvironment = require('./env');
|
||||
const paths = require('./paths');
|
||||
const modules = require('./modules');
|
||||
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 ForkTsCheckerWebpackPlugin =
|
||||
@@ -608,7 +609,7 @@ module.exports = function (webpackEnv) {
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
process: "process/browser.js",
|
||||
process: 'process/browser.js',
|
||||
}),
|
||||
new NodePolyfillPlugin({
|
||||
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/sdoc-editor": "0.3.23",
|
||||
"@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/react-codemirror": "^4.19.4",
|
||||
"classnames": "^2.2.6",
|
||||
@@ -17,9 +17,9 @@
|
||||
"crypto-js": "4.2.0",
|
||||
"deep-copy": "1.4.2",
|
||||
"glamor": "^2.20.40",
|
||||
"i18next": "22.4.6",
|
||||
"i18next-browser-languagedetector": "7.0.1",
|
||||
"i18next-xhr-backend": "3.2.2",
|
||||
"i18next": "^17.0.13",
|
||||
"i18next-browser-languagedetector": "^3.0.3",
|
||||
"i18next-xhr-backend": "^3.1.2",
|
||||
"is-hotkey": "0.2.0",
|
||||
"MD5": "^1.3.0",
|
||||
"moment": "^2.22.2",
|
||||
@@ -32,7 +32,7 @@
|
||||
"react-chartjs-2": "^2.8.0",
|
||||
"react-cookies": "^0.1.0",
|
||||
"react-dom": "17.0.0",
|
||||
"react-i18next": "12.1.1",
|
||||
"react-i18next": "^10.12.2",
|
||||
"react-responsive": "9.0.2",
|
||||
"react-select": "5.7.0",
|
||||
"react-transition-group": "4.4.5",
|
||||
|
@@ -2,7 +2,7 @@ import i18n from 'i18next';
|
||||
import Backend from 'i18next-xhr-backend';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import { mediaUrl } from './utils/constants';
|
||||
import { mediaUrl } from '../utils/constants';
|
||||
|
||||
const lang = window.app.pageOptions.lang;
|
||||
|
||||
@@ -14,7 +14,7 @@ i18n
|
||||
lng: lang,
|
||||
fallbackLng: 'en',
|
||||
ns: ['seafile-editor'],
|
||||
defaultNS: 'translations',
|
||||
defaultNS: 'seafile-editor',
|
||||
|
||||
whitelist: ['en', 'zh-CN', 'fr', 'de', 'cs', 'es', 'es-AR', 'es-MX', 'ru'],
|
||||
|
@@ -13,6 +13,14 @@ const propTypes = {
|
||||
|
||||
class TermsEditorDialog extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isValueChanged: false,
|
||||
};
|
||||
this.editorRef = React.createRef();
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
title: gettext('Terms'),
|
||||
};
|
||||
@@ -22,20 +30,20 @@ class TermsEditorDialog extends React.Component {
|
||||
};
|
||||
|
||||
toggle = () => {
|
||||
if (this.isContentChanged()) {
|
||||
const { isValueChanged } = this.state;
|
||||
if (isValueChanged) {
|
||||
let currentContent = this.getCurrentContent();
|
||||
this.props.onCommit(currentContent);
|
||||
}
|
||||
this.props.onCloseEditorDialog();
|
||||
};
|
||||
|
||||
isContentChanged = () => {
|
||||
return this.simpleEditor.hasContentChange();
|
||||
onContentChanged = () => {
|
||||
return this.setState({isValueChanged: true});
|
||||
};
|
||||
|
||||
getCurrentContent = () => {
|
||||
let markdownContent = this.simpleEditor.getMarkdown();
|
||||
return markdownContent;
|
||||
return this.editorRef.current.getValue();
|
||||
};
|
||||
|
||||
setSimpleEditorRef = (editor) => {
|
||||
@@ -58,8 +66,9 @@ class TermsEditorDialog extends React.Component {
|
||||
<ModalHeader className="conditions-editor-dialog-title" toggle={this.toggle}>{title}</ModalHeader>
|
||||
<ModalBody className={'conditions-editor-dialog-main'}>
|
||||
<SimpleEditor
|
||||
onRef={this.setSimpleEditorRef.bind(this)}
|
||||
ref={this.editorRef}
|
||||
value={content || ''}
|
||||
onContentChanged={this.onContentChanged}
|
||||
/>
|
||||
</ModalBody>
|
||||
</Modal>
|
||||
|
@@ -9,15 +9,14 @@ const { fileContent } = window.app.pageOptions;
|
||||
class FileContent extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="file-view-content flex-1 o-auto">
|
||||
<div className="md-content">
|
||||
<div className="file-view-content md-content">
|
||||
<MarkdownViewer
|
||||
markdownContent={fileContent}
|
||||
showTOC={false}
|
||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
isFetching={false}
|
||||
value={fileContent}
|
||||
isShowOutline={false}
|
||||
mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
/>
|
||||
</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 PropTypes from 'prop-types';
|
||||
import { MarkdownViewer } from '@seafile/seafile-editor';
|
||||
import { gettext, repoID, slug, serviceURL, isPublicWiki, sharedToken, mediaUrl } from '../utils/constants';
|
||||
import { EXTERNAL_EVENTS, EventBus, MarkdownViewer } from '@seafile/seafile-editor';
|
||||
import { gettext, isPublicWiki, mediaUrl, repoID, serviceURL, sharedToken, slug } from '../utils/constants';
|
||||
import Loading from './loading';
|
||||
import { Utils } from '../utils/utils';
|
||||
|
||||
@@ -25,109 +25,30 @@ class WikiMarkdownViewer extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
activeTitleIndex: 0,
|
||||
};
|
||||
this.markdownContainer = React.createRef();
|
||||
this.links = [];
|
||||
this.titlesInfo = [];
|
||||
this.scrollRef = React.createRef();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// Bind event when first loaded
|
||||
this.links = document.querySelectorAll(`.${contentClass} a`);
|
||||
this.links.forEach(link => {
|
||||
link.addEventListener('click', this.onLinkClick);
|
||||
});
|
||||
|
||||
this.getTitlesInfo();
|
||||
const eventBus = EventBus.getInstance();
|
||||
this.unsubscribeLinkClick = eventBus.subscribe(EXTERNAL_EVENTS.ON_LINK_CLICK, this.onLinkClick);
|
||||
}
|
||||
|
||||
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() {
|
||||
// Unbound events when the component is destroyed
|
||||
this.links.forEach(link => {
|
||||
link.removeEventListener('click', this.onLinkClick);
|
||||
});
|
||||
this.unsubscribeLinkClick();
|
||||
}
|
||||
|
||||
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) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
let link = '';
|
||||
if (event.target.tagName !== 'A') {
|
||||
let target = event.target.parentNode;
|
||||
while (target.tagName !== 'A') {
|
||||
let target = event.target;
|
||||
while (!target.dataset || !target.dataset.url) {
|
||||
target = target.parentNode;
|
||||
}
|
||||
link = target.href;
|
||||
} else {
|
||||
link = event.target.href;
|
||||
}
|
||||
if (!target) return;
|
||||
link = target.dataset.url;
|
||||
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) => {
|
||||
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;
|
||||
} 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.isInternalMarkdownLink(url, repoID)) {
|
||||
let path = Utils.getPathFromInternalMarkdownLink(url, repoID);
|
||||
// replace url
|
||||
item.data.href = serviceURL + '/published/' + slug + path;
|
||||
item.url = serviceURL + '/published/' + slug + path;
|
||||
} 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`;
|
||||
});
|
||||
}
|
||||
} else if (Utils.isInternalDirLink(url, repoID)) { // change dir url
|
||||
let path = Utils.getPathFromInternalDirLink(url, repoID);
|
||||
// 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 = () => {
|
||||
let isTOCShow = true;
|
||||
if (this.props.isTOCShow === false) {
|
||||
isTOCShow = false;
|
||||
}
|
||||
if (this.props.isWiki) {
|
||||
return (
|
||||
<MarkdownViewer
|
||||
showTOC={isTOCShow}
|
||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
markdownContent={this.props.markdownContent}
|
||||
activeTitleIndex={this.state.activeTitleIndex}
|
||||
modifyValueBeforeRender={this.modifyValueBeforeRender}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const { isTOCShow = true, isWiki, markdownContent } = this.props;
|
||||
const props = {
|
||||
isShowOutline: isTOCShow,
|
||||
mathJaxSource: `${mediaUrl}js/mathjax/tex-svg.js`,
|
||||
value: markdownContent,
|
||||
scrollRef: this.scrollRef,
|
||||
...(isWiki && {beforeRenderCallback: this.modifyValueBeforeRender})
|
||||
};
|
||||
|
||||
return (
|
||||
<MarkdownViewer
|
||||
showTOC={isTOCShow}
|
||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
markdownContent={this.props.markdownContent}
|
||||
activeTitleIndex={this.state.activeTitleIndex}
|
||||
/>
|
||||
);
|
||||
return <MarkdownViewer {...props} />;
|
||||
};
|
||||
|
||||
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%
|
||||
let contentClassName = `${this.props.repoID ? contentClass + ' w-100' : contentClass}`;
|
||||
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}>
|
||||
{this.props.children}
|
||||
{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 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@@ -29,20 +29,20 @@
|
||||
}
|
||||
|
||||
.content-viewer {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.content-viewer .sf-slate-viewer-scroll-container {
|
||||
background-color: #fafaf9;
|
||||
border-radius: 10px;
|
||||
overflow: auto;
|
||||
padding: 20px 40px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.markdown-viewer-render-content {
|
||||
background-color: #fff;
|
||||
word-break: break-word;
|
||||
margin: 20px 40px;
|
||||
border: 1px solid #e6e6dd;
|
||||
}
|
||||
|
||||
.markdown-viewer-render-content .diff-view {
|
||||
padding: 40px 60px;
|
||||
.content-viewer .sf-slate-viewer-article-container .article {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
@@ -124,10 +124,14 @@
|
||||
.history-content .main-panel {
|
||||
max-width: 100%;
|
||||
}
|
||||
.markdown-viewer-render-content {
|
||||
margin: 20px;
|
||||
.content-viewer .sf-slate-viewer-scroll-container {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -205,8 +205,17 @@
|
||||
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 {
|
||||
margin: 0;
|
||||
padding: 0 10px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.wiki-page-content a {
|
||||
|
@@ -1,3 +1,8 @@
|
||||
html, body, #root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -168,3 +173,10 @@
|
||||
margin-left: 0.5rem;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.sf-md-viewer-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
}
|
@@ -1,9 +1,14 @@
|
||||
.md-content {
|
||||
box-shadow: 0 0 6px #ccc;
|
||||
border: 1px solid #ccc;
|
||||
padding: 70px 75px;
|
||||
width: calc(100% - 40px);
|
||||
max-width: 950px;
|
||||
background: #fff;
|
||||
margin: 0 auto;
|
||||
.file-view-content.md-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #f4f4f4;
|
||||
border-right: none;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.shared-file-view-body .article {
|
||||
min-height: calc(100% - 15px);
|
||||
background: #fff;
|
||||
padding: 40px 60px;
|
||||
margin: 0 340px 15px 40px;
|
||||
border: 1px solid #e6e6dd;
|
||||
.shared-file-view-body.md-view {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.shared-file-view-body .article-no-outline {
|
||||
max-width: 950px;
|
||||
margin: 0 auto 15px;
|
||||
}
|
||||
|
||||
.shared-file-view-body .seafile-markdown-outline {
|
||||
width: 300px;
|
||||
top: 145px;
|
||||
bottom: 30px;
|
||||
height: auto;
|
||||
.shared-file-view-body .sf-slate-viewer-outline {
|
||||
top: 145px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 991.98px) {
|
||||
@@ -73,27 +63,4 @@
|
||||
width: 100%;
|
||||
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 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';
|
||||
|
||||
const URL = require('url-parse');
|
||||
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 = () => {
|
||||
export default function Draft() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.isShowDiff ?
|
||||
<DiffViewer
|
||||
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 style={{display: 'flex', flex: 1, flexDirection: 'column', justifyContent: 'center', alignItems: 'center'}}>
|
||||
<h1>Draft module</h1>
|
||||
<div>The current module is no longer supported</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'));
|
||||
|
@@ -31,19 +31,6 @@ class FileHistory extends React.Component {
|
||||
|
||||
onHistoryItemClick = (item, preItem)=> {
|
||||
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) => {
|
||||
axios.all([
|
||||
seafileAPI.getFileContent(res.data),
|
||||
@@ -51,7 +38,6 @@ class FileHistory extends React.Component {
|
||||
this.setDiffContent(content1.data, '');
|
||||
}));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onBackClick = (event) => {
|
||||
|
@@ -1,15 +1,18 @@
|
||||
// Import React!
|
||||
import React from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
import ReactDom from 'react-dom';
|
||||
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 Loading from './components/loading';
|
||||
|
||||
import './index.css';
|
||||
|
||||
ReactDom.render(
|
||||
<I18nextProvider i18n={ i18n } >
|
||||
<Suspense fallback={<Loading />}>
|
||||
<MarkdownEditor />
|
||||
</Suspense>
|
||||
</I18nextProvider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
@@ -1,11 +1,10 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Prism from 'prismjs';
|
||||
import { DiffViewer } from '@seafile/seafile-editor';
|
||||
import { MarkdownViewer } from '@seafile/seafile-editor';
|
||||
import Loading from '../../components/loading';
|
||||
import { mediaUrl } from '../../utils/constants';
|
||||
|
||||
const contentClass = 'markdown-viewer-render-content';
|
||||
const propTypes = {
|
||||
renderingContent: PropTypes.bool.isRequired,
|
||||
content: PropTypes.string,
|
||||
@@ -24,19 +23,18 @@ class MainPanel extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { renderingContent, newMarkdownContent } = this.props;
|
||||
return (
|
||||
<div className="content-viewer flex-fill">
|
||||
<div className={contentClass}>
|
||||
{this.props.renderingContent ?
|
||||
(<Loading />) :
|
||||
(<div className="diff-view article">
|
||||
<DiffViewer
|
||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
newMarkdownContent={this.props.newMarkdownContent}
|
||||
oldMarkdownContent={this.props.oldMarkdownContent}
|
||||
{renderingContent && <Loading />}
|
||||
{!renderingContent && (
|
||||
<MarkdownViewer
|
||||
isFetching={renderingContent}
|
||||
value={newMarkdownContent}
|
||||
isShowOutline={false}
|
||||
mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
/>
|
||||
</div>)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@@ -23,3 +23,7 @@
|
||||
.collab-users-dropdown.dropdown {
|
||||
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 libName = encodeURIComponent(repoName);
|
||||
let path = Utils.encodePath(parentPath);
|
||||
|
@@ -23,7 +23,6 @@ const propTypes = {
|
||||
onEdit: PropTypes.func.isRequired,
|
||||
toggleNewDraft: PropTypes.func.isRequired,
|
||||
toggleStar: PropTypes.func.isRequired,
|
||||
openParentDirectory: PropTypes.func.isRequired,
|
||||
openDialogs: PropTypes.func.isRequired,
|
||||
showFileHistory: PropTypes.bool.isRequired,
|
||||
toggleHistory: PropTypes.func.isRequired,
|
||||
@@ -31,6 +30,7 @@ const propTypes = {
|
||||
readOnly: PropTypes.bool.isRequired,
|
||||
contentChanged: PropTypes.bool.isRequired,
|
||||
saving: PropTypes.bool.isRequired,
|
||||
onSaveEditorContent: PropTypes.func.isRequired,
|
||||
showDraftSaved: PropTypes.bool.isRequired,
|
||||
isLocked: 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)}`;
|
||||
};
|
||||
|
||||
openParentDirectory = () => {
|
||||
const { editorApi } = this.props;
|
||||
window.location.href = editorApi.getParentDictionaryUrl();
|
||||
};
|
||||
|
||||
render() {
|
||||
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') {
|
||||
return (
|
||||
@@ -71,27 +74,7 @@ class HeaderToolbar extends React.Component {
|
||||
mediaUrl={mediaUrl}
|
||||
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">
|
||||
{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) &&
|
||||
<CollabUsersButton
|
||||
className="collab-users-dropdown"
|
||||
@@ -100,24 +83,43 @@ class HeaderToolbar extends React.Component {
|
||||
/>
|
||||
}
|
||||
<ButtonGroup>
|
||||
<ButtonItem text={gettext('Open parent directory')} id={'parentDirectory'}
|
||||
icon={'fa fa-folder-open'} onMouseDown={this.props.openParentDirectory}/>
|
||||
{(canLockUnlockFile && !isLocked) &&
|
||||
<ButtonItem id="lock-unlock-file" icon='fa fa-lock' 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}/>
|
||||
}
|
||||
<ButtonItem
|
||||
text={gettext('Open parent directory')}
|
||||
id={'parentDirectory'}
|
||||
icon={'fa fa-folder-open'}
|
||||
onMouseDown={this.openParentDirectory}
|
||||
/>
|
||||
{(canLockUnlockFile && !isLocked) && (
|
||||
<ButtonItem
|
||||
id="lock-unlock-file"
|
||||
icon='fa fa-lock'
|
||||
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 ?
|
||||
<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}
|
||||
onMouseDown={window.seafileEditor && window.seafileEditor.onRichEditorSave} isActive={contentChanged}/>
|
||||
onMouseDown={this.props.onSaveEditorContent} isActive={contentChanged}/>
|
||||
}
|
||||
{canDownloadFile && (
|
||||
<ButtonItem
|
||||
@@ -127,14 +129,14 @@ class HeaderToolbar extends React.Component {
|
||||
onClick={this.downloadFile}
|
||||
/>
|
||||
)}
|
||||
{this.props.fileInfo.permission == 'rw' &&
|
||||
{this.props.fileInfo.permission == 'rw' && (
|
||||
<ButtonItem
|
||||
id="open-via-client"
|
||||
icon="sf3-font sf3-font-desktop"
|
||||
text={gettext('Open via Client')}
|
||||
onClick={this.openFileViaClient}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</ButtonGroup>
|
||||
<MoreMenu
|
||||
readOnly={this.props.readOnly}
|
||||
@@ -170,7 +172,7 @@ class HeaderToolbar extends React.Component {
|
||||
editorMode={this.props.editorMode}
|
||||
onEdit={this.props.onEdit}
|
||||
toggleShareLinkDialog={this.props.toggleShareLinkDialog}
|
||||
openParentDirectory={this.props.openParentDirectory}
|
||||
openParentDirectory={this.openParentDirectory}
|
||||
showFileHistory={this.props.showFileHistory}
|
||||
toggleHistory={this.props.toggleHistory}
|
||||
isSmallScreen={true}
|
||||
@@ -179,7 +181,9 @@ class HeaderToolbar extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (this.props.editorMode === 'plain') {
|
||||
}
|
||||
|
||||
if (this.props.editorMode === 'plain') {
|
||||
return (
|
||||
<div className="sf-md-viewer-topbar">
|
||||
<div className="sf-md-viewer-topbar-first d-flex justify-content-between">
|
||||
@@ -196,7 +200,8 @@ class HeaderToolbar extends React.Component {
|
||||
<ButtonGroup>
|
||||
{saving ?
|
||||
<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} />
|
||||
}
|
||||
@@ -238,10 +243,11 @@ class HeaderToolbar extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EXTERNAL_EVENTS, EventBus } from '@seafile/seafile-editor';
|
||||
import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem, Tooltip } from 'reactstrap';
|
||||
import { gettext, canGenerateShareLink } from '../../../utils/constants';
|
||||
|
||||
@@ -35,6 +36,11 @@ class MoreMenu extends React.PureComponent {
|
||||
this.setState({ dropdownOpen: !this.state.dropdownOpen });
|
||||
};
|
||||
|
||||
onHelpModuleToggle = (event) => {
|
||||
const eventBus = EventBus.getInstance();
|
||||
eventBus.dispatch(EXTERNAL_EVENTS.ON_HELP_INFO_TOGGLE, true);
|
||||
};
|
||||
|
||||
downloadFile = () => {
|
||||
location.href = '?dl=1';
|
||||
};
|
||||
@@ -51,18 +57,18 @@ class MoreMenu extends React.PureComponent {
|
||||
</DropdownToggle>
|
||||
<DropdownMenu className="drop-list" right={true}>
|
||||
{(!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') &&
|
||||
<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 &&
|
||||
<DropdownItem onMouseDown={this.props.toggleHistory}>{gettext('History')}</DropdownItem>}
|
||||
<DropdownItem onClick={this.props.toggleHistory}>{gettext('History')}</DropdownItem>}
|
||||
{(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 && canGenerateShareLink && <DropdownItem onMouseDown={this.props.toggleShareLinkDialog}>{gettext('Share')}</DropdownItem>}
|
||||
{isSmall && <DropdownItem onClick={this.props.openParentDirectory}>{gettext('Open parent directory')}</DropdownItem>}
|
||||
{isSmall && canGenerateShareLink && <DropdownItem onClick={this.props.toggleShareLinkDialog}>{gettext('Share')}</DropdownItem>}
|
||||
{(isSmall && this.props.showFileHistory) &&
|
||||
<DropdownItem onMouseDown={this.props.toggleHistory}>{gettext('History')}</DropdownItem>
|
||||
<DropdownItem onClick={this.props.toggleHistory}>{gettext('History')}</DropdownItem>
|
||||
}
|
||||
{isSmall && canDownloadFile &&
|
||||
<DropdownItem onClick={this.downloadFile}>{gettext('Download')}</DropdownItem>
|
||||
|
@@ -1,21 +1,21 @@
|
||||
import React, { Fragment } from 'react';
|
||||
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 { seafileAPI } from '../../utils/seafile-api';
|
||||
import { gettext, isDocs, mediaUrl } from '../../utils/constants';
|
||||
import toaster from '../../components/toast';
|
||||
import ShareDialog from '../../components/dialog/share-dialog';
|
||||
import InsertFileDialog from '../../components/dialog/insert-file-dialog';
|
||||
import LocalDraftDialog from '../../components/dialog/local-draft-dialog';
|
||||
import HeaderToolbar from './header-toolbar';
|
||||
import SeafileEditor from './seafile-editor';
|
||||
import editorApi from './editor-api';
|
||||
import DetailListView from './detail-list-view';
|
||||
|
||||
import '../../css/markdown-viewer/markdown-editor.css';
|
||||
|
||||
const CryptoJS = require('crypto-js');
|
||||
const URL = require('url-parse');
|
||||
|
||||
const { repoID, filePath, fileName, draftID, isDraft, hasDraft, isLocked, lockedByMe } = window.app.pageOptions;
|
||||
const { siteRoot, serviceUrl, seafileCollabServer } = window.app.config;
|
||||
const userInfo = window.app.userInfo;
|
||||
@@ -75,6 +75,9 @@ class MarkdownEditor extends React.Component {
|
||||
this.socket_id = socket.id;
|
||||
});
|
||||
}
|
||||
this.editorRef = React.createRef();
|
||||
this.isParticipant = false;
|
||||
this.editorSelection = null;
|
||||
}
|
||||
|
||||
toggleLockFile = () => {
|
||||
@@ -121,6 +124,8 @@ class MarkdownEditor extends React.Component {
|
||||
|
||||
|
||||
receivePresenceData(data) {
|
||||
let collabUsers = [];
|
||||
let editingUsers = [];
|
||||
switch(data.response) {
|
||||
case 'user_join':
|
||||
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;
|
||||
case 'user_editing':
|
||||
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 = () => {
|
||||
let draftKey = editorApi.getDraftKey();
|
||||
let draft = localStorage.getItem(draftKey);
|
||||
@@ -227,9 +230,6 @@ class MarkdownEditor extends React.Component {
|
||||
|
||||
openDialogs = (option) => {
|
||||
switch (option) {
|
||||
case 'help':
|
||||
window.richMarkdownEditor.showHelpDialog();
|
||||
break;
|
||||
case 'share_link':
|
||||
this.setState({
|
||||
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() {
|
||||
|
||||
const fileIcon = Utils.getFileIconUrl(fileName, 192);
|
||||
@@ -276,7 +264,6 @@ class MarkdownEditor extends React.Component {
|
||||
// get file content
|
||||
const fileContentRes = await seafileAPI.getFileContent(downloadUrl);
|
||||
const markdownContent = fileContentRes.data;
|
||||
const value = deserialize(markdownContent);
|
||||
|
||||
// init permission
|
||||
let hasPermission = permission === 'rw' || permission === 'cloud-edit';
|
||||
@@ -300,7 +287,7 @@ class MarkdownEditor extends React.Component {
|
||||
loading: false,
|
||||
fileInfo: {...fileInfo, mtime, size, starred, permission, lastModifier, id},
|
||||
markdownContent,
|
||||
value,
|
||||
value: '',
|
||||
readOnly: !hasPermission || hasDraft,
|
||||
});
|
||||
|
||||
@@ -333,8 +320,36 @@ class MarkdownEditor extends React.Component {
|
||||
window.location.href = url;
|
||||
}
|
||||
}, 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 = () => {
|
||||
seafileAPI.listFileTags(repoID, filePath).then(res => {
|
||||
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 = () => {
|
||||
this.openDialogs('share_link');
|
||||
};
|
||||
|
||||
onInsertImageToggle = (selection) => {
|
||||
this.editorSelection = selection;
|
||||
this.openDialogs('insert_file');
|
||||
};
|
||||
|
||||
toggleHistory = () => {
|
||||
window.location.href = siteRoot + 'repo/file_revisions/' + repoID + '/?p=' + Utils.encodePath(filePath);
|
||||
};
|
||||
|
||||
getInsertLink = (repoID, filePath) => {
|
||||
const selection = this.editorSelection;
|
||||
const fileName = Utils.getFileName(filePath);
|
||||
const suffix = fileName.slice(fileName.indexOf('.') + 1);
|
||||
const eventBus = EventBus.getInstance();
|
||||
if (IMAGE_SUFFIXES.includes(suffix)) {
|
||||
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;
|
||||
}
|
||||
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) => {
|
||||
this.setState({ contentChanged: value });
|
||||
addParticipants = () => {
|
||||
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) => {
|
||||
this.setState({ saving: value });
|
||||
onContentChanged = () => {
|
||||
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() {
|
||||
if (this.state.loading) {
|
||||
return (
|
||||
<div className="empty-loading-page">
|
||||
<div className="lds-ripple page-centered"><div></div><div></div></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const { loading, editorMode, markdownContent, fileInfo, fileTagList } = this.state;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
@@ -470,10 +483,9 @@ class MarkdownEditor extends React.Component {
|
||||
collabUsers={this.state.collabUsers}
|
||||
fileInfo={this.state.fileInfo}
|
||||
toggleStar={this.toggleStar}
|
||||
openParentDirectory={this.openParentDirectory}
|
||||
openDialogs={this.openDialogs}
|
||||
toggleShareLinkDialog={this.toggleShareLinkDialog}
|
||||
onEdit={this.onEdit}
|
||||
onEdit={this.setEditorMode}
|
||||
toggleNewDraft={editorApi.createDraftFile}
|
||||
showFileHistory={this.state.isShowHistory ? false : true }
|
||||
toggleHistory={this.toggleHistory}
|
||||
@@ -481,50 +493,28 @@ class MarkdownEditor extends React.Component {
|
||||
editorMode={this.state.editorMode}
|
||||
contentChanged={this.state.contentChanged}
|
||||
saving={this.state.saving}
|
||||
onSaveEditorContent={this.onSaveEditorContent}
|
||||
showDraftSaved={this.state.showDraftSaved}
|
||||
isLocked={this.state.isLocked}
|
||||
lockedByMe={this.state.lockedByMe}
|
||||
toggleLockFile={this.toggleLockFile}
|
||||
/>
|
||||
<SeafileEditor
|
||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
fileInfo={this.state.fileInfo}
|
||||
markdownContent={this.state.markdownContent}
|
||||
<div className='sf-md-viewer-content'>
|
||||
<RichMarkdownEditor
|
||||
ref={this.editorRef}
|
||||
mode={editorMode}
|
||||
isFetching={loading}
|
||||
initValue={fileName}
|
||||
value={markdownContent}
|
||||
editorApi={editorApi}
|
||||
collabUsers={this.state.collabUsers}
|
||||
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}
|
||||
onSave={this.onSaveEditorContent}
|
||||
onContentChanged={this.onContentChanged}
|
||||
onSaving={this.onSaving}
|
||||
contentChanged={this.state.contentChanged}
|
||||
fileTagList={this.state.fileTagList}
|
||||
onFileTagChanged={this.onFileTagChanged}
|
||||
participants={this.state.participants}
|
||||
onParticipantsChange={this.onParticipantsChange}
|
||||
markdownLint={fileName.toLowerCase() !== 'index.md'}
|
||||
/>
|
||||
{this.state.localDraftDialog &&
|
||||
<LocalDraftDialog
|
||||
localDraftDialog={this.state.localDraftDialog}
|
||||
deleteDraft={this.deleteDraft}
|
||||
closeDraftDialog={this.closeDraftDialog}
|
||||
useDraft={this.useDraft}
|
||||
/>
|
||||
}
|
||||
mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
isSupportInsertSeafileImage={true}
|
||||
>
|
||||
<DetailListView fileInfo={fileInfo} fileTagList={fileTagList} onFileTagChanged={this.onFileTagChanged}/>
|
||||
</RichMarkdownEditor>
|
||||
</div>
|
||||
{this.state.showMarkdownEditorDialog && (
|
||||
<React.Fragment>
|
||||
{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 { Modal } from 'reactstrap';
|
||||
import { Router } from '@gatsbyjs/reach-router';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { siteRoot } from '../../utils/constants';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import i18n from '../../_i18n/i18n-seafile-editor';
|
||||
|
||||
import SidePanel from './side-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 {
|
||||
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;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
@@ -9,14 +15,17 @@
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
}
|
||||
.wiki-nav-content-highlight a {
|
||||
text-decoration: none;
|
||||
color: #eb8205;
|
||||
}
|
||||
|
||||
.wiki-nav-content a:hover {
|
||||
text-decoration: none;
|
||||
color: #eb8205;
|
||||
}
|
||||
|
||||
.wiki-nav-content-highlight a {
|
||||
text-decoration: none;
|
||||
color: #eb8205;
|
||||
}
|
||||
|
||||
.switch-btn {
|
||||
position: absolute;
|
||||
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 { gettext, siteRoot, repoID, slug, username, permission } from '../../utils/constants';
|
||||
import Logo from '../../components/logo';
|
||||
import Loading from '../../components/loading';
|
||||
import TreeView from '../../components/tree-view/tree-view';
|
||||
import IndexContentViewer from '../../components/index-viewer';
|
||||
import IndexMdViewer from './index-md-viewer';
|
||||
|
||||
const propTypes = {
|
||||
closeSideBar: PropTypes.bool.isRequired,
|
||||
@@ -29,21 +29,18 @@ class SidePanel extends Component {
|
||||
|
||||
renderIndexView = () => {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="wiki-pages-container">
|
||||
<div style={{marginTop: '2px'}}></div>
|
||||
<IndexContentViewer
|
||||
<IndexMdViewer
|
||||
indexContent={this.props.indexContent}
|
||||
onLinkClick={this.props.onLinkClick}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
renderTreeView = () => {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="wiki-pages-container">
|
||||
{this.props.treeData && (
|
||||
<TreeView
|
||||
@@ -56,7 +53,6 @@ class SidePanel extends Component {
|
||||
/>
|
||||
)}
|
||||
</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);
|
||||
};
|
||||
|
||||
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() {
|
||||
if (err) {
|
||||
return <SharedFileViewTip />;
|
||||
@@ -82,21 +75,14 @@ class FileContent extends React.Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="shared-file-view-body">
|
||||
<div className="md-view">
|
||||
<div className="shared-file-view-body md-view">
|
||||
<MarkdownViewer
|
||||
scriptSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
markdownContent={this.state.markdownContent}
|
||||
showTOC={true}
|
||||
updateForNoOutline={this.updateForNoOutline}
|
||||
activeTitleIndex={''}
|
||||
serviceURL={serviceURL}
|
||||
sharedToken={sharedToken}
|
||||
repoID={repoID}
|
||||
modifyValueBeforeRender={this.modifyValueBeforeRender}
|
||||
value={this.state.markdownContent}
|
||||
isShowOutline={true}
|
||||
mathJaxSource={mediaUrl + 'js/mathjax/tex-svg.js'}
|
||||
beforeRenderCallback={this.modifyValueBeforeRender}
|
||||
/>
|
||||
</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 moment from 'moment';
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
import Wiki from './pages/wiki';
|
||||
|
||||
ReactDom.render(<Wiki />, document.getElementById('wrapper'));
|
||||
|
@@ -1,126 +1,126 @@
|
||||
{
|
||||
"bold": "Tučně",
|
||||
"italic": "Kurzíva",
|
||||
"inline_code": "Kód",
|
||||
"header_one": "Záhlaví 1",
|
||||
"header_two": "Záhlaví 2",
|
||||
"header_three": "Záhlaví 3",
|
||||
"header_four": "Záhlaví 4",
|
||||
"header_five": "Záhlaví 5",
|
||||
"header_six": "Záhlaví 6",
|
||||
"paragraph": "Odstavec",
|
||||
"quote": "Citace",
|
||||
"ordered_list": "Číslovaný seznam",
|
||||
"unordered_list": "Nečíslovaný seznam",
|
||||
"check_list_item": "Zkontrolovat položku seznamu",
|
||||
"insert_image": "Vložit obrázek",
|
||||
"insert_formula": "Insert Formula",
|
||||
"formula": "Formula",
|
||||
"insert_file": "Vložit soubor",
|
||||
"code": "Řádkový kód",
|
||||
"code_block": "Blok kódu",
|
||||
"insert_link": "Vložit odkaz",
|
||||
"insert_table": "Vložit tabulku",
|
||||
"save": "Uložit",
|
||||
"more": "Více",
|
||||
"invalid_url": "Chybná URL",
|
||||
"link_address": "Adresa odkazu",
|
||||
"image_address": "Adresa obrázku",
|
||||
"submit": "Odeslat",
|
||||
"cancel": "Storno",
|
||||
"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_viewer": "Přepnout do značkovacího prohlížeče",
|
||||
"help": "Pomoc",
|
||||
"remove_table": "Odebrat tabulku",
|
||||
"column": "Sloupec",
|
||||
"row": "Řádek",
|
||||
"Insert_Row_Before": "Vložit řádku před",
|
||||
"Insert_Row_After": "Vložit řádek za",
|
||||
"Insert_Column_Before": "Vložit sloupec před",
|
||||
"Insert_Column_After": "Vložit sloupec za",
|
||||
"Remove_Row": "Odstranit řádek",
|
||||
"Remove_Column": "Odstranit sloupec",
|
||||
"Insert_Row": "Vložit řádek",
|
||||
"Insert_Column": "Vložit sloupec",
|
||||
"set_align": "Nastavit zarovnání",
|
||||
"left": "Vlevo",
|
||||
"center": "Střed",
|
||||
"right": "Vpravo",
|
||||
"file_saved": "Soubor uložen",
|
||||
"file_failed_to_save": "Soubor nebyl uložen",
|
||||
"star": "Přidat hvězdičku",
|
||||
"unstar": "Odebrat hvězdičku",
|
||||
"back_to_parent_directory":"Zpět do nadřazeného adresáře",
|
||||
"edit": "Upravit",
|
||||
"copy": "Kopírovat",
|
||||
"copied": "Zkopírováno",
|
||||
"internal_link": "Interní odkaz",
|
||||
"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í.",
|
||||
"share": "Sdílet",
|
||||
"share_link": "Veřejný odkaz",
|
||||
"generate": "Generovat",
|
||||
"add_password_protection": "Přidat ochranu heslem",
|
||||
"password": "Heslo",
|
||||
"at_least_8_characters": "nejméně 8 znaků",
|
||||
"password_again": "Heslo znovu",
|
||||
"add_auto_expiration": "Přidat automatickou expiraci",
|
||||
"days": "dní",
|
||||
"please_enter_password": "Zadejte heslo",
|
||||
"greater_than_or_equal_to": "Vyšší nebo rovno",
|
||||
"less_than_or_equal_to": "Nižší nebo rovno",
|
||||
"set_permission": "Nastavit oprávnění",
|
||||
"preview_and_download": "Zobrazit a stáhnout",
|
||||
"preview_only": "Pouze zobrazit",
|
||||
"please_enter_valid_days": "Zadejte platné dny",
|
||||
"please_enter_a_non-negative_integer": "Vložte prosím nezáporné celé číslo",
|
||||
"please_enter_days": "Prosím zadejte dny",
|
||||
"password_is_too_short": "Heslo je příliš krátké.",
|
||||
"passwords_do_not_match": "Hesla nesouhlasí",
|
||||
"return_to_wiki_page": "Návrat na stránku Wiki",
|
||||
"insert_network_image": "Vložit síťový obrázek",
|
||||
"upload_local_image": "Nahrát lokální obrázek",
|
||||
"add_link": "Přidat odkaz",
|
||||
"file_history": "Historie souboru",
|
||||
"history_version": "Historie verzí",
|
||||
"back_to_viewer": "Zpět na prohlížeč",
|
||||
"link_title": "Název odkazu",
|
||||
"local_draft": "Místní koncept",
|
||||
"use_draft": "Použít 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?",
|
||||
"local_draft_saved": "Místní koncept byl uložen",
|
||||
"new_draft": "Nový návrh",
|
||||
"view_draft": "Zobrazit koncept",
|
||||
"publish": "Zveřejnit",
|
||||
"this_file_has_a_draft": "Tento soubor má koncept.",
|
||||
"delete": "Smazat",
|
||||
"comments": "Komentáře",
|
||||
"add_a_comment": "Přidat komentář…",
|
||||
"no_comment_yet": "Žádné komentáře",
|
||||
"Bold": "Tučně",
|
||||
"Italic": "Kurzíva",
|
||||
"Inline_code": "Kód",
|
||||
"Header_one": "Záhlaví 1",
|
||||
"Header_two": "Záhlaví 2",
|
||||
"Header_three": "Záhlaví 3",
|
||||
"Header_four": "Záhlaví 4",
|
||||
"Header_five": "Záhlaví 5",
|
||||
"Header_six": "Záhlaví 6",
|
||||
"Paragraph": "Odstavec",
|
||||
"Quote": "Citace",
|
||||
"Ordered_list": "Číslovaný seznam",
|
||||
"Unordered_list": "Nečíslovaný seznam",
|
||||
"Check_list_item": "Zkontrolovat položku seznamu",
|
||||
"Insert_image": "Vložit obrázek",
|
||||
"Insert_formula": "Insert Formula",
|
||||
"Formula": "Formula",
|
||||
"Insert_file": "Vložit soubor",
|
||||
"Code": "Řádkový kód",
|
||||
"Code_block": "Blok kódu",
|
||||
"Insert_link": "Vložit odkaz",
|
||||
"Insert_table": "Vložit tabulku",
|
||||
"Save": "Uložit",
|
||||
"More": "Více",
|
||||
"Invalid_url": "Chybná URL",
|
||||
"Link_address": "Adresa odkazu",
|
||||
"Image_address": "Adresa obrázku",
|
||||
"Submit": "Odeslat",
|
||||
"Cancel": "Storno",
|
||||
"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_viewer": "Přepnout do značkovacího prohlížeče",
|
||||
"Help": "Pomoc",
|
||||
"Remove_table": "Odebrat tabulku",
|
||||
"Column": "Sloupec",
|
||||
"Row": "Řádek",
|
||||
"Insert_row_before": "Insert row before",
|
||||
"Insert_row_after": "Insert row after",
|
||||
"Insert_column_before": "Insert column before",
|
||||
"Insert_column_after": "Insert column after",
|
||||
"Remove_row": "Remove row",
|
||||
"Remove_column": "Remove column",
|
||||
"Insert_row": "Insert row",
|
||||
"Insert_column": "Insert column",
|
||||
"Set_align": "Nastavit zarovnání",
|
||||
"Left": "Vlevo",
|
||||
"Center": "Střed",
|
||||
"Right": "Vpravo",
|
||||
"File_saved": "Soubor uložen",
|
||||
"File_failed_to_save": "Soubor nebyl uložen",
|
||||
"Star": "Přidat hvězdičku",
|
||||
"Unstar": "Odebrat hvězdičku",
|
||||
"Back_to_parent_directory": "Zpět do nadřazeného adresáře",
|
||||
"Edit": "Upravit",
|
||||
"Copy": "Kopírovat",
|
||||
"Copied": "Zkopírováno",
|
||||
"Internal_link": "Interní odkaz",
|
||||
"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í.",
|
||||
"Share": "Sdílet",
|
||||
"Share_link": "Veřejný odkaz",
|
||||
"Generate": "Generovat",
|
||||
"Add_password_protection": "Přidat ochranu heslem",
|
||||
"Password": "Heslo",
|
||||
"At_least_8_characters": "nejméně 8 znaků",
|
||||
"Password_again": "Heslo znovu",
|
||||
"Add_auto_expiration": "Přidat automatickou expiraci",
|
||||
"Days": "dní",
|
||||
"Please_enter_password": "Zadejte heslo",
|
||||
"Greater_than_or_equal_to": "Vyšší nebo rovno",
|
||||
"Less_than_or_equal_to": "Nižší nebo rovno",
|
||||
"Set_permission": "Nastavit oprávnění",
|
||||
"Preview_and_download": "Zobrazit a stáhnout",
|
||||
"Preview_only": "Pouze zobrazit",
|
||||
"Please_enter_valid_days": "Zadejte platné dny",
|
||||
"Please_enter_a_non-negative_integer": "Vložte prosím nezáporné celé číslo",
|
||||
"Please_enter_days": "Prosím zadejte dny",
|
||||
"Password_is_too_short": "Heslo je příliš krátké.",
|
||||
"Passwords_do_not_match": "Hesla nesouhlasí",
|
||||
"Return_to_wiki_page": "Návrat na stránku Wiki",
|
||||
"Insert_network_image": "Vložit síťový obrázek",
|
||||
"Upload_local_image": "Nahrát lokální obrázek",
|
||||
"Add_link": "Přidat odkaz",
|
||||
"File_history": "Historie souboru",
|
||||
"History_version": "Historie verzí",
|
||||
"Back_to_viewer": "Zpět na prohlížeč",
|
||||
"Link_title": "Název odkazu",
|
||||
"Local_draft": "Místní koncept",
|
||||
"Use_draft": "Použít 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?",
|
||||
"Local_draft_saved": "Místní koncept byl uložen",
|
||||
"New_draft": "Nový návrh",
|
||||
"View_draft": "Zobrazit koncept",
|
||||
"Publish": "Zveřejnit",
|
||||
"This_file_has_a_draft": "Tento soubor má koncept.",
|
||||
"Delete": "Smazat",
|
||||
"Comments": "Komentáře",
|
||||
"Add_a_comment": "Přidat komentář…",
|
||||
"No_comment_yet": "Žádné komentáře",
|
||||
"Mark_as_Resolved": "Označit jako vyřešené",
|
||||
"ask_for_review": "Požádat o kontrolu",
|
||||
"review_already_exists": "Kontrola již existuje. ",
|
||||
"view_review": "Zobrazit kontrolu",
|
||||
"there_is_an_associated_review_with_this_file": "K tomuto souboru je přiřazená kontrola",
|
||||
"start_review": "Začít kontrolu",
|
||||
"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_has_been_updated": "Tento soubor byl aktualizován.",
|
||||
"refresh": "Obnovit",
|
||||
"related_files": "související soubory",
|
||||
"related_file": "související soubor",
|
||||
"no_tags": "Žádné značky",
|
||||
"Ask_for_review": "Požádat o kontrolu",
|
||||
"Review_already_exists": "Kontrola již existuje. ",
|
||||
"View_review": "Zobrazit kontrolu",
|
||||
"There_is_an_associated_review_with_this_file": "K tomuto souboru je přiřazená kontrola",
|
||||
"Start_review": "Začít kontrolu",
|
||||
"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_has_been_updated": "Tento soubor byl aktualizován.",
|
||||
"Refresh": "Obnovit",
|
||||
"Related_files": "související soubory",
|
||||
"Related_file": "související soubor",
|
||||
"No_tags": "Žádné značky",
|
||||
"Date": "Datum",
|
||||
"Participants": "Účastníci",
|
||||
"Meeting_note": "Poznámky ze schůzky",
|
||||
"Chooser_document_type": "Výběr typu dokumentu",
|
||||
"Empty": "Prázdný",
|
||||
"no_related_files": "Žádné související soubory",
|
||||
"no_out_line": "Bez obrysu",
|
||||
"No_related_files": "Žádné související soubory",
|
||||
"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.",
|
||||
"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",
|
||||
"Show_side_panel": "Zobrazit postranní panel",
|
||||
"Show_resolved_comments": "Zobrazit vyřešené komentáře",
|
||||
@@ -131,25 +131,16 @@
|
||||
"Insert_library_image": "Vložit obrázek knihovny",
|
||||
"Size": "Velikost",
|
||||
"Location": "Umístění",
|
||||
"Last_Update": "Poslední aktualizace",
|
||||
"Last_update": "Last update",
|
||||
"Tags": "Štítky",
|
||||
"Related_Files": "Související soubory",
|
||||
"Add_participants": "Přidat účastníky",
|
||||
"markdownLint": {
|
||||
"missing_h1": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"Clear_format": "Clear format",
|
||||
"Image_address_invalid": "Image address invalid",
|
||||
"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": {
|
||||
"title": "Klávesové zkratky",
|
||||
"userHelpData": [
|
||||
@@ -162,7 +153,8 @@
|
||||
"Insert_child_in_item": "Vložit podpoložku",
|
||||
"Increase_depth": "Zvýšit hloubku"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Zkratky záhlaví",
|
||||
"shortcutData": {
|
||||
"Heading_1": "Záhlaví 1",
|
||||
@@ -172,7 +164,8 @@
|
||||
"Heading_5": "Záhlaví 5",
|
||||
"Heading_6": "Záhlaví 6"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Zkratky bloků kódu",
|
||||
"shortcutData": {
|
||||
"Make_code_block": "Vytvořit blok kódu",
|
||||
@@ -180,37 +173,43 @@
|
||||
"Escape_code_block": "Opustit blok kódu",
|
||||
"Insert_indent": "Vložit odrážku"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Zkratky bloku citace",
|
||||
"shortcutData": {
|
||||
"Make_Block_quote": "Vytvořit blokovou citaci",
|
||||
"Escape_Block_quote": "Opustit blokovou citaci"
|
||||
"Make_block_quote": "Make block quote",
|
||||
"Escape_block_quote": "Escape block quote"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Zkratky tabulky",
|
||||
"shortcutData": {
|
||||
"Insert_Table_Row": "Vložit řádku tabulky",
|
||||
"Insert_table_row": "Insert table tow",
|
||||
"Escape_table": "Opustit tabulku"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Zkratky vzorečku",
|
||||
"shortcutData": {
|
||||
"Insert_Formula": "Insert Formula"
|
||||
"Insert_formula": "Insert formula"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Řádkové zkratky",
|
||||
"shortcutData": {
|
||||
"Bold": "Tučně",
|
||||
"Italic": "Kurzíva",
|
||||
"Italic_Bold": "Tučná kurzíva",
|
||||
"Italic_bold": "Italic bold",
|
||||
"Inline_code": "Řádkový kód"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Uložit zkratky",
|
||||
"shortcutData": {
|
||||
"Save_file": "Uložit soubor"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Zkratky obrázku",
|
||||
"shortcutData": {
|
||||
"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",
|
||||
"italic": "Kursiv",
|
||||
"inline_code": "Code",
|
||||
"header_one": "Überschrift 1",
|
||||
"header_two": "Überschrift 2",
|
||||
"header_three": "Überschrift 3",
|
||||
"header_four": "Überschrift 4",
|
||||
"header_five": "Überschrift 5",
|
||||
"header_six": "Überschrift 6",
|
||||
"paragraph": "Absatz",
|
||||
"quote": "Blockquote",
|
||||
"ordered_list": "Nummerierte Liste",
|
||||
"unordered_list": "Ungeordnete Liste",
|
||||
"check_list_item": "Checkbox Liste",
|
||||
"insert_image": "Bild",
|
||||
"insert_formula": "Formel einfügen",
|
||||
"formula": "Formel",
|
||||
"insert_file": "Datei",
|
||||
"code": "Inline-Code",
|
||||
"code_block": "Codeblock",
|
||||
"insert_link": "Link",
|
||||
"insert_table": "Tabelle",
|
||||
"save": "Speichern",
|
||||
"more": "Mehr",
|
||||
"invalid_url": "Ungültige Adresse",
|
||||
"link_address": "Link-URL",
|
||||
"image_address": "Bild-URL",
|
||||
"submit": "Absenden",
|
||||
"cancel": "Abbrechen",
|
||||
"switch_to_plain_text_editor": "Zum Plain Text Editor wechseln",
|
||||
"switch_to_rich_text_editor": "Zum Rich Text Editor wechseln",
|
||||
"switch_to_viewer": "Zur Markdown-Vorschau wechseln",
|
||||
"help": "Hilfe",
|
||||
"remove_table": "Tabelle entfernen",
|
||||
"column": "Spalte",
|
||||
"row": "Zeile",
|
||||
"Insert_Row_Before": "Zeile darüber einfügen",
|
||||
"Insert_Row_After": "Zeile darunter einfügen",
|
||||
"Insert_Column_Before": "Spalte links einfügen",
|
||||
"Insert_Column_After": "Spalte rechts einfügen",
|
||||
"Remove_Row": "Zeile entfernen",
|
||||
"Remove_Column": "Spalte entfernen",
|
||||
"Insert_Row": "Zeile einfügen",
|
||||
"Insert_Column": "Spalte einfügen",
|
||||
"set_align": "Ausrichtung festlegen",
|
||||
"left": "Links",
|
||||
"center": "Zentrieren",
|
||||
"right": "Rechts",
|
||||
"file_saved": "Die Datei wurde gespeichert.",
|
||||
"file_failed_to_save": "Die Datei konnte nicht gespeichert werden.",
|
||||
"star": "Zu Favoriten hinzufügen",
|
||||
"unstar": "Aus Favoriten entfernen",
|
||||
"back_to_parent_directory":"Zurück zum übergeordneten Verzeichnis",
|
||||
"edit": "Bearbeiten",
|
||||
"copy": "Kopieren",
|
||||
"copied": "Kopiert",
|
||||
"internal_link": "Internen Link anzeigen",
|
||||
"copy_internal_link": "Der interne Link wurde in die Zwischenablage 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.",
|
||||
"share": "Freigeben",
|
||||
"share_link": "Download-Link",
|
||||
"generate": "Erstellen",
|
||||
"add_password_protection": "Passwort hinzufügen",
|
||||
"password": "Passwort",
|
||||
"at_least_8_characters": "mindestens 8 Zeichen",
|
||||
"password_again": "Passwort erneut eingeben",
|
||||
"add_auto_expiration": "Befristung hinzufügen",
|
||||
"days": "Tage",
|
||||
"please_enter_password": "Bitte geben Sie ein Passwort ein",
|
||||
"greater_than_or_equal_to": "Größer oder gleich",
|
||||
"less_than_or_equal_to": "Weniger oder gleich",
|
||||
"set_permission": "Rechte festlegen",
|
||||
"preview_and_download": "Vorschau und Herunterladen",
|
||||
"preview_only": "Nur Vorschau erlaubt",
|
||||
"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_days": "Bitte geben Sie Tage ein",
|
||||
"password_is_too_short": "Passwort ist zu kurz",
|
||||
"passwords_do_not_match": "Passwörter stimmen nicht überein",
|
||||
"return_to_wiki_page": "Zurück zur Wiki-Seite",
|
||||
"insert_network_image": "Bild per URL einfügen",
|
||||
"upload_local_image": "Bild hochladen und einfügen",
|
||||
"add_link": "Link hinzufügen",
|
||||
"file_history": "Dateiversionen",
|
||||
"history_version": "Versionen",
|
||||
"back_to_viewer": "Zurück zur Vorschau",
|
||||
"link_title": "Linktext",
|
||||
"local_draft": "Lokaler Entwurf",
|
||||
"use_draft": "Entwurf verwenden",
|
||||
"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?",
|
||||
"local_draft_saved": "Lokaler Entwurf gespeichert",
|
||||
"new_draft": "Neuer Entwurf",
|
||||
"view_draft": "Entwurf anzeigen",
|
||||
"publish": "Veröffentlichen",
|
||||
"this_file_has_a_draft": "Zu dieser Datei gibt es einen Entwurf.",
|
||||
"delete": "Löschen",
|
||||
"comments": "Kommentare",
|
||||
"add_a_comment": "Kommentar einfügen",
|
||||
"no_comment_yet": "Keine Kommentare vorhanden",
|
||||
"Bold": "Fett",
|
||||
"Italic": "Kursiv",
|
||||
"Inline_code": "Code",
|
||||
"Header_one": "Überschrift 1",
|
||||
"Header_two": "Überschrift 2",
|
||||
"Header_three": "Überschrift 3",
|
||||
"Header_four": "Überschrift 4",
|
||||
"Header_five": "Überschrift 5",
|
||||
"Header_six": "Überschrift 6",
|
||||
"Paragraph": "Absatz",
|
||||
"Quote": "Blockquote",
|
||||
"Ordered_list": "Nummerierte Liste",
|
||||
"Unordered_list": "Ungeordnete Liste",
|
||||
"Check_list_item": "Checkbox Liste",
|
||||
"Insert_image": "Bild",
|
||||
"Insert_formula": "Formel einfügen",
|
||||
"Formula": "Formel",
|
||||
"Insert_file": "Datei",
|
||||
"Code": "Inline-Code",
|
||||
"Code_block": "Codeblock",
|
||||
"Insert_link": "Link",
|
||||
"Insert_table": "Tabelle",
|
||||
"Save": "Speichern",
|
||||
"More": "Mehr",
|
||||
"Invalid_url": "Ungültige Adresse",
|
||||
"Link_address": "Link-URL",
|
||||
"Image_address": "Bild-URL",
|
||||
"Submit": "Speichern",
|
||||
"Cancel": "Abbrechen",
|
||||
"Switch_to_plain_text_editor": "Zum Plain Text Editor wechseln",
|
||||
"Switch_to_rich_text_editor": "Zum Rich Text Editor wechseln",
|
||||
"Switch_to_viewer": "Zur Markdown-Vorschau wechseln",
|
||||
"Help": "Hilfe",
|
||||
"Remove_table": "Tabelle entfernen",
|
||||
"Column": "Spalte",
|
||||
"Row": "Zeile",
|
||||
"Insert_row_before": "Insert row before",
|
||||
"Insert_row_after": "Insert row after",
|
||||
"Insert_column_before": "Insert column before",
|
||||
"Insert_column_after": "Insert column after",
|
||||
"Remove_row": "Remove row",
|
||||
"Remove_column": "Remove column",
|
||||
"Insert_row": "Insert row",
|
||||
"Insert_column": "Insert column",
|
||||
"Set_align": "Ausrichtung festlegen",
|
||||
"Left": "Links",
|
||||
"Center": "Zentrieren",
|
||||
"Right": "Rechts",
|
||||
"File_saved": "Die Datei wurde gespeichert.",
|
||||
"File_failed_to_save": "Die Datei konnte nicht gespeichert werden.",
|
||||
"Star": "Zu Favoriten hinzufügen",
|
||||
"Unstar": "Aus Favoriten entfernen",
|
||||
"Back_to_parent_directory": "Zurück zum übergeordneten Verzeichnis",
|
||||
"Edit": "Bearbeiten",
|
||||
"Copy": "Kopieren",
|
||||
"Copied": "Kopiert",
|
||||
"Internal_link": "Internen Link anzeigen",
|
||||
"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.",
|
||||
"Share": "Freigeben",
|
||||
"Share_link": "Download-Link",
|
||||
"Generate": "Erstellen",
|
||||
"Add_password_protection": "Passwort hinzufügen",
|
||||
"Password": "Passwort",
|
||||
"At_least_8_characters": "mindestens 8 Zeichen",
|
||||
"Password_again": "Passwort erneut eingeben",
|
||||
"Add_auto_expiration": "Befristung hinzufügen",
|
||||
"Days": "Tage",
|
||||
"Please_enter_password": "Bitte geben Sie ein Passwort ein",
|
||||
"Greater_than_or_equal_to": "Größer oder gleich",
|
||||
"Less_than_or_equal_to": "Weniger oder gleich",
|
||||
"Set_permission": "Berechtigung festlegen",
|
||||
"Preview_and_download": "Vorschau und Herunterladen",
|
||||
"Preview_only": "Nur Vorschau erlaubt",
|
||||
"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_days": "Bitte geben Sie Tage ein",
|
||||
"Password_is_too_short": "Das Passwort ist zu kurz",
|
||||
"Passwords_do_not_match": "Passwörter stimmen nicht überein",
|
||||
"Return_to_wiki_page": "Zurück zur Wiki-Seite",
|
||||
"Insert_network_image": "Bild per URL einfügen",
|
||||
"Upload_local_image": "Bild hochladen und einfügen",
|
||||
"Add_link": "Link hinzufügen",
|
||||
"File_history": "Dateiversionen",
|
||||
"History_version": "Versionen",
|
||||
"Back_to_viewer": "Zurück zur Vorschau",
|
||||
"Link_title": "Linktext",
|
||||
"Local_draft": "Lokaler Entwurf",
|
||||
"Use_draft": "Entwurf verwenden",
|
||||
"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?",
|
||||
"Local_draft_saved": "Lokaler Entwurf gespeichert",
|
||||
"New_draft": "Neuer Entwurf",
|
||||
"View_draft": "Entwurf anzeigen",
|
||||
"Publish": "Veröffentlichen",
|
||||
"This_file_has_a_draft": "Zu dieser Datei gibt es einen Entwurf.",
|
||||
"Delete": "Löschen",
|
||||
"Comments": "Kommentare",
|
||||
"Add_a_comment": "Kommentar einfügen",
|
||||
"No_comment_yet": "Keine Kommentare vorhanden",
|
||||
"Mark_as_Resolved": "Als erledigt markieren",
|
||||
"ask_for_review": "Um ein Review bitten",
|
||||
"review_already_exists": "Es gibt bereits ein Review.",
|
||||
"view_review": "Review anzeigen",
|
||||
"there_is_an_associated_review_with_this_file": "Es gibt ein Review zu dieser Datei.",
|
||||
"start_review": "Review schreiben",
|
||||
"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_has_been_updated": "Die Datei wurde aktualisiert.",
|
||||
"refresh": "Aktualisieren",
|
||||
"related_files": "Zugehörige Dateien",
|
||||
"related_file": "Zugehörige Datei",
|
||||
"no_tags": "Keine Tags",
|
||||
"Ask_for_review": "Um ein Review bitten",
|
||||
"Review_already_exists": "Es gibt bereits ein Review.",
|
||||
"View_review": "Review anzeigen",
|
||||
"There_is_an_associated_review_with_this_file": "Es gibt ein Review zu dieser Datei.",
|
||||
"Start_review": "Review schreiben",
|
||||
"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_has_been_updated": "Die Datei wurde aktualisiert.",
|
||||
"Refresh": "Aktualisieren",
|
||||
"Related_files": "Zugehörige Dateien",
|
||||
"Related_file": "Zugehörige Datei",
|
||||
"No_tags": "Keine Tags",
|
||||
"Date": "Datum",
|
||||
"Participants": "Teilnehmer",
|
||||
"Meeting_note": "Besprechungsnotiz",
|
||||
"Chooser_document_type": "Auswahl Dokumenttyp",
|
||||
"Empty": "Leer",
|
||||
"no_related_files": "Keine zugehörigen Dateien",
|
||||
"no_out_line": "Keine Gliederung",
|
||||
"No_related_files": "Keine zugehörigen Dateien",
|
||||
"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.",
|
||||
"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",
|
||||
"Show_side_panel": "Seitenleiste anzeigen",
|
||||
"Show_resolved_comments": "Erledigte Kommentare anzeigen",
|
||||
@@ -131,25 +131,16 @@
|
||||
"Insert_library_image": "Bild aus Bibliothek einfügen",
|
||||
"Size": "Größe",
|
||||
"Location": "Ort",
|
||||
"Last_Update": "Letzte Änderung",
|
||||
"Last_update": "Last update",
|
||||
"Tags": "Tags",
|
||||
"Related_Files": "Zugehörige Dateien",
|
||||
"Add_participants": "Teilnehmer hinzufügen",
|
||||
"markdownLint": {
|
||||
"missing_h1": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"Clear_format": "Clear format",
|
||||
"Image_address_invalid": "Image address invalid",
|
||||
"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": {
|
||||
"title": "Tastenkombinationen",
|
||||
"userHelpData": [
|
||||
@@ -162,7 +153,8 @@
|
||||
"Insert_child_in_item": "Textzeile einfügen",
|
||||
"Increase_depth": "Einzug erhöhen"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Überschriften",
|
||||
"shortcutData": {
|
||||
"Heading_1": "Überschrift 1",
|
||||
@@ -172,7 +164,8 @@
|
||||
"Heading_5": "Überschrift 5",
|
||||
"Heading_6": "Überschrift 6"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Codeblock",
|
||||
"shortcutData": {
|
||||
"Make_code_block": "Codeblock anlegen",
|
||||
@@ -180,37 +173,43 @@
|
||||
"Escape_code_block": "Codeblock beenden",
|
||||
"Insert_indent": "Einzug erhöhen"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Blockquote",
|
||||
"shortcutData": {
|
||||
"Make_Block_quote": "Blockquote einfügen",
|
||||
"Escape_Block_quote": "Blockquote beenden"
|
||||
"Make_block_quote": "Make block quote",
|
||||
"Escape_block_quote": "Escape block quote"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Tabellen",
|
||||
"shortcutData": {
|
||||
"Insert_Table_Row": "Tabellenzeile einfügen",
|
||||
"Insert_table_row": "Insert table tow",
|
||||
"Escape_table": "Tabelle beenden"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Formeln",
|
||||
"shortcutData": {
|
||||
"Insert_Formula": "Formel einfügen"
|
||||
"Insert_formula": "Insert formula"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Textformatierung",
|
||||
"shortcutData": {
|
||||
"Bold": "Fett",
|
||||
"Italic": "Kursiv",
|
||||
"Italic_Bold": "Kursiv fett",
|
||||
"Italic_bold": "Italic bold",
|
||||
"Inline_code": "Inline-Code"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Speichern",
|
||||
"shortcutData": {
|
||||
"Save_file": "Datei speichern"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Bilder",
|
||||
"shortcutData": {
|
||||
"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",
|
||||
"italic": "Italic",
|
||||
"inline_code": "Code",
|
||||
"header_one": "Heading 1",
|
||||
"header_two": "Heading 2",
|
||||
"header_three": "Heading 3",
|
||||
"header_four": "Heading 4",
|
||||
"header_five": "Heading 5",
|
||||
"header_six": "Heading 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": "Inline 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 Markdown Viewer",
|
||||
"help": "Help",
|
||||
"remove_table": "Remove Table",
|
||||
"column": "Column",
|
||||
"row": "Row",
|
||||
"Insert_Row_Before": "Insert Row Before",
|
||||
"Insert_Row_After": "Insert Row After",
|
||||
"Insert_Column_Before": "Insert Column Before",
|
||||
"Insert_Column_After": "Insert Column After",
|
||||
"Remove_Row": "Remove Row",
|
||||
"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": "Add star",
|
||||
"unstar": "Remove star",
|
||||
"back_to_parent_directory":"Back to parent directory",
|
||||
"edit": "Edit",
|
||||
"copy": "Copy",
|
||||
"copied": "Copied",
|
||||
"internal_link": "Internal Link",
|
||||
"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.",
|
||||
"share": "Share",
|
||||
"share_link": "Share Link",
|
||||
"generate": "Generate",
|
||||
"add_password_protection": "Add password protection",
|
||||
"password": "Password",
|
||||
"at_least_8_characters": "at least 8 characters",
|
||||
"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 Versions",
|
||||
"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.",
|
||||
"Bold": "Bold",
|
||||
"Italic": "Italic",
|
||||
"Inline_code": "Code",
|
||||
"Header_one": "Heading 1",
|
||||
"Header_two": "Heading 2",
|
||||
"Header_three": "Heading 3",
|
||||
"Header_four": "Heading 4",
|
||||
"Header_five": "Heading 5",
|
||||
"Header_six": "Heading 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": "Inline 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 Markdown Viewer",
|
||||
"Help": "Help",
|
||||
"Remove_table": "Remove Table",
|
||||
"Column": "Column",
|
||||
"Row": "Row",
|
||||
"Insert_row_before": "Insert row before",
|
||||
"Insert_row_after": "Insert row after",
|
||||
"Insert_column_before": "Insert column before",
|
||||
"Insert_column_after": "Insert column after",
|
||||
"Remove_row": "Remove row",
|
||||
"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": "Add star",
|
||||
"Unstar": "Remove star",
|
||||
"Back_to_parent_directory": "Back to parent directory",
|
||||
"Edit": "Edit",
|
||||
"Copy": "Copy",
|
||||
"Copied": "Copied",
|
||||
"Internal_link": "Internal Link",
|
||||
"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.",
|
||||
"Share": "Share",
|
||||
"Share_link": "Share Link",
|
||||
"Generate": "Generate",
|
||||
"Add_password_protection": "Add password protection",
|
||||
"Password": "Password",
|
||||
"At_least_8_characters": "at least 8 characters",
|
||||
"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 Versions",
|
||||
"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",
|
||||
"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 outline",
|
||||
"No_related_files": "No related files",
|
||||
"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.",
|
||||
"no_document_improvement_suggestion": "No document improvement suggestion",
|
||||
"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",
|
||||
"Last_update": "Last update",
|
||||
"Tags": "Tags",
|
||||
"Related_Files": "Related Files",
|
||||
"Add_participants": "Add participants",
|
||||
"markdownLint": {
|
||||
"missing_h1": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"Clear_format": "Clear format",
|
||||
"Image_address_invalid": "Image address invalid",
|
||||
"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": {
|
||||
"title": "Keyboard shortcuts",
|
||||
"userHelpData": [
|
||||
@@ -162,7 +153,8 @@
|
||||
"Insert_child_in_item": "Insert child in item",
|
||||
"Increase_depth": "Increase depth"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Head shortcuts",
|
||||
"shortcutData": {
|
||||
"Heading_1": "Heading 1",
|
||||
@@ -172,7 +164,8 @@
|
||||
"Heading_5": "Heading 5",
|
||||
"Heading_6": "Heading 6"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Code block shortcuts",
|
||||
"shortcutData": {
|
||||
"Make_code_block": "Make code block",
|
||||
@@ -180,37 +173,43 @@
|
||||
"Escape_code_block": "Escape code block",
|
||||
"Insert_indent": "Insert indent"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Block quote shortcuts",
|
||||
"shortcutData": {
|
||||
"Make_Block_quote": "Make Block quote",
|
||||
"Escape_Block_quote": "Escape Block quote"
|
||||
"Make_block_quote": "Make block quote",
|
||||
"Escape_block_quote": "Escape block quote"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Table shortcuts",
|
||||
"shortcutData": {
|
||||
"Insert_Table_Row": "Insert Table Row",
|
||||
"Insert_table_row": "Insert table tow",
|
||||
"Escape_table": "Escape table"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Formula shortcuts",
|
||||
"shortcutData": {
|
||||
"Insert_Formula": "Insert Formula"
|
||||
"Insert_formula": "Insert formula"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Inline shortcuts",
|
||||
"shortcutData": {
|
||||
"Bold": "Bold",
|
||||
"Italic": "Italic",
|
||||
"Italic_Bold": "Italic Bold",
|
||||
"Italic_bold": "Italic bold",
|
||||
"Inline_code": "Inline code"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Save shortcuts",
|
||||
"shortcutData": {
|
||||
"Save_file": "Save file"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Image shortcuts",
|
||||
"shortcutData": {
|
||||
"Paste_screen_shot": "Paste screen shot",
|
||||
@@ -218,5 +217,7 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Select_field": "Select field",
|
||||
"Font_style": "Font style"
|
||||
}
|
||||
|
@@ -1,126 +1,126 @@
|
||||
{
|
||||
"bold": "Negrita",
|
||||
"italic": "Itálica",
|
||||
"inline_code": "Código",
|
||||
"header_one": "Encabezado 1",
|
||||
"header_two": "Encabezado 2",
|
||||
"header_three": "Encabezado 3",
|
||||
"header_four": "Encabezado 4",
|
||||
"header_five": "Encabezado 5",
|
||||
"header_six": "Encabezado 6",
|
||||
"paragraph": "Párrafo",
|
||||
"quote": "Cita",
|
||||
"ordered_list": "Lista Ordenada",
|
||||
"unordered_list": "Lista Desordenada",
|
||||
"check_list_item": "Check List Item",
|
||||
"insert_image": "Insertar Imagen",
|
||||
"insert_formula": "Insertar Fórmula",
|
||||
"formula": "Fórmula",
|
||||
"insert_file": "Insertar Archivo",
|
||||
"code": "Inline Code",
|
||||
"code_block": "Bloque de Código",
|
||||
"insert_link": "Insertar Enlace",
|
||||
"insert_table": "Insertar Tabla",
|
||||
"save": "Guardar",
|
||||
"more": "Más",
|
||||
"invalid_url": "URL Inválida",
|
||||
"link_address": "Dirección del enlace",
|
||||
"image_address": "Dirección de la imagen",
|
||||
"submit": "Enviar",
|
||||
"cancel": "Cancelar",
|
||||
"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_viewer": "Cambiar a visualizador Markdown",
|
||||
"help": "Ayuda",
|
||||
"remove_table": "Eliminar tabla",
|
||||
"column": "Columna",
|
||||
"row": "Fila",
|
||||
"Insert_Row_Before": "Insertar Línea Antes",
|
||||
"Insert_Row_After": "Insertar Línea Después",
|
||||
"Insert_Column_Before": "Insertar Columna Antes",
|
||||
"Insert_Column_After": "Insertar Columna Después",
|
||||
"Remove_Row": "Eliminar Fila",
|
||||
"Remove_Column": "Eliminar Columna",
|
||||
"Insert_Row": "Insertar Fila",
|
||||
"Insert_Column": "Insertar Columna",
|
||||
"set_align": "Establecer alineación",
|
||||
"left": "Izquierda",
|
||||
"center": "Centrar",
|
||||
"right": "derecha",
|
||||
"file_saved": "Archivo guardado",
|
||||
"file_failed_to_save": "Fallo al guardar archivo",
|
||||
"star": "Add star",
|
||||
"unstar": "Remove star",
|
||||
"back_to_parent_directory":"Volver a la carpeta superior",
|
||||
"edit": "Editar",
|
||||
"copy": "Copiar",
|
||||
"copied": "Copiado",
|
||||
"internal_link": "Enlace interno",
|
||||
"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. ",
|
||||
"share": "Compartir",
|
||||
"share_link": "Compartir enlace",
|
||||
"generate": "Generar",
|
||||
"add_password_protection": "Agregar protección por contraseña",
|
||||
"password": "Contraseña ",
|
||||
"at_least_8_characters": "al menos 8 caracteres",
|
||||
"password_again": "Repetir contraseña",
|
||||
"add_auto_expiration": "Agregar vencimiento automático",
|
||||
"days": "días",
|
||||
"please_enter_password": "Ingresa una contraseña",
|
||||
"greater_than_or_equal_to": "Mayor o igual que",
|
||||
"less_than_or_equal_to": "Menor o igual que",
|
||||
"set_permission": "Establecer permiso",
|
||||
"preview_and_download": "Vista previa y descargar",
|
||||
"preview_only": "Vista previa solamente",
|
||||
"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_days": "Ingresa cantidad de días",
|
||||
"password_is_too_short": "Contraseña demasiado corta",
|
||||
"passwords_do_not_match": "Las contraseñas no concuerdan",
|
||||
"return_to_wiki_page": "Volver a la página del Wiki",
|
||||
"insert_network_image": "Insertar imágen desde la red",
|
||||
"upload_local_image": "Subir imagen local",
|
||||
"add_link": "Agregar enlace",
|
||||
"file_history": "Historial del Archivo",
|
||||
"history_version": "Historial de Versiones",
|
||||
"back_to_viewer": "Volver al Visualizador",
|
||||
"link_title": "Título del enlace",
|
||||
"local_draft": "Borrador local",
|
||||
"use_draft": "Usar borrador",
|
||||
"delete_draft": "Eliminar borrador",
|
||||
"you_have_an_unsaved_draft_do_you_like_to_use_it": "Tienes un borrador sin guardar. ¿Deseas utilizarlo?",
|
||||
"local_draft_saved": "Borrador local guardado",
|
||||
"new_draft": "Nuevo Borrador",
|
||||
"view_draft": "Ver Borrador",
|
||||
"publish": "Publicar",
|
||||
"this_file_has_a_draft": "Este archivo tiene un borrador",
|
||||
"delete": "Borrar",
|
||||
"comments": "Comentarios",
|
||||
"add_a_comment": "Agregar un comentario...",
|
||||
"no_comment_yet": "No hay comentarios.",
|
||||
"Bold": "Negrita",
|
||||
"Italic": "Itálica",
|
||||
"Inline_code": "Código",
|
||||
"Header_one": "Encabezado 1",
|
||||
"Header_two": "Encabezado 2",
|
||||
"Header_three": "Encabezado 3",
|
||||
"Header_four": "Encabezado 4",
|
||||
"Header_five": "Encabezado 5",
|
||||
"Header_six": "Encabezado 6",
|
||||
"Paragraph": "Párrafo",
|
||||
"Quote": "Cita",
|
||||
"Ordered_list": "Lista Ordenada",
|
||||
"Unordered_list": "Lista Desordenada",
|
||||
"Check_list_item": "Check List Item",
|
||||
"Insert_image": "Insertar Imagen",
|
||||
"Insert_formula": "Insertar Fórmula",
|
||||
"Formula": "Fórmula",
|
||||
"Insert_file": "Insertar Archivo",
|
||||
"Code": "Inline Code",
|
||||
"Code_block": "Bloque de Código",
|
||||
"Insert_link": "Insertar Enlace",
|
||||
"Insert_table": "Insertar Tabla",
|
||||
"Save": "Guardar",
|
||||
"More": "Más",
|
||||
"Invalid_url": "URL Inválida",
|
||||
"Link_address": "Dirección del enlace",
|
||||
"Image_address": "Dirección de la imagen",
|
||||
"Submit": "Enviar",
|
||||
"Cancel": "Cancelar",
|
||||
"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_viewer": "Cambiar a visualizador Markdown",
|
||||
"Help": "Ayuda",
|
||||
"Remove_table": "Eliminar tabla",
|
||||
"Column": "Columna",
|
||||
"Row": "Fila",
|
||||
"Insert_row_before": "Insert row before",
|
||||
"Insert_row_after": "Insert row after",
|
||||
"Insert_column_before": "Insert column before",
|
||||
"Insert_column_after": "Insert column after",
|
||||
"Remove_row": "Remove row",
|
||||
"Remove_column": "Remove column",
|
||||
"Insert_row": "Insert row",
|
||||
"Insert_column": "Insert column",
|
||||
"Set_align": "Establecer alineación",
|
||||
"Left": "Izquierda",
|
||||
"Center": "Centrar",
|
||||
"Right": "derecha",
|
||||
"File_saved": "Archivo guardado",
|
||||
"File_failed_to_save": "Fallo al guardar archivo",
|
||||
"Star": "Add star",
|
||||
"Unstar": "Remove star",
|
||||
"Back_to_parent_directory": "Volver a la carpeta superior",
|
||||
"Edit": "Editar",
|
||||
"Copy": "Copiar",
|
||||
"Copied": "Copiado",
|
||||
"Internal_link": "Enlace interno",
|
||||
"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. ",
|
||||
"Share": "Compartir",
|
||||
"Share_link": "Compartir enlace",
|
||||
"Generate": "Generar",
|
||||
"Add_password_protection": "Agregar protección por contraseña",
|
||||
"Password": "Contraseña ",
|
||||
"At_least_8_characters": "al menos 8 caracteres",
|
||||
"Password_again": "Repetir contraseña",
|
||||
"Add_auto_expiration": "Agregar vencimiento automático",
|
||||
"Days": "días",
|
||||
"Please_enter_password": "Ingresa una contraseña",
|
||||
"Greater_than_or_equal_to": "Mayor o igual que",
|
||||
"Less_than_or_equal_to": "Menor o igual que",
|
||||
"Set_permission": "Establecer permiso",
|
||||
"Preview_and_download": "Vista previa y descargar",
|
||||
"Preview_only": "Vista previa solamente",
|
||||
"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_days": "Ingresa cantidad de días",
|
||||
"Password_is_too_short": "Contraseña demasiado corta",
|
||||
"Passwords_do_not_match": "Las contraseñas no concuerdan",
|
||||
"Return_to_wiki_page": "Volver a la página del Wiki",
|
||||
"Insert_network_image": "Insertar imágen desde la red",
|
||||
"Upload_local_image": "Subir imagen local",
|
||||
"Add_link": "Agregar enlace",
|
||||
"File_history": "Historial del Archivo",
|
||||
"History_version": "Historial de Versiones",
|
||||
"Back_to_viewer": "Volver al Visualizador",
|
||||
"Link_title": "Título del enlace",
|
||||
"Local_draft": "Borrador local",
|
||||
"Use_draft": "Usar borrador",
|
||||
"Delete_draft": "Eliminar borrador",
|
||||
"You_have_an_unsaved_draft_do_you_like_to_use_it": "Tienes un borrador sin guardar. ¿Deseas utilizarlo?",
|
||||
"Local_draft_saved": "Borrador local guardado",
|
||||
"New_draft": "Nuevo Borrador",
|
||||
"View_draft": "Ver Borrador",
|
||||
"Publish": "Publicar",
|
||||
"This_file_has_a_draft": "Este archivo tiene un borrador",
|
||||
"Delete": "Borrar",
|
||||
"Comments": "Comentarios",
|
||||
"Add_a_comment": "Agregar un comentario...",
|
||||
"No_comment_yet": "No hay comentarios.",
|
||||
"Mark_as_Resolved": "Marcar como Resuelto",
|
||||
"ask_for_review": "Solicitar revisión",
|
||||
"review_already_exists": "La revisión ya existe",
|
||||
"view_review": "Ver revisión",
|
||||
"there_is_an_associated_review_with_this_file": "Hay una revisión asociada con este archivo",
|
||||
"start_review": "Iniciar revisión",
|
||||
"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_has_been_updated": "Este archivo ha sido actualizado.",
|
||||
"refresh": "Refrescar",
|
||||
"related_files": "archivos relacionados",
|
||||
"related_file": "archivo relacionado",
|
||||
"no_tags": "Sin etiquetas",
|
||||
"Ask_for_review": "Solicitar revisión",
|
||||
"Review_already_exists": "La revisión ya existe",
|
||||
"View_review": "Ver revisión",
|
||||
"There_is_an_associated_review_with_this_file": "Hay una revisión asociada con este archivo",
|
||||
"Start_review": "Iniciar revisión",
|
||||
"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_has_been_updated": "Este archivo ha sido actualizado.",
|
||||
"Refresh": "Refrescar",
|
||||
"Related_files": "archivos relacionados",
|
||||
"Related_file": "archivo relacionado",
|
||||
"No_tags": "Sin etiquetas",
|
||||
"Date": "Fecha",
|
||||
"Participants": "Participantes",
|
||||
"Meeting_note": "Nota de la reunión",
|
||||
"Chooser_document_type": "Elija el tipo de documento",
|
||||
"Empty": "Vacío",
|
||||
"no_related_files": "Sin archivos relacionados",
|
||||
"no_out_line": "No hay esquema",
|
||||
"No_related_files": "Sin archivos relacionados",
|
||||
"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.",
|
||||
"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",
|
||||
"Show_side_panel": "Mostrar panel lateral",
|
||||
"Show_resolved_comments": "Mostrar comentarios resueltos",
|
||||
@@ -131,25 +131,16 @@
|
||||
"Insert_library_image": "Insertar imagen desde la biblioteca",
|
||||
"Size": "Tamaño",
|
||||
"Location": "Ubicación",
|
||||
"Last_Update": "Última actualización",
|
||||
"Last_update": "Last update",
|
||||
"Tags": "Rótulos",
|
||||
"Related_Files": "Archivos Relacionados",
|
||||
"Add_participants": "Agregar participantes",
|
||||
"markdownLint": {
|
||||
"missing_h1": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"Clear_format": "Clear format",
|
||||
"Image_address_invalid": "Image address invalid",
|
||||
"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": {
|
||||
"title": "Atajos de teclado",
|
||||
"userHelpData": [
|
||||
@@ -162,7 +153,8 @@
|
||||
"Insert_child_in_item": "Insert child in item",
|
||||
"Increase_depth": "Increase depth"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Head shortcuts",
|
||||
"shortcutData": {
|
||||
"Heading_1": "Encabezado 1",
|
||||
@@ -172,7 +164,8 @@
|
||||
"Heading_5": "Encabezado 5",
|
||||
"Heading_6": "Encabezado 6"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Code block shortcuts",
|
||||
"shortcutData": {
|
||||
"Make_code_block": "Crear bloque de código",
|
||||
@@ -180,37 +173,43 @@
|
||||
"Escape_code_block": "Escape code block",
|
||||
"Insert_indent": "Insert indent"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Block quote shortcuts",
|
||||
"shortcutData": {
|
||||
"Make_Block_quote": "Make Block quote",
|
||||
"Escape_Block_quote": "Escape Block quote"
|
||||
"Make_block_quote": "Make block quote",
|
||||
"Escape_block_quote": "Escape block quote"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Atajos de tabla",
|
||||
"shortcutData": {
|
||||
"Insert_Table_Row": "Insertar fila de tabla",
|
||||
"Insert_table_row": "Insert table tow",
|
||||
"Escape_table": "Escape table"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Atajos de fórmula",
|
||||
"shortcutData": {
|
||||
"Insert_Formula": "Insertar Fórmula"
|
||||
"Insert_formula": "Insert formula"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Inline shortcuts",
|
||||
"shortcutData": {
|
||||
"Bold": "Negrita",
|
||||
"Italic": "Itálica",
|
||||
"Italic_Bold": "Negrita itálica",
|
||||
"Italic_bold": "Italic bold",
|
||||
"Inline_code": "Inline code"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Guardar atajos",
|
||||
"shortcutData": {
|
||||
"Save_file": "Guardar archivo"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Atajos de imagen",
|
||||
"shortcutData": {
|
||||
"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",
|
||||
"italic": "Italique",
|
||||
"inline_code": "Code",
|
||||
"header_one": "Titre 1",
|
||||
"header_two": "Titre 2",
|
||||
"header_three": "Titre 3",
|
||||
"header_four": "Titre 4",
|
||||
"header_five": "Titre 5",
|
||||
"header_six": "Titre 6",
|
||||
"paragraph": "Paragraphe",
|
||||
"quote": "Blockquote",
|
||||
"ordered_list": "Numérotation",
|
||||
"unordered_list": "Enumeration",
|
||||
"check_list_item": "Case à chocher",
|
||||
"insert_image": "Image",
|
||||
"insert_formula": "Insérer formule",
|
||||
"formula": "Formule",
|
||||
"insert_file": "Fichier",
|
||||
"code": "Ligne de code",
|
||||
"code_block": "Bloc de code",
|
||||
"insert_link": "Lien",
|
||||
"insert_table": "Tableau",
|
||||
"save": "Sauvegarder",
|
||||
"more": "Plus",
|
||||
"invalid_url": "L'adresse n'est pas valide",
|
||||
"link_address": "Adresse du lien",
|
||||
"image_address": "Adresse de l'image",
|
||||
"submit": "Soumettre",
|
||||
"cancel": "Annuler",
|
||||
"switch_to_plain_text_editor": "Basculer en éditeur de texte plein",
|
||||
"switch_to_rich_text_editor": "Basculer en éditeur de texte riche",
|
||||
"switch_to_viewer": "Basculer en visualiseur Markdown",
|
||||
"help": "Aide",
|
||||
"remove_table": "Supprimer le tableau",
|
||||
"column": "Colonne",
|
||||
"row": "ligne",
|
||||
"Insert_Row_Before": "Insérer au-dessus",
|
||||
"Insert_Row_After": "Insérer en-dessous",
|
||||
"Insert_Column_Before": "Insérer à gauche",
|
||||
"Insert_Column_After": "Insérer à droite",
|
||||
"Remove_Row": "Supprimer la ligne",
|
||||
"Remove_Column": "Supprimer la colonne",
|
||||
"Insert_Row": "Insérer une ligne",
|
||||
"Insert_Column": "Insérer une colonne",
|
||||
"set_align": "Ajuster l'alignement",
|
||||
"left": "Gauche",
|
||||
"center": "Centrer",
|
||||
"right": "Droite",
|
||||
"file_saved": "Le fichier a été sauvegardé.",
|
||||
"file_failed_to_save": "Échec de la sauvegarde du fichier",
|
||||
"star": "Ajouter à favoris",
|
||||
"unstar": "Enlever des favoris",
|
||||
"back_to_parent_directory":"Retour au répertoire parent",
|
||||
"edit": "Modifier",
|
||||
"copy": "Copier",
|
||||
"copied": "Copié",
|
||||
"internal_link": "Afficher le lien interne",
|
||||
"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.",
|
||||
"share": "Partager",
|
||||
"share_link": "Lien de téléchargement",
|
||||
"generate": "Créer",
|
||||
"add_password_protection": "Ajouter un mot de passe",
|
||||
"password": "Mot de passe",
|
||||
"at_least_8_characters": "Au moins 8 caractères",
|
||||
"password_again": "Mot de passe (à nouveau)",
|
||||
"add_auto_expiration": "Ajouter une date d'expiration",
|
||||
"days": "jours",
|
||||
"please_enter_password": "Entrez un mot de passe",
|
||||
"greater_than_or_equal_to": "Plus grand ou égale à",
|
||||
"less_than_or_equal_to": "Plus petit ou égal à",
|
||||
"set_permission": "Définir la permission",
|
||||
"preview_and_download": "Prévisualiser et télécharger",
|
||||
"preview_only": "Aperçu uniquement",
|
||||
"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_days": "Veuillez entrer un nombre de jours",
|
||||
"password_is_too_short": "Le mot de passe est trop court",
|
||||
"passwords_do_not_match": "Les mots de passe ne correspondent pas.",
|
||||
"return_to_wiki_page": "Retour à la page du Wiki",
|
||||
"insert_network_image": "Insérer une image du réseau",
|
||||
"upload_local_image": "Insérer une image locale",
|
||||
"add_link": "Ajouter un lien",
|
||||
"file_history": "Historique du fichier",
|
||||
"history_version": "Historique des versions",
|
||||
"back_to_viewer": "Retour au visualiseur",
|
||||
"link_title": "Titre du lien",
|
||||
"local_draft": "Brouillon local",
|
||||
"use_draft": "Utiliser 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 ?",
|
||||
"local_draft_saved": "Brouillon local sauvegardé",
|
||||
"new_draft": "Nouveau brouillon",
|
||||
"view_draft": "Voir le brouillon",
|
||||
"publish": "Publier",
|
||||
"this_file_has_a_draft": "Ce fichier possède un brouillon.",
|
||||
"delete": "Supprimer",
|
||||
"comments": "Commentaires",
|
||||
"add_a_comment": "Ajouter un commentaire",
|
||||
"no_comment_yet": "Aucun commentaire disponible",
|
||||
"Bold": "Gras",
|
||||
"Italic": "Italique",
|
||||
"Inline_code": "Code",
|
||||
"Header_one": "Titre 1",
|
||||
"Header_two": "Titre 2",
|
||||
"Header_three": "Titre 3",
|
||||
"Header_four": "Titre 4",
|
||||
"Header_five": "Titre 5",
|
||||
"Header_six": "Titre 6",
|
||||
"Paragraph": "Paragraphe",
|
||||
"Quote": "Blockquote",
|
||||
"Ordered_list": "Liste ordonée",
|
||||
"Unordered_list": "Liste non-ordonée",
|
||||
"Check_list_item": "Liste à chocher",
|
||||
"Insert_image": "Image",
|
||||
"Insert_formula": "Insérer formule",
|
||||
"Formula": "Formule",
|
||||
"Insert_file": "Fichier",
|
||||
"Code": "Ligne de code",
|
||||
"Code_block": "Bloc de code",
|
||||
"Insert_link": "Lien",
|
||||
"Insert_table": "Tableau",
|
||||
"Save": "Sauvegarder",
|
||||
"More": "Plus",
|
||||
"Invalid_url": "L'adresse n'est pas valide.",
|
||||
"Link_address": "Adresse du lien",
|
||||
"Image_address": "Adresse de l'image",
|
||||
"Submit": "Soummettre",
|
||||
"Cancel": "Annuler",
|
||||
"Switch_to_plain_text_editor": "Basculer en éditeur de texte plein",
|
||||
"Switch_to_rich_text_editor": "Basculer en éditeur de texte riche",
|
||||
"Switch_to_viewer": "Basculer en visualiseur Markdown",
|
||||
"Help": "Aide",
|
||||
"Remove_table": "Supprimer le tableau",
|
||||
"Column": "Colonne",
|
||||
"Row": "Ligne",
|
||||
"Insert_row_before": "Insert row before",
|
||||
"Insert_row_after": "Insert row after",
|
||||
"Insert_column_before": "Insert column before",
|
||||
"Insert_column_after": "Insert column after",
|
||||
"Remove_row": "Remove row",
|
||||
"Remove_column": "Remove column",
|
||||
"Insert_row": "Insérer une ligne",
|
||||
"Insert_column": "Insérer une colonne",
|
||||
"Set_align": "Ajuster l'alignement",
|
||||
"Left": "Gauche",
|
||||
"Center": "Centrer",
|
||||
"Right": "Droite",
|
||||
"File_saved": "Le fichier a été sauvegardé.",
|
||||
"File_failed_to_save": "Échec de la sauvegarde du fichier",
|
||||
"Star": "Ajouter à favoris",
|
||||
"Unstar": "Enlever des favoris",
|
||||
"Back_to_parent_directory": "Retour au répertoire parent",
|
||||
"Edit": "Modifier",
|
||||
"Copy": "Copier",
|
||||
"Copied": "Copié",
|
||||
"Internal_link": "Afficher le lien interne",
|
||||
"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.",
|
||||
"Share": "Partager",
|
||||
"Share_link": "Lien de téléchargement",
|
||||
"Generate": "Créer",
|
||||
"Add_password_protection": "Ajouter un mot de passe",
|
||||
"Password": "Mot de passe",
|
||||
"At_least_8_characters": "Au moins 8 caractères",
|
||||
"Password_again": "Mot de passe (à nouveau)",
|
||||
"Add_auto_expiration": "Ajouter une date d'expiration",
|
||||
"Days": "jours",
|
||||
"Please_enter_password": "Entrez un mot de passe",
|
||||
"Greater_than_or_equal_to": "Plus grand ou égale à",
|
||||
"Less_than_or_equal_to": "Plus petit ou égal à",
|
||||
"Set_permission": "Définir la permission",
|
||||
"Preview_and_download": "Prévisualiser et télécharger",
|
||||
"Preview_only": "Aperçu uniquement",
|
||||
"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_days": "Veuillez entrer un nombre de jours.",
|
||||
"Password_is_too_short": "Le mot de passe est trop court.",
|
||||
"Passwords_do_not_match": "Les mots de passe ne correspondent pas.",
|
||||
"Return_to_wiki_page": "Retour à la page du Wiki",
|
||||
"Insert_network_image": "Insérer une image du réseau",
|
||||
"Upload_local_image": "Insérer une image locale",
|
||||
"Add_link": "Ajouter un lien",
|
||||
"File_history": "Voir historique",
|
||||
"History_version": "Historique des versions",
|
||||
"Back_to_viewer": "Retour au visualiseur",
|
||||
"Link_title": "Titre du lien",
|
||||
"Local_draft": "Brouillon local",
|
||||
"Use_draft": "Utiliser 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 ?",
|
||||
"Local_draft_saved": "Brouillon local sauvegardé",
|
||||
"New_draft": "Nouveau brouillon",
|
||||
"View_draft": "Voir le brouillon",
|
||||
"Publish": "Publier",
|
||||
"This_file_has_a_draft": "Ce fichier possède un brouillon.",
|
||||
"Delete": "Supprimer",
|
||||
"Comments": "Commentaires",
|
||||
"Add_a_comment": "Ajouter un commentaire",
|
||||
"No_comment_yet": "Aucun commentaire disponible",
|
||||
"Mark_as_Resolved": "Marquer com pris en compte",
|
||||
"ask_for_review": "Demande d'un avis",
|
||||
"review_already_exists": "Un avis existe déjà",
|
||||
"view_review": "Voir l'avis",
|
||||
"there_is_an_associated_review_with_this_file": "Il y a un avis associé à ce fichier.",
|
||||
"start_review": "Commencer l'avis",
|
||||
"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_has_been_updated": "Ce fichier à été mis à jour.",
|
||||
"refresh": "Rafraichir",
|
||||
"related_files": "Fichiers relatifs",
|
||||
"related_file": "Fichier relatif",
|
||||
"no_tags": "Pas de tag",
|
||||
"Ask_for_review": "Demande d'un avis",
|
||||
"Review_already_exists": "Un avis existe déjà.",
|
||||
"View_review": "Voir l'avis",
|
||||
"There_is_an_associated_review_with_this_file": "Il y a un avis associé à ce fichier.",
|
||||
"Start_review": "Commencer l'avis",
|
||||
"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_has_been_updated": "Ce fichier à été mis à jour.",
|
||||
"Refresh": "Rafraichir",
|
||||
"Related_files": "Fichiers relatifs",
|
||||
"Related_file": "Fichier relatif",
|
||||
"No_tags": "Pas de tag",
|
||||
"Date": "Date",
|
||||
"Participants": "Participants",
|
||||
"Meeting_note": "Note de réunion",
|
||||
"Chooser_document_type": "Choisir un type de document",
|
||||
"Empty": "Vide",
|
||||
"no_related_files": "Aucun fichier relatif",
|
||||
"no_out_line": "Pas de contour",
|
||||
"No_related_files": "Aucun fichier relatif",
|
||||
"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.",
|
||||
"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",
|
||||
"Show_side_panel": "Afficher détails",
|
||||
"Show_resolved_comments": "Voir les commentaires pris en compte",
|
||||
@@ -131,25 +131,16 @@
|
||||
"Insert_library_image": "Insérer une image d‘une bibliothèque",
|
||||
"Size": "Taille",
|
||||
"Location": "Emplacement",
|
||||
"Last_Update": "Mise à jour",
|
||||
"Last_update": "Dernière mise à jour",
|
||||
"Tags": "Tags",
|
||||
"Related_Files": "Fichiers relatifs",
|
||||
"Add_participants": "Ajouter des participants",
|
||||
"markdownLint": {
|
||||
"missing_h1": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"Clear_format": "Sans formatage",
|
||||
"Image_address_invalid": "Image address invalid",
|
||||
"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": {
|
||||
"title": "Raccourcis clavier",
|
||||
"userHelpData": [
|
||||
@@ -162,7 +153,8 @@
|
||||
"Insert_child_in_item": "Insérer enfant dans l'élément",
|
||||
"Increase_depth": "Améliorer la profondeur"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Raccourcis en-tête",
|
||||
"shortcutData": {
|
||||
"Heading_1": "Titre 1",
|
||||
@@ -172,7 +164,8 @@
|
||||
"Heading_5": "Titre 5",
|
||||
"Heading_6": "Titre 6"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Raccourcis de blocs de code",
|
||||
"shortcutData": {
|
||||
"Make_code_block": "Faire un bloc de code",
|
||||
@@ -180,37 +173,43 @@
|
||||
"Escape_code_block": "Sortir du bloc de code",
|
||||
"Insert_indent": "Insérer un espace"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Raccourcis blocs de citation",
|
||||
"shortcutData": {
|
||||
"Make_Block_quote": "Faire un bloc de citation",
|
||||
"Escape_Block_quote": "Sortir du bloc de citation"
|
||||
"Make_block_quote": "Make block quote",
|
||||
"Escape_block_quote": "Escape block quote"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Raccourcis tableau",
|
||||
"shortcutData": {
|
||||
"Insert_Table_Row": "Insérer une ligne à la table",
|
||||
"Insert_table_row": "Insert table tow",
|
||||
"Escape_table": "Sortir de la table"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Raccourcis formule",
|
||||
"shortcutData": {
|
||||
"Insert_Formula": "Insérer formule"
|
||||
"Insert_formula": "Insérer formule"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Raccourcis en ligne",
|
||||
"shortcutData": {
|
||||
"Bold": "Gras",
|
||||
"Italic": "Italique",
|
||||
"Italic_Bold": "Italique Gras",
|
||||
"Italic_bold": "Italic bold",
|
||||
"Inline_code": "Ligne de code"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Raccourcis sauvegarde",
|
||||
"shortcutData": {
|
||||
"Save_file": "Sauvegarder le fichier"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Raccourcis image",
|
||||
"shortcutData": {
|
||||
"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",
|
||||
"italic": "Corsivo",
|
||||
"inline_code": "Codice",
|
||||
"header_one": "Titolo 1",
|
||||
"header_two": "Titolo 2",
|
||||
"header_three": "Titolo 3",
|
||||
"header_four": "Titolo 4",
|
||||
"header_five": "Intestazione 5",
|
||||
"header_six": "Intestazione 6",
|
||||
"paragraph": "Paragrafo",
|
||||
"quote": "Citazione",
|
||||
"ordered_list": "Lista ordinata",
|
||||
"unordered_list": "Lista non ordinata",
|
||||
"check_list_item": "Controlla la voce dell'elenco",
|
||||
"insert_image": "Inserisci Immagine",
|
||||
"insert_formula": "Insert Formula",
|
||||
"formula": "Formula",
|
||||
"insert_file": "Insert File",
|
||||
"code": "Codice in linea",
|
||||
"code_block": "Codice",
|
||||
"insert_link": "Inserisci Collegamento",
|
||||
"insert_table": "Inserisci tabella",
|
||||
"save": "Salvare",
|
||||
"more": "Altro",
|
||||
"invalid_url": "URL non valida",
|
||||
"link_address": "Indirizzo collegamento",
|
||||
"image_address": "Indirizzo Immagine",
|
||||
"submit": "Invia",
|
||||
"cancel": "Annulla",
|
||||
"switch_to_plain_text_editor": "Passa all'Editor di testo semplice",
|
||||
"switch_to_rich_text_editor": "Passa all'Editor di testo formattato",
|
||||
"switch_to_viewer": "Passa alla vista di tipo Markdown",
|
||||
"help": "Aiuto",
|
||||
"remove_table": "Rimuovere Tabella",
|
||||
"column": "Colonna",
|
||||
"row": "Riga",
|
||||
"Insert_Row_Before": "Insert Row Before",
|
||||
"Insert_Row_After": "Insert Row After",
|
||||
"Insert_Column_Before": "Insert Column Before",
|
||||
"Insert_Column_After": "Insert Column After",
|
||||
"Remove_Row": "Remove Row",
|
||||
"Remove_Column": "Remove Column",
|
||||
"Insert_Row": "Insert Row",
|
||||
"Insert_Column": "Insert Column",
|
||||
"set_align": "Imposta allineamento",
|
||||
"left": "Sinistra",
|
||||
"center": "Centrato",
|
||||
"right": "Destra",
|
||||
"file_saved": "File salvato.",
|
||||
"file_failed_to_save": "Errore salvataggio file.",
|
||||
"star": "Aggiungi asterisco",
|
||||
"unstar": "Rimozione asterisco",
|
||||
"back_to_parent_directory":"Torna alla cartella precedente",
|
||||
"edit": "Modifica",
|
||||
"copy": "Copia",
|
||||
"copied": "Copiato",
|
||||
"internal_link": "Collegamento interno",
|
||||
"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.",
|
||||
"share": "Condividi",
|
||||
"share_link": "Condividi Collegamento",
|
||||
"generate": "Generare",
|
||||
"add_password_protection": "Aggiungi la protezione password",
|
||||
"password": "Password",
|
||||
"at_least_8_characters": "almeno 8 caratteri",
|
||||
"password_again": "Ridigita password",
|
||||
"add_auto_expiration": "Aggiungi la scadenza automatica",
|
||||
"days": "giorni",
|
||||
"please_enter_password": "Per favore, inserisci la password",
|
||||
"greater_than_or_equal_to": "Maggiore o uguale a ",
|
||||
"less_than_or_equal_to": "Minore o uguale a",
|
||||
"set_permission": "Imposta permessi",
|
||||
"preview_and_download": "Anteprima e scarica",
|
||||
"preview_only": "Solo Anteprima",
|
||||
"please_enter_valid_days": "Si prega di inserire giorni validi",
|
||||
"please_enter_a_non-negative_integer": "Prego inserire un intero non negativo",
|
||||
"please_enter_days": "Prego inserire i giorni",
|
||||
"password_is_too_short": "La password è troppo corta",
|
||||
"passwords_do_not_match": "Le password non corrispondono",
|
||||
"return_to_wiki_page": "Torna alla pagina Wiki",
|
||||
"insert_network_image": "Inserisci immagine di rete",
|
||||
"upload_local_image": "Inserisci immagine locale",
|
||||
"add_link": "Aggiungi collegamento",
|
||||
"file_history": "Cronologia dei file",
|
||||
"history_version": "Versioni cronologia",
|
||||
"back_to_viewer": "Torma alla vista",
|
||||
"link_title": "Link al titolo",
|
||||
"local_draft": "Bozza locale",
|
||||
"use_draft": "Usa bozza",
|
||||
"delete_draft": "Rimuovi Bozza",
|
||||
"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",
|
||||
"new_draft": "Nuova Bozza",
|
||||
"view_draft": "Bozza",
|
||||
"publish": "Pubblica",
|
||||
"this_file_has_a_draft": "Questo file è una bozza",
|
||||
"delete": "Elimina",
|
||||
"comments": "Commenti",
|
||||
"add_a_comment": "Aggiungi un commento...",
|
||||
"no_comment_yet": "Ancora nessun commento.",
|
||||
"Bold": "Grassetto",
|
||||
"Italic": "Corsivo",
|
||||
"Inline_code": "Codice",
|
||||
"Header_one": "Titolo 1",
|
||||
"Header_two": "Titolo 2",
|
||||
"Header_three": "Titolo 3",
|
||||
"Header_four": "Titolo 4",
|
||||
"Header_five": "Intestazione 5",
|
||||
"Header_six": "Intestazione 6",
|
||||
"Paragraph": "Paragrafo",
|
||||
"Quote": "Citazione",
|
||||
"Ordered_list": "Lista ordinata",
|
||||
"Unordered_list": "Lista non ordinata",
|
||||
"Check_list_item": "Controlla la voce dell'elenco",
|
||||
"Insert_image": "Inserisci Immagine",
|
||||
"Insert_formula": "Insert Formula",
|
||||
"Formula": "Formula",
|
||||
"Insert_file": "Insert File",
|
||||
"Code": "Codice in linea",
|
||||
"Code_block": "Codice",
|
||||
"Insert_link": "Inserisci Collegamento",
|
||||
"Insert_table": "Inserisci tabella",
|
||||
"Save": "Salvare",
|
||||
"More": "Altro",
|
||||
"Invalid_url": "URL non valida",
|
||||
"Link_address": "Indirizzo collegamento",
|
||||
"Image_address": "Indirizzo Immagine",
|
||||
"Submit": "Invia",
|
||||
"Cancel": "Annulla",
|
||||
"Switch_to_plain_text_editor": "Passa all'Editor di testo semplice",
|
||||
"Switch_to_rich_text_editor": "Passa all'Editor di testo formattato",
|
||||
"Switch_to_viewer": "Passa alla vista di tipo Markdown",
|
||||
"Help": "Aiuto",
|
||||
"Remove_table": "Rimuovere Tabella",
|
||||
"Column": "Colonna",
|
||||
"Row": "Riga",
|
||||
"Insert_row_before": "Insert row before",
|
||||
"Insert_row_after": "Insert row after",
|
||||
"Insert_column_before": "Insert column before",
|
||||
"Insert_column_after": "Insert column after",
|
||||
"Remove_row": "Remove row",
|
||||
"Remove_column": "Remove column",
|
||||
"Insert_row": "Insert row",
|
||||
"Insert_column": "Insert column",
|
||||
"Set_align": "Imposta allineamento",
|
||||
"Left": "Sinistra",
|
||||
"Center": "Centrato",
|
||||
"Right": "Destra",
|
||||
"File_saved": "File salvato.",
|
||||
"File_failed_to_save": "Errore salvataggio file.",
|
||||
"Star": "Aggiungi asterisco",
|
||||
"Unstar": "Rimozione asterisco",
|
||||
"Back_to_parent_directory": "Torna alla cartella precedente",
|
||||
"Edit": "Modifica",
|
||||
"Copy": "Copia",
|
||||
"Copied": "Copiato",
|
||||
"Internal_link": "Collegamento interno",
|
||||
"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.",
|
||||
"Share": "Condividi",
|
||||
"Share_link": "Condividi Collegamento",
|
||||
"Generate": "Generare",
|
||||
"Add_password_protection": "Aggiungi la protezione password",
|
||||
"Password": "Password",
|
||||
"At_least_8_characters": "almeno 8 caratteri",
|
||||
"Password_again": "Ridigita password",
|
||||
"Add_auto_expiration": "Aggiungi la scadenza automatica",
|
||||
"Days": "giorni",
|
||||
"Please_enter_password": "Per favore, inserisci la password",
|
||||
"Greater_than_or_equal_to": "Maggiore o uguale a ",
|
||||
"Less_than_or_equal_to": "Minore o uguale a",
|
||||
"Set_permission": "Imposta permessi",
|
||||
"Preview_and_download": "Anteprima e download",
|
||||
"Preview_only": "Solo Anteprima",
|
||||
"Please_enter_valid_days": "Si prega di inserire giorni validi",
|
||||
"Please_enter_a_non-negative_integer": "Prego inserire un intero non negativo",
|
||||
"Please_enter_days": "Prego inserire i giorni",
|
||||
"Password_is_too_short": "La password è troppo corta",
|
||||
"Passwords_do_not_match": "Le password non corrispondono",
|
||||
"Return_to_wiki_page": "Torna alla pagina Wiki",
|
||||
"Insert_network_image": "Inserisci immagine di rete",
|
||||
"Upload_local_image": "Inserisci immagine locale",
|
||||
"Add_link": "Aggiungi collegamento",
|
||||
"File_history": "Cronologia dei file",
|
||||
"History_version": "Versioni cronologia",
|
||||
"Back_to_viewer": "Torma alla vista",
|
||||
"Link_title": "Link al titolo",
|
||||
"Local_draft": "Bozza locale",
|
||||
"Use_draft": "Usa bozza",
|
||||
"Delete_draft": "Rimuovi Bozza",
|
||||
"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",
|
||||
"New_draft": "Nuova Bozza",
|
||||
"View_draft": "Bozza",
|
||||
"Publish": "Pubblica",
|
||||
"This_file_has_a_draft": "Questo file è una bozza",
|
||||
"Delete": "Elimina",
|
||||
"Comments": "Commenti",
|
||||
"Add_a_comment": "Aggiungi un commento...",
|
||||
"No_comment_yet": "Ancora nessun commento.",
|
||||
"Mark_as_Resolved": "Mark as Resolved",
|
||||
"ask_for_review": "Richiedi una revisione",
|
||||
"review_already_exists": "Revisione già esistente",
|
||||
"view_review": "Visualizza revisione",
|
||||
"there_is_an_associated_review_with_this_file": "C'è una recensione associata con questo file.",
|
||||
"start_review": "Inizia Revisione",
|
||||
"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_has_been_updated": "Questo file è stato aggiornato.",
|
||||
"refresh": "Aggiornare",
|
||||
"related_files": "file correlati",
|
||||
"related_file": "file correlato",
|
||||
"no_tags": "Nessun tag",
|
||||
"Ask_for_review": "Richiedi una revisione",
|
||||
"Review_already_exists": "Revisione già esistente",
|
||||
"View_review": "Visualizza revisione",
|
||||
"There_is_an_associated_review_with_this_file": "C'è una recensione associata con questo file.",
|
||||
"Start_review": "Inizia Revisione",
|
||||
"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_has_been_updated": "Questo file è stato aggiornato.",
|
||||
"Refresh": "Aggiornare",
|
||||
"Related_files": "file correlati",
|
||||
"Related_file": "file correlato",
|
||||
"No_tags": "Nessun tag",
|
||||
"Date": "Data",
|
||||
"Participants": "Participants",
|
||||
"Meeting_note": "Meeting note",
|
||||
"Chooser_document_type": "Chooser document type",
|
||||
"Empty": "Vuoto",
|
||||
"no_related_files": "Nessun file correlato",
|
||||
"no_out_line": "No outline",
|
||||
"No_related_files": "Nessun file correlato",
|
||||
"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.",
|
||||
"no_document_improvement_suggestion": "No document improvement suggestion",
|
||||
"No_document_improvement_suggestion": "No document improvement suggestion",
|
||||
"Hide_side_panel": "Hide side panel",
|
||||
"Show_side_panel": "Show side panel",
|
||||
"Show_resolved_comments": "Mostra commenti risolti",
|
||||
@@ -131,25 +131,16 @@
|
||||
"Insert_library_image": "Insert library image",
|
||||
"Size": "Dimensione",
|
||||
"Location": "Posizione",
|
||||
"Last_Update": "Ultimo aggiornamento",
|
||||
"Last_update": "Last update",
|
||||
"Tags": "Tag",
|
||||
"Related_Files": "File correlati",
|
||||
"Add_participants": "Add participants",
|
||||
"markdownLint": {
|
||||
"missing_h1": {
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"Clear_format": "Clear format",
|
||||
"Image_address_invalid": "Image address invalid",
|
||||
"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": {
|
||||
"title": "Tasti rapidi",
|
||||
"userHelpData": [
|
||||
@@ -162,7 +153,8 @@
|
||||
"Insert_child_in_item": "Inserisci un elemento figlio sotto questo elemento",
|
||||
"Increase_depth": "Aumenta la profondità"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Scorciatoie principali",
|
||||
"shortcutData": {
|
||||
"Heading_1": "Titolo 1",
|
||||
@@ -172,7 +164,8 @@
|
||||
"Heading_5": "Intestazione 5",
|
||||
"Heading_6": "Intestazione 6"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Scorciatoie di codice",
|
||||
"shortcutData": {
|
||||
"Make_code_block": "Crea un blocco di codice",
|
||||
@@ -180,37 +173,43 @@
|
||||
"Escape_code_block": "Codice di escape",
|
||||
"Insert_indent": "Inserisci indentazione"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Blocco scorciatoie di citazione",
|
||||
"shortcutData": {
|
||||
"Make_Block_quote": "Crea blocco citazioni",
|
||||
"Escape_Block_quote": "Escape Blocco Codice"
|
||||
"Make_block_quote": "Make block quote",
|
||||
"Escape_block_quote": "Escape block quote"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Scorciatoie Tabella",
|
||||
"shortcutData": {
|
||||
"Insert_Table_Row": "Inserisci riga nella tabella",
|
||||
"Insert_table_row": "Insert table tow",
|
||||
"Escape_table": "Escape tabella"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Formula shortcuts",
|
||||
"shortcutData": {
|
||||
"Insert_Formula": "Insert Formula"
|
||||
"Insert_formula": "Insert formula"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Scorciatoie in linea",
|
||||
"shortcutData": {
|
||||
"Bold": "Grassetto",
|
||||
"Italic": "Corsivo",
|
||||
"Italic_Bold": "Corsivo Grassetto",
|
||||
"Italic_bold": "Italic bold",
|
||||
"Inline_code": "Codice in linea"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Salva scorciatoie",
|
||||
"shortcutData": {
|
||||
"Save_file": "Salva file"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Scorciatoie per le immagini",
|
||||
"shortcutData": {
|
||||
"Paste_screen_shot": "Incolla la schermata",
|
||||
@@ -218,5 +217,7 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Select_field": "Select field",
|
||||
"Font_style": "Font style"
|
||||
}
|
||||
|
@@ -1,126 +1,126 @@
|
||||
{
|
||||
"bold": "Полужирный",
|
||||
"italic": "Курсив",
|
||||
"inline_code": "Код",
|
||||
"header_one": "Заголовок 1",
|
||||
"header_two": "Заголовок 2",
|
||||
"header_three": "Заголовок 3",
|
||||
"header_four": "Заголовок 4",
|
||||
"header_five": "Заголовок 5",
|
||||
"header_six": "Заголовок 6",
|
||||
"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": "Недопустимый URL",
|
||||
"link_address": "Адрес ссылки",
|
||||
"image_address": "Адрес изображения",
|
||||
"submit": "Отправить",
|
||||
"cancel": "Отменить",
|
||||
"switch_to_plain_text_editor": "Переключиться на обычный текстовый редактор",
|
||||
"switch_to_rich_text_editor": "Переключиться на визуальный редактор",
|
||||
"switch_to_viewer": "Переключиться на просмотр Markdown",
|
||||
"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": "Комментариев пока нет.",
|
||||
"Bold": "Полужирный",
|
||||
"Italic": "Курсив",
|
||||
"Inline_code": "Код",
|
||||
"Header_one": "Заголовок 1",
|
||||
"Header_two": "Заголовок 2",
|
||||
"Header_three": "Заголовок 3",
|
||||
"Header_four": "Заголовок 4",
|
||||
"Header_five": "Заголовок 5",
|
||||
"Header_six": "Заголовок 6",
|
||||
"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": "Недопустимый URL",
|
||||
"Link_address": "Адрес ссылки",
|
||||
"Image_address": "Адрес изображения",
|
||||
"Submit": "Отправить",
|
||||
"Cancel": "Отменить",
|
||||
"Switch_to_plain_text_editor": "Переключиться на обычный текстовый редактор",
|
||||
"Switch_to_rich_text_editor": "Переключиться на визуальный редактор",
|
||||
"Switch_to_viewer": "Переключиться на просмотр Markdown",
|
||||
"Help": "Помощь",
|
||||
"Remove_table": "Удалить таблицу",
|
||||
"Column": "Столбец",
|
||||
"Row": "Строка",
|
||||
"Insert_row_before": "Insert row before",
|
||||
"Insert_row_after": "Insert row after",
|
||||
"Insert_column_before": "Insert column before",
|
||||
"Insert_column_after": "Insert column after",
|
||||
"Remove_row": "Remove row",
|
||||
"Remove_column": "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": "Отзыв уже существует",
|
||||
"view_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": "Нет меток",
|
||||
"Ask_for_review": "Спросить отзыв",
|
||||
"Review_already_exists": "Отзыв уже существует",
|
||||
"View_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": "Нет контура",
|
||||
"No_related_files": "Нет связанных файлов",
|
||||
"No_out_line": "Нет контура",
|
||||
"Editing_files_in_this_browser_can_lead_to_slight_display_problems": "Изменение файлов в этом браузере может привести к небольшим проблемам с отображением.",
|
||||
"no_document_improvement_suggestion": "Нет предложений по улучшению документа",
|
||||
"No_document_improvement_suggestion": "Нет предложений по улучшению документа",
|
||||
"Hide_side_panel": "Скрыть боковую панель",
|
||||
"Show_side_panel": "Показать боковую панель",
|
||||
"Show_resolved_comments": "Показать разрешённые комментарии",
|
||||
@@ -131,25 +131,16 @@
|
||||
"Insert_library_image": "Вставить изображение библиотеки",
|
||||
"Size": "Размер",
|
||||
"Location": "Местонахождение",
|
||||
"Last_Update": "Последнее обновление",
|
||||
"Last_update": "Последнее обновление",
|
||||
"Tags": "Метки",
|
||||
"Related_Files": "Связанные файлы",
|
||||
"Add_participants": "Добавить участников",
|
||||
"markdownLint": {
|
||||
"missing_h1": {
|
||||
"description": "В документе нет h1",
|
||||
"issue" : "Отсутствует h1"
|
||||
},
|
||||
"heading_end_with_colon": {
|
||||
"description": "Завершающая пунктуация в заголовке не должна быть двоеточием",
|
||||
"issue": "Заголовок заканчивается двоеточием"
|
||||
},
|
||||
"heading_increase_irregular": {
|
||||
"description": "Уровни заголовков должны увеличиваться только на один уровень за раз",
|
||||
"issue": "Проблема уровня заголовка"
|
||||
}
|
||||
},
|
||||
"Clear_format": "Очистить формат",
|
||||
"Image_address_invalid": "Image address invalid",
|
||||
"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": {
|
||||
"title": "Горячие клавиши",
|
||||
"userHelpData": [
|
||||
@@ -162,7 +153,8 @@
|
||||
"Insert_child_in_item": "Вставить дочерний в элемент",
|
||||
"Increase_depth": "Увеличить глубину"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Горячие клавиши для заголовка",
|
||||
"shortcutData": {
|
||||
"Heading_1": "Заголовок 1",
|
||||
@@ -172,7 +164,8 @@
|
||||
"Heading_5": "Заголовок 5",
|
||||
"Heading_6": "Заголовок 6"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Горячие клавиши для кода",
|
||||
"shortcutData": {
|
||||
"Make_code_block": "Создать блок кода",
|
||||
@@ -180,37 +173,43 @@
|
||||
"Escape_code_block": "Выделить блок кода",
|
||||
"Insert_indent": "Вставить отступ"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Горячие клавиши для блока цитаты",
|
||||
"shortcutData": {
|
||||
"Make_Block_quote": "Создать блок цитаты",
|
||||
"Escape_Block_quote": "Выделить блок цитаты"
|
||||
"Make_block_quote": "Make block quote",
|
||||
"Escape_block_quote": "Escape block quote"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Горячие клавиши для таблицы",
|
||||
"shortcutData": {
|
||||
"Insert_Table_Row": "Вставить строку таблицы",
|
||||
"Insert_table_row": "Insert table tow",
|
||||
"Escape_table": "Выделить таблицу"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Горячие клавиши для формул",
|
||||
"shortcutData": {
|
||||
"Insert_Formula": "Вставить формулу"
|
||||
"Insert_formula": "Вставить формулу"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Встроенные горячие клавиши",
|
||||
"shortcutData": {
|
||||
"Bold": "Полужирный",
|
||||
"Italic": "Курсив",
|
||||
"Italic_Bold": "Курсив полужирный",
|
||||
"Italic_bold": "Italic bold",
|
||||
"Inline_code": "Встроенный код"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Сохранить горячие клавиши",
|
||||
"shortcutData": {
|
||||
"Save_file": "Сохранить файл"
|
||||
}
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"shortcutType": "Горячие клавиши для изображений",
|
||||
"shortcutData": {
|
||||
"Paste_screen_shot": "Вставить скриншот",
|
||||
@@ -218,5 +217,7 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Select_field": "Select field",
|
||||
"Font_style": "Font style"
|
||||
}
|
||||
|
@@ -1,121 +1,124 @@
|
||||
{
|
||||
"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": "删除表格",
|
||||
"Insert_Row_Before": "上方插入行",
|
||||
"Insert_Row_After": "下方插入行",
|
||||
"Insert_Column_Before": "左边插入列",
|
||||
"Insert_Column_After": "右边插入列",
|
||||
"Remove_Row": "删除当前行",
|
||||
"Remove_Column": "删除当前列",
|
||||
"Insert_Row": "插入行",
|
||||
"Insert_Column": "插入列",
|
||||
"column": "列",
|
||||
"row": "行",
|
||||
"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": "还没有评论",
|
||||
"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": "评审已存在",
|
||||
"view_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": "参与者",
|
||||
"no_related_files": "没有相关文件",
|
||||
"no_out_line": "没有大纲",
|
||||
"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": "隐藏侧旁栏",
|
||||
@@ -128,24 +131,10 @@
|
||||
"Insert_library_image": "插入资料库图片",
|
||||
"Size": "大小",
|
||||
"Location": "位置",
|
||||
"Last_Update": "更新时间",
|
||||
"Last_update": "更新时间",
|
||||
"Tags": "标签",
|
||||
"Related_Files": "相关文档",
|
||||
"Add_participants": "增加文件参与人",
|
||||
"markdownLint": {
|
||||
"missing_h1": {
|
||||
"description": "文档缺少一级标题",
|
||||
"issue" : "缺少一级标题"
|
||||
},
|
||||
"heading_end_with_colon": {
|
||||
"description": "标题末尾的标点符号不应该是冒号",
|
||||
"issue": "标题末尾是冒号"
|
||||
},
|
||||
"heading_increase_irregular": {
|
||||
"description": "标题级别一次只能增加一级",
|
||||
"issue": "标题级别不规范"
|
||||
}
|
||||
},
|
||||
"Shortcut_help": "快捷键帮助",
|
||||
"userHelp": {
|
||||
"title": "键盘快捷键",
|
||||
@@ -180,40 +169,42 @@
|
||||
}, {
|
||||
"shortcutType": "引用快捷键",
|
||||
"shortcutData": {
|
||||
"Make_Block_quote": "生成引用",
|
||||
"Escape_Block_quote": "退出引用"
|
||||
"Make_block_quote": "生成引用",
|
||||
"Escape_block_quote": "退出引用"
|
||||
}
|
||||
}, {
|
||||
"shortcutType": "表格快捷键",
|
||||
"shortcutData": {
|
||||
"Insert_Table_Row": "插入行",
|
||||
"Insert_table_row": "插入行",
|
||||
"Escape_table": "退出表格"
|
||||
}
|
||||
}, {
|
||||
"shortcutType": "公式快捷键",
|
||||
"shortcutData": {
|
||||
"Insert_Formula": "插入公式"
|
||||
"Insert_formula": "插入公式"
|
||||
}
|
||||
}, {
|
||||
"shortcutType":"行级操作",
|
||||
"shortcutType": "行内快捷键",
|
||||
"shortcutData": {
|
||||
"Bold": "粗体",
|
||||
"Italic": "斜体",
|
||||
"Italic_Bold": "斜体加粗",
|
||||
"Italic_bold": "斜体粗体",
|
||||
"Inline_code": "行内代码"
|
||||
}
|
||||
}, {
|
||||
"shortcutType": "文件保存",
|
||||
"shortcutType": "保存快捷键",
|
||||
"shortcutData": {
|
||||
"Save_file": "保存文件"
|
||||
}
|
||||
}, {
|
||||
"shortcutType": "图片操作",
|
||||
"shortcutType": "图片快捷键",
|
||||
"shortcutData": {
|
||||
"Paste_screen_shot": "上传截图",
|
||||
"Drag_image_from_anywhere_to_upload_it": "拖拽任意图片上传"
|
||||
"Paste_screen_shot": "粘贴屏幕截图",
|
||||
"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