Commit Graph

453 Commits

Author SHA1 Message Date
Michael Demetriou be93f91311 Add error handling for HTTP response codes other than 200.
This works also for local errors such as no connection as browsers
return a response code of 0 in that case
2019-07-14 15:26:14 +03:00
Michael Demetriou 6cca097de0 Needs testing: frontend (javascript) code for image uploads.
I was trying to create the image upload functionality of *writefreely*. The spec said that after the user drops an image on the textarea a markdown image placeholder should appear `[image](file.png)`, just like it happens on [discourse](https://www.discourse.org/).

However there were a few challenges. *Writefreely* is a blogging platform, not a forum, so longer texts are possible, if not common. Appending the markdown at the end of the text, especially if the text overflows the viewport is bad user interface as the user will have no confirmation whether his action had a result or not (the text would have been appended off-screen). Also, in blog posts we often append larger images which take some time to upload, so a progress indicator would be useful.

Another challenge was multiple uploads. Since additional markup isn't allowed inside the textarea I had to find a way to update the right markdown block when the respective file upload updates or finishes.

Lastly the default action when one hovers a file over a textarea, the browser insinuates that the file will be dropped in a specific place under the mouse cursor by showing a text cursor in the text. However it doesn't give the developers any way to know where that text will be dropped. It does drop the local `file://` URI however so we can replace that with our markdown. What if the user had the same `file://` uri elsewhere in the text, however? Perhaps he was writing about including local files in markdown documents.

The above function does not work reliably in Chrome on GNOME. Sometimes it inserts the `file://` URI under the cursor and sometimes it navigates to the image directly. So I'll probably have to browser-sniff there (bad, I know)

So the solution had to deal with the following stuff:

1. Insert the image in the last editing position unless the browser allows you to drop at a specific place
2. If the browser allows you to drop at a specific place, do it.
3. Update the markdown with progress and when the upload is done go replace the loading thing with the remote filename the server returned

This is simple. You can use `textarea.selectionStart` and `textarea.selectionEnd` to get the selection index (if text is selected) or the cursor position if these two values are equal. If text is selected replace with the dropped image.

This was not so simple and despite being able to create a [demo](http://qwazix.com/shared/firefox%20dropping%20in%20place.webm) this did not work for more than one files (this is fixable) nor it could work in chrome (this doesn't seem fixable, chrome sometimes drops the `file://` URI in the textarea and others navigates to it). Thus I'm inclined to drop this functionality as the code for it is dirty anyway. [And then I found out that this doesn't work on Windows/MacOS so yeah...][Now I have dropped this]

<video><source src="http://qwazix.com/shared/firefox%20dropping%20in%20place.webm" type="video/webm"></video>

However I'd like to talk about my solution: in the drop event `textarea.value` still holds the text without the `file://` URI. However ten milliseconds later the text has already updated. Here's why the dirty code: a `setTimeout({...},10)` that allow us to get to the updated text. We can then iterate over all the occurrences of `file://.*?/filename.ext` and check if they exist in the previous text. If we find one that doesn't then we can replace that with our markdown. This is the code:

``` javascript
        function insertTextAtDropPoint(text, textarea, filename){
            if (textarea.nodeName == "TEXTAREA") {
                // save cursor position so that we can set it
                // back after the operation on value
                var startingPosition = textarea.selectionStart;
                var rxp = new RegExp('file://.*?/'+filename);
                console.log(rxp);
                textarea.value = replaceNewPatternInString(rxp, oldtext, textarea.value, text);
                // set the cursor to its original position
                textarea.selectionStart = textarea.selectionEnd = startingPosition + text.length;
            } else throw "Element is not a textarea"
        }

function replaceNewPatternInString(pattern, oldstring, newstring, replacement){
            var index = 0;
            do {
                // find first occurence of pattern
                var match = newstring.substr(index, newstring.length).match(pattern);
                index += match.index;
                // take the part of the string from the beginning until
                // the end of the pattern
                // and check if you can find it in the old string
                // if you can go to the next occurence of the pattern
                // until you find one
                // that doesn't exist in the old string.
                index += match[0].length;
            } while (oldstring.indexOf(newstring.substr(0, index)) != -1);
            return newstring.substr(0,index-match[0].length) + replacement + newstring.substr(index,newstring.length);
        }
```

Still, believing that the file will be dropped under the cursor (which is probably the user's expectation when they see the moving **I** cursor) and then have it dropped in the last edit position is not good UX. Chrome disables that animation if you `preventDefault()` on `dragover` but Firefox does not so I'll have to resort to using `pointer-events` to disable that functionality. [Update: it looks like doing `preventDefault()` on `dragenter` resolves this nicely]

We don't have additional markup inside the textarea so if the user drops multiple files we need to know which one to update when the upload progresses or finishes. *Discourse* solves this by using filenames and appending numbers to them if it finds the same filename being already used. I decided that creating a temporary hash is simpler so I prepend one before each filename, making the markdown unique. Then it's a matter of search and replace to update progress.

Replacing text in the textarea entails getting the contents, changing them in javascript and putting them back in. This causes the spellcheck to fire again creating a subtle flicker in the wavy red lines. I was testing with *lorem ipsum* which has wavy red lines everywhere and that flicker quickly became annoying. Updating the progress every 5, or even 10% makes that annoyance a lot less noticeable and I suspect that in regular text with much less misspelled words this will not be an issue.

Finally, after each change we also need to put the cursor back to where it was because updating `textarea.value` sets the cursor to the end.

This was surprisingly easy. I just copied everything into `pad.tmpl` and it (almost) just worked. I had to point the `xhr` endpoint to my `upload.php` test file and enable **CORS** there but this was trivial.

 ## Backend

Next step: backend image handling.

Also posted here: https://mixt.qwazix.com/d/naac7l07tr
Individual commits while I developed this: https://github.com/qwazix/minimalist-ajax-upload/commits/dragDrop
2019-07-12 15:03:19 +03:00
Matt Baer 71fb63580a Merge branch 'master' into develop 2019-07-08 08:57:05 -04:00
Matt Baer e0666baa5d Include ARMv7 build in `make release`
This closes #135
2019-07-08 08:56:25 -04:00
Matt Baer 0b25109a6b Add `make build-arm7`
This makes it easy to build WF for ARMv7, e.g. the Raspberry Pi.

part of #135
2019-07-08 08:55:22 -04:00
Matt Baer 3b079810bb Accept Apper in writefreely.ResetPassword()
instead of *App
2019-07-03 14:39:43 -04:00
Matt Baer 79cf6ce0eb Accept Apper in writefreely.Migrate()
instead of *App
2019-07-03 14:39:05 -04:00
Matt Baer 3faa2def08 Add Documentation section and fix dev setup link 2019-07-02 11:41:43 -04:00
Matt Baer 5923b6401c Replace old "quick start" section with Getting Started link 2019-07-02 11:02:54 -04:00
Matt Baer ad6fd5e809 Use "Draft" in post meta page
instead of "Anonymous".
2019-07-01 19:59:52 -04:00
Matt Baer 554995916e Replace top-left "w" button on post meta page
This was still a relic of Write.as. Now it has the same icon as the
WriteFreely editor.
2019-07-01 19:56:50 -04:00
Matt Baer 7aaff778da
Merge pull request #123 from writeas/private-instance
Private instances

Resolves T576
2019-07-01 19:14:20 -04:00
Matt Baer 7240bf0cdc
Merge pull request #131 from writeas/customize-landing
Customize landing page

Resolves T565
2019-07-01 19:12:58 -04:00
Matt Baer bd180f56a8 Add comments about isRaw logic 2019-07-01 19:10:29 -04:00
Matt Baer fdcdfe4d25 Open landing page preview in new window 2019-07-01 19:05:47 -04:00
Matt Baer 60a6848361 Fix userlevel error logging
Previously, we just included the value of `ul`, which is a func. This
now calls `ul()` and logs that value.
2019-07-01 16:45:35 -04:00
Matt Baer 5757407994 Bump version to 0.10.0 2019-07-01 15:20:29 -04:00
Matt Baer 18bafadc43
Merge pull request #127 from writeas/shorter-config-process
Shorter config process
2019-07-01 14:15:41 -04:00
Matt Baer b8b15c8550 Move Environment prompt back under Server section 2019-07-01 14:00:56 -04:00
Matt Baer a740c67495 Fix whitespace
This runs `go fmt` on changed files and moves around some blank lines.
2019-07-01 13:33:26 -04:00
Matt Baer ebeb7b03e6 Explicitly set background-color
Closes #132
2019-06-28 08:26:15 -04:00
Matt Baer c3f3eb0a65 Rename getLandingPage -> getLandingBody
This makes the naming scheme more consistent with other funcs.

Ref T565
2019-06-27 22:22:21 -04:00
Matt Baer a72ce2ef29 Make landing page dynamic
This enables admins to customize their landing / home page via the Admin
dashboard -- including the text at the top of the page and the section
below it. It keeps the current default text, falling back to it if the
user hasn't overwritten it.

Ref T565
2019-06-27 17:06:37 -04:00
Matt Baer aedb05080c Support ?landing=1 to always show landing page
This supports admins previewing changes to the landing page.

Ref T565
2019-06-27 16:38:24 -04:00
Matt Baer 6fdc343986
Merge pull request #130 from mrvdb/issue125
Construct version from annotated tags only
2019-06-27 15:32:14 -04:00
Marcel van der Boom f6c129ed20 Construct version from annotated tags only
Fixes issue 125
2019-06-27 21:25:22 +02:00
Matt Baer f26e0ca86e
Merge pull request #128 from writeas/fix-c-syntax-highlighting
Fix #124 according to the snippet by @mrvdb
2019-06-27 15:07:04 -04:00
Michael Demetriou 4feac6dcd2 Remove `langs` list from `post-render` as it does not actually
do anything useful (see https://github.com/writeas/writefreely/pull/128#issuecomment-506207107)
2019-06-27 18:15:58 +03:00
Matt Baer 8d9f60aaa9 Always initialize database after --config
Previously, this would only run when configuring an instance for
single-user usage. Now it'll also run when configuring for multi-user
usage.

It also adds a log when the database has already been initialized.
2019-06-27 18:15:58 +03:00
Michael Demetriou a102f97c3e Fix #96
This solves the error 500 on the /api/me endpoint.

Replace token search query `=` with `LIKE` to fix sqlite complaining about
no valid tokens. Also checked with MySQL and it still works after the change.
2019-06-27 18:15:58 +03:00
Matt Baer bb0be02b4f
Merge pull request #126 from writeas/config-improvements
Always initialize database after --config
2019-06-27 09:31:58 -04:00
Matt Baer 00a8f8c951
Merge pull request #119 from qwazix/develop
Half-fix of #96
2019-06-27 09:29:25 -04:00
Michael Demetriou 0842119694 Change `sh` alias back to `bash`
because this is the alias in highlight itself.

(see https://github.com/writeas/writefreely/pull/128#issuecomment-505766645)
2019-06-27 00:12:18 +03:00
Michael Demetriou c2d7c2c8b7 Fix #124 according to the snippet by @mrvdb
I changed the sh alias to shell instead of bash.

The additions to the `highlight(nodes)` function look redundant.
It works for me without them but maybe they cover an edge case I
cannot think about?
2019-06-25 21:17:30 +03:00
Michael Demetriou 6506709fbc Merge branch 'develop' into shorter-config-process
Move flag parsing to main.go as per the issue description
2019-06-21 12:07:01 +03:00
Michael Demetriou aeab30db8a Fix #96
This solves the error 500 on the /api/me endpoint.

Replace token search query `=` with `LIKE` to fix sqlite complaining about
no valid tokens. Also checked with MySQL and it still works after the change.
2019-06-21 10:48:40 +03:00
Michael Demetriou efbef83362 make sure app exits after error in --sections argument 2019-06-21 10:40:40 +03:00
Matt Baer 77bf403443 Merge branch 'develop' into private-instance 2019-06-20 21:10:36 -04:00
Matt Baer 86a128483b Fix more missing hostNames
This fixes places, especially around federation, where the Collection's
`hostName` wasn't set.
2019-06-20 21:08:30 -04:00
Michael Demetriou 07fe366c15 Fix T657: add --sections argument to allow partial configuration.
Use the split argument list (slice) just for validation purposes
as it's substantially easier to do `.contains` in a string instead
of a slice. As such, pass the `configSections` arguments to
`Configure()` and check the existence of each one before showing
the options to the user.

An empty argument list is replaced by "server db app" so everything
is there negating the need to check anything else in `Configure()`.
In the same vein the default is "server db app".

The parsing is done in `app.go` alongside the other flags instead
of `main.go` as described in T657.
2019-06-20 23:41:03 +03:00
Michael Demetriou 1d5c396327 Add --sections flag to app.go and pass it to setup.go
Add --sections flag to app.go according to T657, parse them
into a string array (check for invalid arguments and abort)
and pass them to Configure(). For now Configure() doesn't do
anything with them yet.
2019-06-20 23:14:36 +03:00
Matt Baer bbd775bcc6 Always initialize database after --config
Previously, this would only run when configuring an instance for
single-user usage. Now it'll also run when configuring for multi-user
usage.

It also adds a log when the database has already been initialized.
2019-06-20 09:04:52 -04:00
Matt Baer 2b39b714de Use UserLevelReader func for read routes
Previously, that func was duplicated here.
2019-06-19 19:26:10 -04:00
Matt Baer 44a4fd7a79 Correctly log and return after serving static file 2019-06-19 19:17:45 -04:00
Matt Baer 7dc620aff1 Check reader permissions on .well-known endpoints
(for private instances)

Ref T576
2019-06-16 21:22:56 -04:00
Matt Baer d6a77d6668 Check reader permissions on RSS feed & sitemap
(on private instances)

Ref T576
2019-06-16 21:16:23 -04:00
Matt Baer 63b536ec87 Don't federate anything when instance is private
Ref T576
2019-06-16 20:34:32 -04:00
Matt Baer 35718cd239 Change blog visibility explanations on Private instance
Ref T576
2019-06-16 20:30:56 -04:00
Matt Baer bf989eb696 Hide Reader link on private instance when unauth'd
Ref T576
2019-06-16 20:29:31 -04:00
Matt Baer a2088c1646 Restrict API read access based on Private setting
This verifies that a user is authenticated before getting to the actual
handler on API endpoints where a user is reading content.

Ref T576
2019-06-16 20:24:47 -04:00