Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/text.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--css/style.scss4
-rw-r--r--lib/Service/DocumentService.php1
-rw-r--r--package.json54
-rw-r--r--src/EditorSync.js33
-rw-r--r--src/components/Editor.vue40
-rw-r--r--src/public.js37
-rw-r--r--webpack.common.js1
7 files changed, 118 insertions, 52 deletions
diff --git a/css/style.scss b/css/style.scss
index df5b00c09..63ae1bf00 100644
--- a/css/style.scss
+++ b/css/style.scss
@@ -15,6 +15,10 @@
display: flex;
height: 100%;
flex-direction: column;
+
+ * {
+ box-sizing: border-box;
+ }
}
.ProseMirror {
diff --git a/lib/Service/DocumentService.php b/lib/Service/DocumentService.php
index 953bbd005..2ccc588ae 100644
--- a/lib/Service/DocumentService.php
+++ b/lib/Service/DocumentService.php
@@ -137,6 +137,7 @@ class DocumentService {
}
// TODO: Only do this when no sessions active, otherise we need to resolve the conflict differently
+ // TODO: Add parameter so that we can force this, else just opening the document will cause a rebuild
$lastMTime = $document->getLastSavedVersionTime();
if ($file->getMTime() > $lastMTime && $lastMTime > 0) {
$this->resetDocument($document->getId());
diff --git a/package.json b/package.json
index 1b3926f86..bdc15b03f 100644
--- a/package.json
+++ b/package.json
@@ -30,32 +30,32 @@
"linkifyjs": "^2.1.8",
"lodash": "^4.17.11",
"nextcloud-axios": "^0.1.3",
- "nextcloud-vue": "^0.9.0",
- "prosemirror": "^0.11.1",
+ "nextcloud-vue": "^0.9.7",
"prosemirror-collab": "^1.1.1",
"prosemirror-example-setup": "^1.0.1",
"prosemirror-history": "^1.0.4",
+ "prosemirror-keymap": "^1.0.1",
"prosemirror-markdown": "^1.3.0",
"prosemirror-menu": "^1.0.5",
"prosemirror-model": "^1.7.0",
- "prosemirror-schema-basic": "^1.0.0",
- "prosemirror-schema-list": "^1.0.2",
- "prosemirror-state": "^1.2.2",
- "prosemirror-view": "^1.8.3",
- "tributejs": "^3.6.0",
+ "prosemirror-schema-basic": "^1.0.1",
+ "prosemirror-schema-list": "^1.0.3",
+ "prosemirror-state": "^1.2.3",
+ "prosemirror-view": "^1.9.4",
+ "tributejs": "^3.7.1",
"twemoji": "^11.3.0",
"uuid": "^3.3.2",
- "v-tooltip": "^2.0.0-rc.33",
- "vue": "^2.6.8",
+ "v-tooltip": "^2.0.2",
+ "vue": "^2.6.10",
"vue-click-outside": "^1.0.7",
"vue-contenteditable-directive": "^1.2.0",
"vue-emoji-picker": "^1.0.1",
- "vue-infinite-loading": "^2.4.3",
- "vue-router": "^3.0.2",
+ "vue-infinite-loading": "^2.4.4",
+ "vue-router": "^3.0.6",
"vue-tribute": "^1.0.2",
"vue-twemoji": "^1.0.1",
- "vuetrend": "^0.3.2",
- "vuex": "^3.1.0",
+ "vuetrend": "^0.3.4",
+ "vuex": "^3.1.1",
"vuex-router-sync": "^5.0.0"
},
"browserslist": [
@@ -66,40 +66,40 @@
"node": ">=10.0.0"
},
"devDependencies": {
- "@babel/core": "^7.3.4",
+ "@babel/core": "^7.4.4",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
- "@babel/preset-env": "^7.3.4",
+ "@babel/preset-env": "^7.4.4",
"@vue/test-utils": "^1.0.0-beta.29",
"acorn": "^6.1.1",
"babel-eslint": "^10.0.1",
- "babel-jest": "^24.3.1",
- "babel-loader": "^8.0.5",
- "css-loader": "^2.1.0",
- "eslint": "^5.15.1",
+ "babel-jest": "^24.8.0",
+ "babel-loader": "^8.0.6",
+ "css-loader": "^2.1.1",
+ "eslint": "^5.16.0",
"eslint-config-standard": "^12.0.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^2.1.1",
- "eslint-plugin-import": "^2.16.0",
+ "eslint-plugin-import": "^2.17.2",
"eslint-plugin-node": "^8.0.1",
- "eslint-plugin-promise": "^4.0.1",
+ "eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.2.2",
"file-loader": "^3.0.1",
- "jest": "^24.0.0",
+ "jest": "^24.8.0",
"jest-serializer-vue": "^2.0.2",
- "node-sass": "^4.11.0",
+ "node-sass": "^4.12.0",
"prettier-eslint": "^8.8.2",
"raw-loader": "^1.0.0",
"sass-loader": "^7.1.0",
"stylelint": "^8.4.0",
- "stylelint-config-recommended-scss": "^3.2.0",
+ "stylelint-config-recommended-scss": "^3.3.0",
"stylelint-webpack-plugin": "^0.10.5",
"vue-jest": "^3.0.4",
"vue-loader": "^15.7.0",
"vue-style-loader": "^4.1.1",
- "vue-template-compiler": "^2.6.8",
- "webpack": "^4.29.6",
- "webpack-cli": "^3.2.3",
+ "vue-template-compiler": "^2.6.10",
+ "webpack": "^4.31.0",
+ "webpack-cli": "^3.3.2",
"webpack-merge": "^4.2.1"
},
"jest": {
diff --git a/src/EditorSync.js b/src/EditorSync.js
index 663f7dc04..67f8646d6 100644
--- a/src/EditorSync.js
+++ b/src/EditorSync.js
@@ -64,12 +64,18 @@ const ERROR_TYPE = {
PUSH_FAILURE: 1
}
-const URL_SYNC = OC.generateUrl('/apps/text/session/sync')
-const URL_PUSH = OC.generateUrl('/apps/text/session/push')
+const baseUrl = OC.generateUrl('/apps/text')
+
+const endpointUrl = (endpoint, isPublic = false) => {
+ if (isPublic) {
+ return `${baseUrl}/public/${endpoint}`
+ }
+ return `${baseUrl}/${endpoint}`
+};
class EditorSync {
- constructor(doc, data) {
+ constructor(doc, data, shareToken) {
this.view = null
this.doc = doc
this.session = data.session
@@ -80,6 +86,7 @@ class EditorSync {
this.retryTime = MIN_PUSH_RETRY
this.dirty = false
this.fetchInverval = FETCH_INTERVAL
+ this.shareToken = shareToken
this.onSyncHandlers = []
this.onErrorHandlers = []
@@ -90,6 +97,10 @@ class EditorSync {
this.fetcher = setInterval(() => this.fetchSteps(), this.fetchInverval)
}
+ isPublic() {
+ return !!this.shareToken
+ }
+
destroy() {
clearInterval(this.fetcher)
}
@@ -136,14 +147,15 @@ class EditorSync {
) {
autosaveContent = this.content()
}
- axios.post(URL_SYNC, {
+ axios.post(endpointUrl('session/sync', this.isPublic()), {
documentId: this.document.id,
sessionId: this.session.id,
- token: this.session.token,
+ sessionToken: this.session.token,
version: authority.steps.length,
autosaveContent,
force: !!this._forcedSave,
- manualSave: !!this._manualSave
+ manualSave: !!this._manualSave,
+ token: this.shareToken
}).then((response) => {
if (this.document.lastSavedVersion < response.data.document.lastSavedVersion) {
console.debug('Saved document', response.data.document)
@@ -255,12 +267,13 @@ class EditorSync {
this.lock = true
const authority = this
let steps = sendable.steps
- axios.post(URL_PUSH, {
+ axios.post(endpointUrl('session/push', this.isPublic()), {
documentId: this.document.id,
sessionId: this.session.id,
- token: this.session.token,
+ sessionToken: this.session.token,
steps: steps.map(s => s.toJSON()) || [],
- version: getVersion(authority.view.state)
+ version: getVersion(authority.view.state),
+ token: this.shareToken
}).then((response) => {
// sucessfully applied steps on the server
steps.forEach(step => {
@@ -289,4 +302,4 @@ class EditorSync {
}
-export { EditorSync, ERROR_TYPE }
+export { EditorSync, ERROR_TYPE, endpointUrl }
diff --git a/src/components/Editor.vue b/src/components/Editor.vue
index 16e24a55b..2b55a9795 100644
--- a/src/components/Editor.vue
+++ b/src/components/Editor.vue
@@ -47,13 +47,13 @@
</button>
</div>
</div>
-</template>c
+</template>
<script>
import axios from 'nextcloud-axios'
import debounce from 'lodash/debounce'
-import { EditorSync, ERROR_TYPE } from './../EditorSync'
+import { EditorSync, ERROR_TYPE, endpointUrl } from './../EditorSync'
import { collab, getVersion } from 'prosemirror-collab'
import { EditorState } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view'
@@ -104,7 +104,7 @@ export default {
document: null,
currentSession: null,
sessions: [],
- name: 'Guest',
+ name: null,
dirty: false,
initialLoading: false,
lastSavedString: '',
@@ -151,10 +151,15 @@ export default {
},
hasUnsavedChanges() {
return this.authority && this.document.lastSavedVersion !== getVersion(this.authority.view.state)
+ },
+ backendUrl() {
+ return (endpoint) => {
+ return endpointUrl(endpoint, !!this.shareToken)
+ }
}
},
- beforeMount() {
- if (this.active || this.shareToken) {
+ mounted() {
+ if (this.active && this.fileId || (this.shareToken)) {
this.initSession()
}
setInterval(() => { this.updateLastSavedStatus() }, 2000)
@@ -166,30 +171,31 @@ export default {
}
},
initSession() {
- if (!this.relativePath && !this.shareToken) {
- console.error('No relative path given')
+ if ((!this.relativePath && !this.fileId) && !this.shareToken ) {
+ console.error('No file given')
this.$emit('error', 'No relative path given')
return
}
- axios.get(OC.generateUrl('/apps/text/session/create'), {
- // TODO: viewer should provide the file id so we can use it in all places (also for public pages)
+ axios.get(this.backendUrl('session/create'), {
params: {
+ fileId: this.fileId,
file: this.relativePath,
- shareToken: this.shareToken
+ token: this.shareToken
}
}).then((response) => {
this.document = response.data.document
this.currentSession = response.data.session
- axios.get(OC.generateUrl('/apps/text/session/fetch'),
+ axios.get(this.backendUrl('session/fetch'),
{
params: {
documentId: this.document.id,
sessionId: this.currentSession.id,
- token: this.currentSession.token
+ sessionToken: this.currentSession.token,
+ token: this.shareToken
}
}
).then((fileContent) => {
- const { authority } = this.initEditor(this.$refs.editor, response.data, fileContent.data)
+ const { authority } = this.initEditor(this.$refs.editor, response.data, fileContent.data, this.shareToken)
this.authority = authority
this.authority.onSync((data) => {
this.syncError = null
@@ -232,8 +238,8 @@ export default {
this.initSession()
},
- initEditor: (ref, data, initialDocument) => {
- const authority = new EditorSync(defaultMarkdownParser.parse(initialDocument), data)
+ initEditor: (ref, data, initialDocument, shareToken) => {
+ const authority = new EditorSync(defaultMarkdownParser.parse(initialDocument), data, shareToken)
const sendStepsDebounce = () => authority.sendSteps()
const sendStepsDebounced = debounce(sendStepsDebounce, EDITOR_PUSH_DEBOUNCE, { maxWait: 500 })
@@ -373,4 +379,8 @@ export default {
</style>
<style lang="scss">
@import './../../css/style';
+
+ #files-public-content {
+ width: 100% !important;
+ }
</style>
diff --git a/src/public.js b/src/public.js
new file mode 100644
index 000000000..abebe549a
--- /dev/null
+++ b/src/public.js
@@ -0,0 +1,37 @@
+import Vue from 'vue'
+import Editor from './components/Editor'
+import { documentReady } from './helpers'
+
+__webpack_nonce__ = btoa(OC.requestToken) // eslint-disable-line
+
+Vue.prototype.t = t
+Vue.prototype.OCA = OCA
+
+documentReady(() => {
+ const sharingToken = document.getElementById('sharingToken').value
+ const dir = document.getElementById('dir').value
+ const mimetype = document.getElementById('mimetype').value
+
+ // Load regular viewer integration
+ if (dir !== '') {
+ // TODO: implement for public file lists
+ // import('./files')
+ }
+
+ const container = document.createElement('div')
+ container.id = 'texteditor'
+ const body = document.getElementById('app-content');
+ body.append(container);
+
+ if (mimetype === 'text/markdown') {
+ const vm = new Vue({
+ render: h => h(Editor, {
+ props: {
+ active: true,
+ shareToken: sharingToken
+ }
+ })
+ })
+ vm.$mount(document.getElementById('preview'))
+ }
+})
diff --git a/webpack.common.js b/webpack.common.js
index 4b1a9dff1..b4f92be4a 100644
--- a/webpack.common.js
+++ b/webpack.common.js
@@ -6,6 +6,7 @@ module.exports = {
entry: {
type: path.join(__dirname, 'src', 'main.js'),
files: path.join(__dirname, 'src', 'files.js'),
+ public: path.join(__dirname, 'src', 'public.js'),
},
output: {
path: path.resolve(__dirname, './js'),