Giter Site home page Giter Site logo

nextcloud / text Goto Github PK

View Code? Open in Web Editor NEW
505.0 13.0 82.0 1.62 GB

📑 Collaborative document editing using Markdown

License: GNU Affero General Public License v3.0

JavaScript 65.52% PHP 18.04% Vue 15.23% Makefile 0.06% Shell 0.13% Dockerfile 0.07% SCSS 0.80% HTML 0.15%
text markdown collaboration tiptap prosemirror vue nextcloud nextcloud-app wysiwyg wysiwyg-editor

text's Introduction

Nextcloud Text

GitHub Workflow Status Start contributing

📑 Collaborative document editing!

Features

  • 📝 Simple focused writing: No distractions, only the formatting you need.
  • 🙋 Work together: Share and collaborate with friends and colleagues, no matter if they use Nextcloud or not!
  • 💾 Open format: Files are saved as Markdown, so you can edit them from any other text app too.
  • ✊ Strong foundation: We use 🐈 tiptap which is based on 🦉 ProseMirror – huge thanks to them!

Nextcloud Text is the default text editor since Nextcloud 17. To start editing just open an existing markdown or plaintext file or create a new one.

Configuration

The rich workspaces in the file list can be disabled either by the users in the files app settings or globally by the admin with the following occ command:

occ config:app:set text workspace_available --value=0

🏗 Development setup

This app requires the main branch of the Viewer app to be installed and enabled. Follow its development setup and then continue here.

  1. ☁ Clone this app into the apps folder of your Nextcloud: git clone https://github.com/nextcloud/text.git
  2. 👩‍💻 In the folder of the app, run the command make to install dependencies and build the Javascript.
  3. ✅ Enable the app through the app management of your Nextcloud
  4. 🎉 Partytime! Help fix some issues and review pull requests 👍

🧙 Advanced development stuff

To build the Javascript whenever you make changes, instead of the full make you can also run npm run build. Or run npm run watch to rebuild on every file save.

🐞 Testing the app

Currently, this app uses three different kinds of tests:

For testing the backend (PHP) Psalm and PHPUnit are used, you can run the testcases (placed in tests/) using the composer scripts psalm and test:unit.

For testing the frontend jest is used for unittests, whereas cypress is used for end2end testing. The unittests are also placed in src/tests/, the cypress tests are placed in cypress/. You can run the tests using the package scripts npm run test (jest), and respective npm run test:cypress (cypress).

Please note the cypress tests require a nextcloud server running, the if no running server is detected a docker container will be started, this requires the current user to be in the docker group. Or you might set the CYPRESS_baseUrl environment variable for a custom nextcloud server.

Adding support for other mime types

  • The mime type needs to be known by Nextcloud server (see nextcloud/server#24488 for how this can be added)
  • Once that is there, please open a pull request to add them to

    text/src/helpers/mime.js

    Lines 35 to 61 in 12df66f

    const openMimetypesMarkdown = [
    'text/markdown',
    ]
    const openMimetypesPlainText = [
    'text/plain',
    'application/cmd',
    'application/x-empty',
    'application/x-msdos-program',
    'application/javascript',
    'application/json',
    'application/x-perl',
    'application/x-php',
    'application/x-tex',
    'application/xml',
    'application/yaml',
    'text/css',
    'text/html',
    'text/org',
    'text/x-c',
    'text/x-c++src',
    'text/x-h',
    'text/x-java-source',
    'text/x-ldif',
    'text/x-python',
    'text/x-shellscript',
    ]
  • You can test them like other mime types in cypress/e2e/files.spec.js

🛠️ Integrate text in your app

Load the editor

In order to load the editor in your app, you'll need to dispatch an event.

if (class_exists(LoadEditor::class)) {
	$this->eventDispatcher->dispatchTyped(new LoadEditor());
}

Integrate a file editor

Make sure to check if OCA.Text is available as the Text app needs to be enabled. If you want your app to work without Text being installed, you will need to provide an editor fallback on your own.

window.OCA.Text.createEditor({
	el: document.getElementById('my-editor-div'),
	fileId: 12345,
	filePath: '/Readme.md',
}).then((editor) => {
	// Once ready you can access the editor instance and call methods like:

	editor.setContent('new content') // Beware: this will overwrite the content read from the source file
	editor.setReadOnly(true)
	editor.insertAtCursor('<h1>Heading</h1>')

	// Make sure to destory the editor instance once you remove the dom element
	editor.destroy()
})

Markdown based content editor

window.OCA.Text.createEditor({
	el: document.getElementById('my-editor-div'),
	content: 'initial content',
}).then((editor) => {
	// Once ready you can access the editor instance and call methods like:

	editor.setContent('new content')
	editor.setReadOnly(true)
	editor.insertAtCursor('<h1>Heading</h1>')

	// Make sure to destory the editor instance once you remove the dom element
	editor.destroy()
})

text's People

Contributors

azul avatar blizzz avatar christophwurst avatar danxuliu avatar dependabot-preview[bot] avatar dependabot[bot] avatar elzody avatar github-actions[bot] avatar jancborchardt avatar julien-nc avatar juliushaertl avatar luka-nextcloud avatar marcelklehr avatar max-nextcloud avatar mejo- avatar morrisjobke avatar nextcloud-bot avatar nextcloud-command avatar nickvergessen avatar npmbuildbot[bot] avatar pvince81 avatar pytal avatar raudius avatar renovate[bot] avatar rullzer avatar shgkme avatar skjnldsv avatar susnux avatar szaimen avatar valdnet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

text's Issues

Integration tests

We should have the important backend functions covered with integration test, especially logic related to pushing steps and save collision handling.

"Error loading text document"

On opening an .md file, I get this error:
error loading text document

Browser console:

oc_config is deprecated: use OC.config instead     globals.js:26:2
No relative path given    Editor.vue:170
The escapeHTML library is deprecated! It will be removed in nextcloud 19. globals.js:26:2

Any idea @juliushaertl?

File changes from outside

Since we discussed going for a file based solution, we need to take care that file changes from outside are handled properly. If no one is currently editing a file in the collaborative editor this is not an issue, since once the first session is opened, we just read the current file and continue from that. But once there is a user editing, we have a base version and a list of changes on top of that managed by prosemirror. There is no way we can properly apply the changes in the original file (done when overwriting the file) to the collaborative editing. So we would either need to lock the file for the whole time any user is using the collaborative editor or have some conflict resolution. That would for example be to let the user choose if the file version or the current editing version should be used.

Just for reference, the current collaborative editing works the following way:

  1. On first open a copy of the file is made and used as the base document
  2. Prosemirror is converting markdown to a prosemirror own json format
  3. Changes made are pushed to the server and distributed to the active editing sessions
  4. The clients can apply the changes to the base document
  5. Writing back the file needs to happen at some point (see #4 for that)

I don't feel comfortable with just locking the file for the whole time, this is why I thought once a collision happens, we could just ask the user which of the two versions we should keep. After that we would re-initiate all collaborative sessions to use the new file as base document.

Any input on that is welcome, maybe someone also has some different idea.

cc @rullzer

Uncaught TypeError: Cannot read property 'registerHandler' of undefined

Sometimes I get a race condition

files.js:54 Uncaught TypeError: Cannot read property 'registerHandler' of undefined
    at files.js:54
(anonymous) @ files.js:54
setTimeout (async)
e @ helpers.js:28
r @ helpers.js:30
(anonymous) @ files.js:53
n @ bootstrap:19
(anonymous) @ bootstrap:83
(anonymous) @ bootstrap:83
09:32:37.074 

Please use the DOMContentLoaded event for that :)

https://developer.mozilla.org/en-US/docs/Web/API/Window/DOMContentLoaded_event

"Select parent node" option needed?

When you select something like list items, there is a "select parent node" button in the controls bar (the dotted square). It doesn’t really seem to be useful, or what is it for?

Clicking outside of image picker (to close it) closes Text app instead

If you click outside the file picker, you expect it to be closed. What currently happens if you click outside (if it also is outside the Text app) is that the Text app is closed but the filepicker is still there.

  1. If the Text app is closed, invoked filepickers from there should be closed?
  2. The first click outside of the filepicker should close it.

filepicker still open

Name input should not be mandatory step to join share

When joining a share link I’m faced with this:
public editor

Feels quite intrusive and strange. If I got the link it’s also fine to join as a guest and then set the name. This puts a barrier between people just quickly checking out the document and should not be there.

Warnings during npm install and npm run build

Some warnings during the setup commands – doesn’t break but looks off:

jan@Rechenknecht:~/nextcloud/apps/text$ npm install
npm WARN [email protected] requires a peer of stylelint-scss@^2.0.0 || ^3.0.0 but none is installed. You must install peer dependencies yourself.
npm WARN [email protected] requires a peer of babel-core@^6.25.0 || ^7.0.0-0 but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

audited 878251 packages in 15.26s
found 2 vulnerabilities (1 low, 1 high)
  run `npm audit fix` to fix them, or `npm audit` for details
jan@Rechenknecht:~/nextcloud/apps/text$ npm run build

> [email protected] build /home/jan/nextcloud/apps/text
> webpack --progress --hide-modules --config webpack.prod.js

Hash: 6169939a3b0d51aa74eb                                                             
Version: webpack 4.31.0
Time: 38316ms
Built at: 2019-05-14 15:50:03
        Asset      Size  Chunks                    Chunk Names
     files.js   524 KiB       0  [emitted]  [big]  files
 files.js.map  1.73 MiB       0  [emitted]         files
    public.js   618 KiB       1  [emitted]  [big]  public
public.js.map  2.21 MiB       1  [emitted]         public
      type.js   616 KiB       2  [emitted]  [big]  type
  type.js.map  2.21 MiB       2  [emitted]         type
Entrypoint type [big] = type.js type.js.map
Entrypoint files [big] = files.js files.js.map
Entrypoint public [big] = public.js public.js.map

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets: 
  files.js (524 KiB)
  public.js (618 KiB)
  type.js (616 KiB)

WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
  type (616 KiB)
      type.js
  files (524 KiB)
      files.js
  public (618 KiB)
      public.js


WARNING in webpack performance recommendations: 
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

Inserting links flow

(TL;DR would be so awesome to use tiptap instead #8 since it fixes a looot of our basic UX issues)

link dialog

  • When having marked text and then inserting a link, the "Title" field should be prefilled with the text you selected? Or what is it?
  • "Link target" is very technical, just say "Link https://…"
  • "Ok" is too generic. "Insert link" is better, and the button should be on the right, cancel on the left.

With https://tiptap.scrumpy.io/links this would all be nice and not needed, so we should maybe just move? ;)

Consider moving to tiptap

tiptap is an editor that is based on prosemirror and has a nice API built around the prosemirror framework, which would save us quite some development effort when adding more features.

Requirements:

Ideally we should also run some tests against the commonmark spec: https://spec.commonmark.org/0.29/spec.json

Future plans for mobile

Just to sum up the discussion we had via email on the plans for mobile:

We do it step by step:

  1. Server app should be responsive and work on mobile (we need this anyway for share links)
  2. Integration into mobile app via webview
  3. (Possible desktop integration via webview)
  4. Estimate native mobile integration, maybe something with the Android Notes app?
  5. (Possibility to join shared documents without an account via the app, similar to proposal for Talk: nextcloud/talk-android#261 – only makes sense once there is native mobile integration)

cc @rullzer @tobiasKaminsky @juliushaertl

Helping people write better / grading readability

This is a "maybe someday" feature, but just opening it as an issue so it doesn’t get lost:

We could have a mode which helps people write better by rating the readability of their text. This mostly applies if you work on blog posts or essays. I’m imagining something similar to https://hemingwayapp.com

In write mode:
hemingway-writemode

In edit mode (as in "being the Editor"):
hemingway

Top header bar takes unnecessary space and focus

In the Text app, unlike when viewing photos, we still show the blue header bar:
header bar is shown not really useful and on mobile we have very little space

This has several issues:

  • The bright blue bar takes a lot of focus away from the actual content and the text.
  • None of the controls are really useful, and they all take you out of the document when you accidentally click them.
  • Especially on mobile, and when the keyboard is out, it takes a considerable amount of screen space that we don’t have.

→ We should overlay the header bar with the dark part, just like we do with the Viewer when looking at pictures etc.

What we could do to retain some branding is show the Nextcloud logo in the top left in white.

Some link popover issues

The link popover is not centered above the text, has grey highlight and white border around it (could just be white) and could use a triangle on the bottom to point to the text. (Also, if it’s just inserting the link, we can add text "Insert link"):
link popover not centered and has some stuff around it

The next step should be centered too, triangle too, and could also still highlight the selected word? Also, when you put in something without https:// or http://, it should be automatically prepended:
popover not centered and doesn’t highlight word and doesnt have a triangle

Refresh closes editor

If you refresh the browser, the Files view is shown. I’d expect the document to open again as we know the url?

Menu bar and actions design

When you click open the menu, the first entry looks as if it’s active. Also, the headings could use a better icon?
menu click open first entry looks as if active and h icons use paragraph icon

If a style like h5 is set, it should be highlighted as active in the menu:
current style should be highlighted as active

The code block is duplicated in the menu. I’d say we should only put the h4, h5 and h6 in the menu, and blockquote inbetween strikethrough and code block (or remove code block from the menu bar – but quote is definitely more relevant than code):
code block action is duplicate  I’d only put the headings in the 3-dot menu and blockquote is more important than code

Bunch of errors and warnings during make

The make command has a bunch of errors and it results in the Text app not working here. Let me know if you need more info to fix it @juliushaertl :)

jan@Rechenknecht:~/nextcloud/apps/text$ make
rm -f js/*
rm -rf node_modules
npm install

> [email protected] install /home/jan/nextcloud/apps/text/node_modules/node-sass
> node scripts/install.js

Cached binary found at /home/jan/.npm/node-sass/4.12.0/linux-x64-67_binding.node

> [email protected] postinstall /home/jan/nextcloud/apps/text/node_modules/core-js-pure
> node scripts/postinstall || echo "ignore"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js on Open Collective or Patreon: 
> https://opencollective.com/core-js 
> https://www.patreon.com/zloirock 

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> [email protected] postinstall /home/jan/nextcloud/apps/text/node_modules/node-sass
> node scripts/build.js

Binary found at /home/jan/nextcloud/apps/text/node_modules/node-sass/vendor/linux-x64-67/binding.node
Testing binary
Binary is fine

> [email protected] postinstall /home/jan/nextcloud/apps/text/node_modules/webpack-cli
> node ./bin/opencollective.js



                            Thanks for using Webpack!
                 Please consider donating to our Open Collective
                        to help us maintain this package.



                 Donate: https://opencollective.com/webpack/donate


npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})

added 1299 packages from 958 contributors in 37.117s
npm run lint

> [email protected] lint /home/jan/nextcloud/apps/text
> eslint --ext .js,.vue src


/home/jan/nextcloud/apps/text/src/components/Editor.vue
   25:33   warning  Attribute "v-if" should go before "id"                                                  vue/attributes-order
   30:1    error    Expected indentation of 4 tabs but found 5 tabs                                         vue/html-indent
   31:1    error    Expected indentation of 4 tabs but found 5 tabs                                         vue/html-indent
   32:1    error    Expected indentation of 4 tabs but found 5 tabs                                         vue/html-indent
   41:39   warning  Attribute "v-slot" should go before ":editor"                                           vue/attributes-order
   41:71   warning  Attribute "v-if" should go before ":editor"                                             vue/attributes-order
   43:7    warning  Require self-closing on HTML elements (<button>)                                        vue/html-self-closing
   44:7    warning  Require self-closing on HTML elements (<button>)                                        vue/html-self-closing
   45:7    warning  Require self-closing on HTML elements (<button>)                                        vue/html-self-closing
   47:112  warning  Expected 1 line break after opening tag (`<button>`), but no line breaks found          vue/singleline-html-element-content-newline
   47:114  warning  Expected 1 line break before closing tag (`</button>`), but no line breaks found        vue/singleline-html-element-content-newline
   48:112  warning  Expected 1 line break after opening tag (`<button>`), but no line breaks found          vue/singleline-html-element-content-newline
   48:114  warning  Expected 1 line break before closing tag (`</button>`), but no line breaks found        vue/singleline-html-element-content-newline
   49:112  warning  Expected 1 line break after opening tag (`<button>`), but no line breaks found          vue/singleline-html-element-content-newline
   49:114  warning  Expected 1 line break before closing tag (`</button>`), but no line breaks found        vue/singleline-html-element-content-newline
   50:7    error    Component name "Actions" is not kebab-case                                              vue/component-name-in-template-casing
   51:8    error    Component name "ActionButton" is not kebab-case                                         vue/component-name-in-template-casing
   51:84   warning  Expected 1 line break after opening tag (`<ActionButton>`), but no line breaks found    vue/singleline-html-element-content-newline
   51:93   warning  Expected 1 line break before closing tag (`</ActionButton>`), but no line breaks found  vue/singleline-html-element-content-newline
   52:8    error    Component name "ActionButton" is not kebab-case                                         vue/component-name-in-template-casing
   52:84   warning  Expected 1 line break after opening tag (`<ActionButton>`), but no line breaks found    vue/singleline-html-element-content-newline
   52:93   warning  Expected 1 line break before closing tag (`</ActionButton>`), but no line breaks found  vue/singleline-html-element-content-newline
   53:8    error    Component name "ActionButton" is not kebab-case                                         vue/component-name-in-template-casing
   53:84   warning  Expected 1 line break after opening tag (`<ActionButton>`), but no line breaks found    vue/singleline-html-element-content-newline
   53:93   warning  Expected 1 line break before closing tag (`</ActionButton>`), but no line breaks found  vue/singleline-html-element-content-newline
   54:8    error    Component name "ActionButton" is not kebab-case                                         vue/component-name-in-template-casing
   54:70   warning  Expected 1 line break after opening tag (`<ActionButton>`), but no line breaks found    vue/singleline-html-element-content-newline
   54:80   warning  Expected 1 line break before closing tag (`</ActionButton>`), but no line breaks found  vue/singleline-html-element-content-newline
   55:8    error    Component name "ActionButton" is not kebab-case                                         vue/component-name-in-template-casing
   55:71   warning  Expected 1 line break after opening tag (`<ActionButton>`), but no line breaks found    vue/singleline-html-element-content-newline
   55:81   warning  Expected 1 line break before closing tag (`</ActionButton>`), but no line breaks found  vue/singleline-html-element-content-newline
   58:7    warning  Require self-closing on HTML elements (<button>)                                        vue/html-self-closing
   59:7    warning  Require self-closing on HTML elements (<button>)                                        vue/html-self-closing
   61:7    warning  Require self-closing on HTML elements (<button>)                                        vue/html-self-closing
   64:78   error    Event "hide" should be on a new line                                                    vue/max-attributes-per-line
   64:99   error    Directive "slot" should be on a new line                                                vue/max-attributes-per-line
   64:99   warning  Attribute "v-slot" should go before "@hide"                                             vue/attributes-order
   65:129  warning  Expected 1 line break after opening tag (`<div>`), but 2 line breaks found              vue/multiline-html-element-content-newline
   67:38   warning  Attribute "v-if" should go before "class"                                               vue/attributes-order
   68:8    warning  Disallow self-closing on HTML void elements (<input/>)                                  vue/html-self-closing
   68:53   warning  Attribute "v-model" should go before "type"                                             vue/attributes-order
   68:71   error    Attribute "placeholder" should be on a new line                                         vue/max-attributes-per-line
   68:94   error    Attribute "ref" should be on a new line                                                 vue/max-attributes-per-line
   68:94   warning  Attribute "ref" should go before "placeholder"                                          vue/attributes-order
   68:110  error    Event "keydown" should be on a new line                                                 vue/max-attributes-per-line
   68:137  error    Expected a space before '/>', but not found                                             vue/html-closing-bracket-spacing
   69:8    warning  Require self-closing on HTML elements (<button>)                                        vue/html-self-closing
   69:84   warning  Attribute "type" should go before "@click"                                              vue/attributes-order
   74:1    error    Expected indentation of 8 tabs but found 9 tabs                                         vue/html-indent
   75:1    error    Expected indentation of 8 tabs but found 9 tabs                                         vue/html-indent
   76:1    error    Expected indentation of 8 tabs but found 9 tabs                                         vue/html-indent
   76:10   warning  Attribute ":class" should go before "@click"                                            vue/attributes-order
   76:51   error    Expected no line breaks before closing bracket, but 1 line break found                  vue/html-closing-bracket-newline
   77:9    warning  Expected 1 line break after opening tag (`<button>`), but no line breaks found          vue/multiline-html-element-content-newline
   77:62   warning  Expected 1 space before '}}', but not found                                             vue/mustache-interpolation-spacing
   77:71   warning  Expected 1 line break before closing tag (`</button>`), but no line breaks found        vue/multiline-html-element-content-newline
   78:18   warning  Expected 1 line break before closing tag (`</div>`), but 2 line breaks found            vue/multiline-html-element-content-newline
   98:5    warning  Disallow self-closing on HTML void elements (<input/>)                                  vue/html-self-closing
   98:24   warning  Attribute "v-model" should go before "type"                                             vue/attributes-order
   99:5    warning  Disallow self-closing on HTML void elements (<input/>)                                  vue/html-self-closing
  107:8    error    'debounce' is defined but never used                                                    no-unused-vars
  109:10   error    'EditorSync' is defined but never used                                                  no-unused-vars
  120:2    error    'Bold' is defined but never used                                                        no-unused-vars
  130:15   error    Unexpected trailing comma                                                               comma-dangle
  135:1    error    More than 1 blank line not allowed                                                      no-multiple-empty-lines
  145:7    error    'EDITOR_PUSH_DEBOUNCE' is assigned a value but never used                               no-unused-vars
  200:27   error    Unexpected trailing comma                                                               comma-dangle
  242:65   error    Multiple spaces found before '&&'                                                       no-multi-spaces
  285:14   error    Unexpected space before function parentheses                                            space-before-function-paren
  297:20   error    A space is required after '{'                                                           object-curly-spacing
  297:38   error    A space is required before '}'                                                          object-curly-spacing
  302:20   error    A space is required after '{'                                                           object-curly-spacing
  302:39   error    A space is required before '}'                                                          object-curly-spacing
  307:46   error    Extra semicolon                                                                         semi
  310:29   error    A space is required after '{'                                                           object-curly-spacing
  310:62   error    A space is required before '}'                                                          object-curly-spacing
  312:20   error    A space is required after '{'                                                           object-curly-spacing
  312:54   error    A space is required before '}'                                                          object-curly-spacing
  313:12   error    'documentData' is assigned a value but never used                                       no-unused-vars
  313:27   error    A space is required after '{'                                                           object-curly-spacing
  313:45   error    A space is required before '}'                                                          object-curly-spacing
  314:12   error    'initialDocument' is assigned a value but never used                                    no-unused-vars
  316:49   error    A space is required after '{'                                                           object-curly-spacing
  316:61   error    A space is required before '}'                                                          object-curly-spacing
  316:63   error    Extra semicolon                                                                         semi
  319:18   error    A space is required after '{'                                                           object-curly-spacing
  319:24   error    A space is required before '}'                                                          object-curly-spacing
  320:8    error    Unexpected console statement                                                            no-console
  320:20   error    Strings must use singlequote                                                            quotes
  321:8    error    Unexpected console statement                                                            no-console
  325:8    error    Missing '()' invoking a constructor                                                     new-parens
  326:8    error    Missing '()' invoking a constructor                                                     new-parens
  327:8    error    Missing '()' invoking a constructor                                                     new-parens
  328:8    error    Missing '()' invoking a constructor                                                     new-parens
  329:8    error    Missing '()' invoking a constructor                                                     new-parens
  330:8    error    Missing '()' invoking a constructor                                                     new-parens
  331:8    error    Missing '()' invoking a constructor                                                     new-parens
  332:8    error    Missing '()' invoking a constructor                                                     new-parens
  333:8    error    Missing '()' invoking a constructor                                                     new-parens
  334:8    error    Missing '()' invoking a constructor                                                     new-parens
  335:8    error    Missing '()' invoking a constructor                                                     new-parens
  336:8    error    Missing '()' invoking a constructor                                                     new-parens
  353:10   error    Unexpected console statement                                                            no-console
  353:35   error    Extra semicolon                                                                         semi
  354:21   error    Extra semicolon                                                                         semi
  357:8    error    Unexpected trailing comma                                                               comma-dangle
  363:18   error    A space is required after '{'                                                           object-curly-spacing
  363:34   error    A space is required before '}'                                                          object-curly-spacing
  377:30   error    A space is required after '{'                                                           object-curly-spacing
  377:46   error    A space is required before '}'                                                          object-curly-spacing
  387:26   error    Expected consistent spacing                                                             standard/object-curly-even-spacing
  387:72   error    A space is required before '}'                                                          object-curly-spacing
  392:27   error    A space is required after '{'                                                           object-curly-spacing
  392:60   error    A space is required before '}'                                                          object-curly-spacing
  403:36   error    A space is required after ','                                                           comma-spacing
  405:10   error    'stillExistingSessions' is assigned a value but never used                              no-unused-vars
  451:46   error    Multiple spaces found before '('                                                        no-multi-spaces
  457:4    error    Unexpected trailing comma                                                               comma-dangle
  577:1    error    More than 1 blank line not allowed                                                      no-multiple-empty-lines

/home/jan/nextcloud/apps/text/src/EditorSync.js
   25:10  error  'receiveTransaction' is defined but never used                no-unused-vars
   67:1   error  More than 1 blank line not allowed                            no-multiple-empty-lines
  179:8   error  'newData' is assigned a value but never used                  no-unused-vars
  180:4   error  Expected exception block, space or tab after '/*' in comment  spaced-comment
  180:4   error  Expected space or tab before '*/' in comment                  spaced-comment
  273:4   error  Expected exception block, space or tab after '/*' in comment  spaced-comment
  273:4   error  Expected space or tab before '*/' in comment                  spaced-comment

/home/jan/nextcloud/apps/text/src/extensions/Keymap.js
  34:1  error  Block must be padded by blank lines  padded-blocks

/home/jan/nextcloud/apps/text/src/helpers.js
  43:1  error  More than 1 blank line not allowed  no-multiple-empty-lines

/home/jan/nextcloud/apps/text/src/marks/index.js
  30:27  error  Block must be padded by blank lines  padded-blocks
  34:1   error  Block must be padded by blank lines  padded-blocks
  36:35  error  Block must be padded by blank lines  padded-blocks
  40:1   error  Block must be padded by blank lines  padded-blocks

/home/jan/nextcloud/apps/text/src/public.js
  7:1   error  Unexpected console statement              no-console
  7:13  error  '__webpack_public_path__' is not defined  no-undef

/home/jan/nextcloud/apps/text/src/services/PollingBackend.js
   24:8   error  A space is required after '{'                                 object-curly-spacing
   24:19  error  A space is required before '}'                                object-curly-spacing
   25:8   error  A space is required after '{'                                 object-curly-spacing
   25:22  error  A space is required before '}'                                object-curly-spacing
   25:49  error  Extra semicolon                                               semi
   26:1   error  More than 1 blank line not allowed                            no-multiple-empty-lines
   89:9   error  'authority' is assigned a value but never used                no-unused-vars
   91:46  error  '||' should be placed at the beginning of the line            operator-linebreak
   92:45  error  '&&' should be placed at the beginning of the line            operator-linebreak
  114:35  error  A space is required after '{'                                 object-curly-spacing
  114:35  error  Expected consistent spacing                                   standard/object-curly-even-spacing
  123:41  error  Expected consistent spacing                                   standard/object-curly-even-spacing
  123:55  error  A space is required before '}'                                object-curly-spacing
  124:41  error  Expected consistent spacing                                   standard/object-curly-even-spacing
  124:63  error  A space is required before '}'                                object-curly-spacing
  159:9   error  'authority' is assigned a value but never used                no-unused-vars
  160:77  error  Extra semicolon                                               semi
  179:4   error  Expected exception block, space or tab after '/*' in comment  spaced-comment
  179:4   error  Expected space or tab before '*/' in comment                  spaced-comment
  212:32  error  A space is required after ','                                 comma-spacing

/home/jan/nextcloud/apps/text/src/services/SyncService.js
   26:8   error  A space is required after '{'                                     object-curly-spacing
   26:9   error  'Step' is defined but never used                                  no-unused-vars
   26:13  error  A space is required before '}'                                    object-curly-spacing
   26:43  error  Extra semicolon                                                   semi
   27:8   error  A space is required after '{'                                     object-curly-spacing
   27:34  error  A space is required before '}'                                    object-curly-spacing
   32:2   error  Extra semicolon                                                   semi
   45:15  error  Unexpected trailing comma                                         comma-dangle
   48:19  error  Block must be padded by blank lines                               padded-blocks
   49:13  error  Unexpected space before function parentheses                      space-before-function-paren
   63:14  error  Unexpected trailing comma                                         comma-dangle
   83:7   error  A space is required after '{'                                     object-curly-spacing
   83:24  error  A space is required before '}'                                    object-curly-spacing
   84:29  error  A space is required after '{'                                     object-curly-spacing
   84:46  error  A space is required before '}'                                    object-curly-spacing
   87:26  error  Unexpected trailing comma                                         comma-dangle
   89:39  error  A space is required after '{'                                     object-curly-spacing
   89:44  error  A space is required before '}'                                    object-curly-spacing
  106:16  error  A space is required after '{'                                     object-curly-spacing
  106:33  error  A space is required before '}'                                    object-curly-spacing
  136:30  error  Unnecessary use of conditional expression for default assignment  no-unneeded-ternary
  150:16  error  A space is required after '{'                                     object-curly-spacing
  150:32  error  A space is required before '}'                                    object-curly-spacing
  162:3   error  Unexpected console statement                                      no-console
  162:24  error  Extra semicolon                                                   semi
  163:21  error  A space is required after '{'                                     object-curly-spacing
  163:47  error  A space is required before '}'                                    object-curly-spacing
  164:3   error  Unexpected console statement                                      no-console
  223:1   error  Block must be padded by blank lines                               padded-blocks
  225:27  error  Extra semicolon                                                   semi

✖ 184 problems (143 errors, 41 warnings)
  117 errors and 41 warnings potentially fixable with the `--fix` option.

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] lint: `eslint --ext .js,.vue src`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] lint script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/jan/.npm/_logs/2019-06-07T15_30_31_450Z-debug.log
Makefile:47: recipe for target 'lint' failed
make: *** [lint] Error 1

Insert image/file from Nextcloud

  • Open filepicker
  • Insert preview
  • Create a custom image node component
  • Insert private link
  • Dynamically get preview url depending on file id
  • Display placeholder if preview is not available

Persisting changes to files

Prosemirror uses a custom JSON based document format with a list of changes that are applied on top of the base document. We need to store those in the prosemirror format to exchange the transactions between the editing clients. Since the editor is using files as data source, we need to find a way to properly sync back changes to the original file.

Solution 1: Let client build the final document

  • Either autosave or send full document on every push
  • Rely on existing prosemirror code
  • Possible outdated documents when clients loose connections before saving
    • Note that once the editor connects back, those edits are still there, but they might be overwritten by a regular file upload
  • Additional runtime and data transfer overhead on save

Solution 2: Building the document on the server

@rullzer Any other ideas on that?

Inserting images flow (and error)

Inserting an image shows this dialog:
image insertion dialog design

Several issues:

  • Should have rounded corners like our default dialog
  • Heading should be styled as heading as in the default dialog.
  • Is too small / narrow so the fields are very small
  • "Ok" button should be on the right and read "Insert image"
  • Unclear what "Location" is? I guess "Link https://…" would work better?
  • What is the difference between "Title" and "Description"? Also I guess both are optional
  • Probably advanced, but could we have a simple picker for picking from Files or from computer?

Then I get this error in the console:

Content Security Policy: The page’s settings blocked the loading of a resource at https://raw.githubusercontent.com/nextcloud/promo/master/nextcloud-logo.png (“img-src”).

Whitespace at bottom of document

Is it possible to have some whitespace at the bottom of the document?
some whitespace at the bottom would be nice

Just like we have at the bottom of the Files app, 250px to make clear the list is over:
files app bottom whitespace

I didn’t want to mess with any padding or margin since in some editors I had issues with then lines on the top hiding too early / showing too late.

Link share view design issues

Only 2 things:

  • The scroll container should be the whole width, that is the scrollbar should be at the right edge
  • The footer with Nextcloud info should be at the bottom, that is not visible when the document is longer than the viewport (scroll container whole height of app-content)

public text view

Double avatar shown on document reopen

I closed the document and opened it again, then there were two me's! :D
two jans

Generally yourself does not need to be shown at all I’d say? Or only if at least one other person is in the document?

Buttons too small

We should comply with the 44px rule :)

Also, they need to be rounded (background is shown as square-ish), You could also use the Action component if you want, it will receive future updates with that ;)

Right sidebar not fully shown?

The sidebar looks a bit buggy, it’s not fully shown (no tabs) and stuck to the top? Shouldn’t it just show the regular sidebar which shows in Files too, with comments and such? (Also, there’s no way to close it again.)
sidebar not fully shown and content stuck to top, also how to close

Line length is too long

Our line length currently goes up to ~105 characters, which is a bit much. Also, there could be a bit more whitespace to the sides:
line length 105 characters

With padding: 20px 114px; it looks like this with ~80 characters:
line length 80

(Just as demo. Of course it doesn’t work responsively with the set padding, but max-width does not work because the scrollbars are on that container.)

From https://en.wikipedia.org/wiki/Line_length:

Traditional line length research, limited to print based text, resulted in a variety of results but generally for printed text it is widely accepted that line length fall between 45–75 characters per line (cpl), though the ideal is 66 cpl (including letters and spaces).

I used 80 chars cause lots of our target audience might use that as a standard. ;)

Viewer integration issues

There are some issues with the viewer integration:

  • Keyboard events should be disabled (arrow, enter should only be catched by the editor, not the viewer)
  • Expose the file id to the viewer component
  • Overwrite max-width for mobile view, so that the editor is shown full size on small screens
  • We probably don't need navigation between documents with the arrows
  • Slideshow doesn't make sense for documents

Sometimes permanent scrollbars show

Sometimes when I open the editor, permanent scrollbars show both vertically and horizontally. This is especially visible with the dark system theme:
scrollbars

(Container should probably have some kind of overflow:hidden?)

Regarding the Notes app

Now the main thing we are doing with the Text app is replacing files_texteditor and offer a lightweight collaborative document alternative.

But we also overlap a lot with the simple Notes app. Maybe we should talk with the contributors (korelstar and stefan-niedermann) there ahead of time since it seems that when the Text app is fully fleshed out, Notes is a bit redundant. Since the design goal with Notes from the beginning was simplicity, then if the Text app is using the Viewer then it’s even more simple and focused as it doesn’t even show a left sidebar.

Or what we could keep in mind for Text and / or viewer is possibly have a left list on the side which could be expanded to show other documents in the folder for quick switching?

Not entirely sure here, what do you think @juliushaertl @skjnldsv?

Ability to insert images from local device (or link)

It would be nice if it’s possible to also insert images from the local device into the document. For example:

  • The image icon shows a popover having 2 options: "Image from Nextcloud" and "Image from device"
  • "Image from Nextcloud" shows the current picker"
  • "Image from device" shows a native file picker
  • The image is uploaded in the background – we have to probably decide where to. We shouldn’t necessarily make the same mistake as in Talk and dump it into the root folder – maybe it doesn’t even need to be visible at all?

And as @juliushaertl said about remote images:

We cannot add remote images in general because they are blocked by the CSP as mentioned in the error. So for now only images from the same domain work for that.

@rullzer Does it make sense to to fetch remote images and deliver them from the local domain, similar to the proxy we have for the app store images? Or should we just block remote images for security reasons.

Related solutions

To see what people would expect from the Text app, we should list some widely-used projects in the same space (mainly collaborative):

Working out of the box with prosemirror/markdown:

  • Text formating bold/italic/underlined
  • Code blocks
  • Headlines
  • Horizontal ruler
  • Lists (ordered/unordered)
  • Blockquote
  • Links
  • Images

Should be possible:

  • Lists with checkboxes
  • User mentions

Harder to accomplish (due to markdown format):

  • Tables/Columns
  • Text alignment/color/hightlight
  • Dynamic content (videos/files)
  • Inline comments

Not clear how to open links

Right now you can open links in the document via Ctrl-Click or Shift-Click, which most people of course don’t know. Can we have it so that on click a little tooltip thingy opens which gives you a list of:

  • Open link
  • Edit link

And "Open link" should of course automatically open in a new tab to not rip you out of the collaboration.

Cleanup transactions

After a document has been saved and all connected sessions have moved to that state, we can cleanup old transaction data.

Options for image like delete and alt text?

Currently it seems you can only delete images via Delete on the keyboard, right? And there’s no way to set alt text?

I would expect something like a 3-dot menu in the top-right corner to show up when the image is tapped, with:

  • Add alt text
  • Delete image

how to delete an image with mouse, would expect a delete icon in the corner on tap

Pasting markdown does not apply styling

This is what happens when you paste some markdown text, e.g. from Lorem Markdownum:
markdown paste

Should probably be highlighted as markdown properly, or is that difficult?

Prosemirror.net has the same issue, so I guess it’s upstream? Or maybe a setting?

Text vs files_texteditor

In the create menu in Files, there are 2 entries now:

  • "New text file" → defaulting to .txt
  • "New text document" → defaulting to .md

text file vs text document difference not clear

Seeing this is a bit confusing, and the difference is not really clear and not really relevant either to regular people. The .txt files are still opened by files_texteditor, and the .md files by Text.

Proposal (all this only for when the Text app is installed):

  • There is only one entry, saying "New text document" → defaulting to .md
  • The Text app should be able to open .txt files too, overriding the files_texteditor app
  • The files_texteditor app should basically be phased out, as I thought was the plan?

What do you think @juliushaertl?

Image picker glitch in breadcrumbs bar

In the breadcrumbs bar, there is an "actions creatable" element showing as just a vertical grey bar. It doesn’t happen in other filepickers like in the avatar picker:
Filepicker shows actions creatable element

Loading takes quite long

The initial load of a new document you just created takes like 3–5 seconds, and every open of a document also takes like 3 seconds or so.

Anything we can do to speed that up?

Previews in Files don’t reflect view of rendered Markdown

So now that we have this fancy WYSIWYG editor, we have kind of a problem with our default previews:
markdown preview

If you just created a document and used some headings and it looked nice, you will be confused when you see that.

Anything we can do there? Like a markdown renderer for the preview generator? cc @rullzer maybe?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.