From 0e2351e79ef7ed9fe2f7d876e300bf37fe23f99b Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 22 Jan 2021 23:35:54 +0000 Subject: [PATCH] Mobile: Removing no longer used beta Markdown editor Ref: https://discourse.joplinapp.org/t/anyone-using-the-beta-editor-on-ios/11658 --- packages/app-mobile/MarkdownEditor/Formats.js | 23 --- .../MarkdownEditor/MarkdownEditor.js | 162 ------------------ .../MarkdownEditor/applyListFormat.js | 44 ----- .../MarkdownEditor/applyWebLinkFormat.js | 39 ----- .../MarkdownEditor/applyWrapFormat.js | 28 --- .../MarkdownEditor/applyWrapFormatNewLines.js | 56 ------ packages/app-mobile/MarkdownEditor/index.js | 13 -- .../MarkdownEditor/renderButtons.js | 33 ---- .../MarkdownEditor/static/visibility.png | Bin 309 -> 0 bytes packages/app-mobile/MarkdownEditor/utils.js | 9 - .../MarkdownEditor/webLinkValidator.js | 104 ----------- 11 files changed, 511 deletions(-) delete mode 100644 packages/app-mobile/MarkdownEditor/Formats.js delete mode 100644 packages/app-mobile/MarkdownEditor/MarkdownEditor.js delete mode 100644 packages/app-mobile/MarkdownEditor/applyListFormat.js delete mode 100644 packages/app-mobile/MarkdownEditor/applyWebLinkFormat.js delete mode 100644 packages/app-mobile/MarkdownEditor/applyWrapFormat.js delete mode 100644 packages/app-mobile/MarkdownEditor/applyWrapFormatNewLines.js delete mode 100644 packages/app-mobile/MarkdownEditor/index.js delete mode 100644 packages/app-mobile/MarkdownEditor/renderButtons.js delete mode 100644 packages/app-mobile/MarkdownEditor/static/visibility.png delete mode 100644 packages/app-mobile/MarkdownEditor/utils.js delete mode 100644 packages/app-mobile/MarkdownEditor/webLinkValidator.js diff --git a/packages/app-mobile/MarkdownEditor/Formats.js b/packages/app-mobile/MarkdownEditor/Formats.js deleted file mode 100644 index 981fa6a2c..000000000 --- a/packages/app-mobile/MarkdownEditor/Formats.js +++ /dev/null @@ -1,23 +0,0 @@ -import applyWrapFormat from './applyWrapFormat'; -import applyWrapFormatNewLines from './applyWrapFormatNewLines'; -import applyListFormat from './applyListFormat'; -import applyWebLinkFormat from './applyWebLinkFormat'; - -export default [ - { key: 'B', title: 'B', wrapper: '**', onPress: applyWrapFormat, style: { fontWeight: 'bold' } }, - { key: 'I', title: 'I', wrapper: '*', onPress: applyWrapFormat, style: { fontStyle: 'italic' } }, - { key: 'Link', title: 'Link', onPress: applyWebLinkFormat }, - { key: 'List', title: 'List', prefix: '-', onPress: applyListFormat }, - { - key: 'S', - title: 'S', - wrapper: '~~', - onPress: applyWrapFormat, - style: { textDecorationLine: 'line-through' }, - }, - { key: '', title: '', wrapper: '`', onPress: applyWrapFormat }, - { key: 'Pre', title: 'Pre', wrapper: '```', onPress: applyWrapFormatNewLines }, - { key: 'H1', title: 'H1', prefix: '#', onPress: applyListFormat }, - { key: 'H2', title: 'H2', prefix: '##', onPress: applyListFormat }, - { key: 'H3', title: 'H3', prefix: '###', onPress: applyListFormat }, -]; diff --git a/packages/app-mobile/MarkdownEditor/MarkdownEditor.js b/packages/app-mobile/MarkdownEditor/MarkdownEditor.js deleted file mode 100644 index 61a44d5f1..000000000 --- a/packages/app-mobile/MarkdownEditor/MarkdownEditor.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * Inspired by https://github.com/kunall17/MarkdownEditor - */ - -import React from 'react'; -import { - View, - StyleSheet, - TextInput, - Platform, - KeyboardAvoidingView, - TouchableOpacity, - Image, -} from 'react-native'; -import { renderFormatButtons } from './renderButtons'; -import NoteBodyViewer from '@joplin/lib/components/NoteBodyViewer/NoteBodyViewer'; - -const styles = StyleSheet.create({ - buttonContainer: { - flex: 0, - flexDirection: 'row', - }, - screen: { // Wrapper around the editor and the preview - flex: 1, - flexDirection: 'column', - alignItems: 'stretch', - }, -}); - -const MarkdownPreviewButton = (props) => - - - ; - -export default class MarkdownEditor extends React.Component { - constructor(props) { - super(props); - this.state = { - text: props.value, - selection: { start: 0, end: 0 }, - // Show preview by default - showPreview: props.showPreview ? props.showPreview : true, - }; - this.textAreaRef = React.createRef(); // For focusing the textarea - } - textInput: TextInput; - - changeText = (selection: {start: number, end: number}) => (input: string) => { - let result = input; - const cursor = selection.start; - const isOnNewline = '\n' === input.slice(cursor - 1, cursor); - const isDeletion = input.length < this.state.text.length; - if (isOnNewline && !isDeletion) { - const prevLines = input.slice(0, cursor - 1).split('\n'); - const prevLine = prevLines[prevLines.length - 1]; - - const insertListLine = (bullet) => ([ - prevLines.join('\n'), // Previous text - `\n${bullet} `, // Current line with new bullet point - input.slice(cursor, input.length), // Following text - ].join('')); - - const insertedEndListLine = [ - // Previous text (all but last bullet line, which we remove) - prevLines.slice(0, prevLines.length - 1).join('\n') , - '\n\n', // Two newlines to get out of the list - input.slice(cursor, input.length), // Following text - ].join(''); - - // Add new ordered list line item - if (prevLine.startsWith('- ') && !prevLine.startsWith('- [ ')) { - // If the bullet on the previous line isn't empty, add a new bullet. - if (prevLine.trim() !== '-') { - result = insertListLine('-'); - } else { - result = insertedEndListLine; - } - } - - // Add new checklist line item - if ((prevLine.startsWith('- [ ] ') || prevLine.startsWith('- [x] '))) { - // If the bullet on the previous line isn't empty, add a new bullet. - if (prevLine.trim() !== '- [ ]' && prevLine.trim() !== '- [x]') { - result = insertListLine('- [ ]'); - } else { - result = insertedEndListLine; - } - } - - // Add new ordered list item - if (/^\d+\./.test(prevLine)) { - // If the bullet on the previous line isn't empty, add a new bullet. - const digit = Number(prevLine.match(/^\d+/)[0]); - if (prevLine.trim() !== `${digit}.`) { - result = insertListLine(`${digit + 1}.`); - } else { - result = insertedEndListLine; - } - } - } - // Hide Markdown preview on text change - this.setState({ text: result, showPreview: false }); - this.props.saveText(result); - if (this.props.onMarkdownChange) this.props.onMarkdownChange(input); - }; - - onSelectionChange = event => { - this.setState({ selection: event.nativeEvent.selection }); - }; - - focus = () => this.textAreaRef.current.focus() - - convertMarkdown = () => this.setState({ showPreview: !this.state.showPreview }) - - render() { - const WrapperView = Platform.OS === 'ios' ? KeyboardAvoidingView : View; - const { Formats, markdownButton } = this.props; - const { text, selection, showPreview } = this.state; - return ( - - - {showPreview && } - - - {renderFormatButtons( - { - color: this.props.markdownButtonsColor, - getState: () => this.state, - setState: (state, callback) => { - // Hide Markdown preview on text change - this.setState({ showPreview: false }); - this.setState(state, callback); - }, - }, - Formats, - markdownButton - )} - - - ); - } -} diff --git a/packages/app-mobile/MarkdownEditor/applyListFormat.js b/packages/app-mobile/MarkdownEditor/applyListFormat.js deleted file mode 100644 index 069cde54a..000000000 --- a/packages/app-mobile/MarkdownEditor/applyListFormat.js +++ /dev/null @@ -1,44 +0,0 @@ -import { replaceBetween } from './utils'; -const shim = require('@joplin/lib/shim').default; - -export default ({ getState, item, setState }) => { - let { text } = getState(); - const { selection } = getState(); - text = text || ''; - let newText; - let newSelection; - - // Ignore multi-character selections. - // NOTE: I was on the fence about whether more appropriate behavior would be - // to add the list prefix (e.g. '-', '1.', '#', '##', '###') at the - // beginning of the line where the selection begins, but for now I think - // it's more natural to just ignore it in this case. If after using this - // editor for a while it turns out the other way is more natural, that's - // fine by me! - if (selection.start !== selection.end) { - return; - } - - const spaceForPrefix = item.prefix.length + 1; - const isNewLine = text.substring(selection.start - 1, selection.start) === '\n'; - if (isNewLine) { // We're at the start of a line - newText = replaceBetween(text, selection, `${item.prefix} `); - newSelection = { start: selection.start + spaceForPrefix, end: selection.start + spaceForPrefix }; - } else { // We're in the middle of a line - // NOTE: It may be more natural for the prefix (e.g. '-', '1.', '#', '##') - // to be prepended at the beginning of the line where the selection is, - // rather than creating a new line (which is the behavior implemented here). - // If the other way is more natural, that's fine by me! - newText = replaceBetween(text, selection, `\n${item.prefix} `); - newSelection = { - start: selection.start + spaceForPrefix + 1, - end: selection.start + spaceForPrefix + 1, - }; - } - - setState({ text: newText }, () => { - shim.setTimeout(() => { - setState({ selection: newSelection }); - }, 300); - }); -}; diff --git a/packages/app-mobile/MarkdownEditor/applyWebLinkFormat.js b/packages/app-mobile/MarkdownEditor/applyWebLinkFormat.js deleted file mode 100644 index f5666f152..000000000 --- a/packages/app-mobile/MarkdownEditor/applyWebLinkFormat.js +++ /dev/null @@ -1,39 +0,0 @@ -import { isStringWebLink, replaceBetween } from './utils'; - -export const writeUrlTextHere = 'https://example.com'; -export const writeTextHereString = 'Write some text here'; -const shim = require('@joplin/lib/shim').default; - -// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars -export default ({ getState, item, setState }) => { - const { selection, text } = getState(); - let newText; - let newSelection; - const selectedText = text.substring(selection.start, selection.end); - if (selection.start !== selection.end) { - if (isStringWebLink(selectedText)) { - newText = replaceBetween(text, selection, `[${writeTextHereString}](${selectedText})`); - newSelection = { - start: selection.start + 1, - end: selection.start + 1 + writeTextHereString.length, - }; - } else { - newText = replaceBetween(text, selection, `[${selectedText}](${writeUrlTextHere})`); - newSelection = { - start: selection.end + 3, - end: selection.end + 3 + writeUrlTextHere.length, - }; - } - } else { - newText = replaceBetween(text, selection, `[${writeTextHereString}](${writeUrlTextHere})`); - newSelection = { - start: selection.start + 1, - end: selection.start + 1 + writeTextHereString.length, - }; - } - setState({ text: newText }, () => { - shim.setTimeout(() => { - setState({ selection: newSelection }); - }, 25); - }); -}; diff --git a/packages/app-mobile/MarkdownEditor/applyWrapFormat.js b/packages/app-mobile/MarkdownEditor/applyWrapFormat.js deleted file mode 100644 index 78cf8836c..000000000 --- a/packages/app-mobile/MarkdownEditor/applyWrapFormat.js +++ /dev/null @@ -1,28 +0,0 @@ -import { replaceBetween } from './utils'; -const shim = require('@joplin/lib/shim').default; - -export default ({ getState, item, setState }) => { - const { text, selection } = getState(); - const newText = replaceBetween( - text, - selection, - item.wrapper.concat(text.substring(selection.start, selection.end), item.wrapper) - ); - let newPosition; - if (selection.start === selection.end) { - newPosition = selection.end + item.wrapper.length; - } else { - newPosition = selection.end + item.wrapper.length * 2; - } - const extra = { - selection: { - start: newPosition, - end: newPosition, - }, - }; - setState({ text: newText }, () => { - shim.setTimeout(() => { - setState({ ...extra }); - }, 25); - }); -}; diff --git a/packages/app-mobile/MarkdownEditor/applyWrapFormatNewLines.js b/packages/app-mobile/MarkdownEditor/applyWrapFormatNewLines.js deleted file mode 100644 index 6d0eaef12..000000000 --- a/packages/app-mobile/MarkdownEditor/applyWrapFormatNewLines.js +++ /dev/null @@ -1,56 +0,0 @@ -import { replaceBetween } from './utils'; -const shim = require('@joplin/lib/shim').default; - -export default ({ getState, item, setState }) => { - const { text, selection } = getState(); - let newText = replaceBetween( - text, - selection, - `\n${item.wrapper.concat( - '\n', - text.substring(selection.start, selection.end), - '\n', - item.wrapper, - '\n' - )}` - ); - let newPosition; - if (selection.start === selection.end) { - newPosition = selection.end + item.wrapper.length + 2; // +2 For two new lines - newText = replaceBetween( - text, - selection, - `\n${item.wrapper.concat( - '\n', - text.substring(selection.start, selection.end), - '\n', - item.wrapper, - '\n' - )}` - ); - } else { - newPosition = selection.end + item.wrapper.length * 2 + 3; // +3 For three new lines - newText = replaceBetween( - text, - selection, - `${item.wrapper.concat( - '\n', - text.substring(selection.start, selection.end), - '\n', - item.wrapper, - '\n' - )}` - ); - } - const extra = { - selection: { - start: newPosition, - end: newPosition, - }, - }; - setState({ text: newText }, () => { - shim.setTimeout(() => { - setState({ ...extra }); - }, 25); - }); -}; diff --git a/packages/app-mobile/MarkdownEditor/index.js b/packages/app-mobile/MarkdownEditor/index.js deleted file mode 100644 index 2687c75de..000000000 --- a/packages/app-mobile/MarkdownEditor/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import applyWrapFormat from './applyWrapFormat'; -import applyWrapFormatNewLines from './applyWrapFormatNewLines'; -import applyListFormat from './applyListFormat'; -import applyWebLinkFormat from './applyWebLinkFormat'; -import MarkdownEditor from './MarkdownEditor'; - -module.exports = { - MarkdownEditor, - applyWrapFormat, - applyWrapFormatNewLines, - applyListFormat, - applyWebLinkFormat, -}; diff --git a/packages/app-mobile/MarkdownEditor/renderButtons.js b/packages/app-mobile/MarkdownEditor/renderButtons.js deleted file mode 100644 index 7629405d4..000000000 --- a/packages/app-mobile/MarkdownEditor/renderButtons.js +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import { FlatList, TouchableOpacity, Text } from 'react-native'; - -import Formats from './Formats'; - -const defaultStyles = { padding: 8, fontSize: 16 }; - -const defaultMarkdownButton = ({ item, getState, setState, color }) => { - return ( - item.onPress({ getState, setState, item })}> - - {item.title} - - - ); -}; - -// eslint-disable-next-line import/prefer-default-export -export const renderFormatButtons = ({ getState, setState, color }, formats, markdownButton) => { - const list = ( - - markdownButton - ? markdownButton({ item, getState, setState }) - : defaultMarkdownButton({ item, getState, setState, color })} - horizontal - /> - ); - return list; -}; diff --git a/packages/app-mobile/MarkdownEditor/static/visibility.png b/packages/app-mobile/MarkdownEditor/static/visibility.png deleted file mode 100644 index 58597e91b97dda5cef43b40691793da044e2a662..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 309 zcmV-50m}Y~P)4oRAdjLA!j=$GOA!1wD58Z(%>yB7{_)W_5fllEprBcZw1WnQAhZ=d4l}Sb zdUys07vOb`?)!e;*Hu#Jd+mMYD}4nzW%|BR1L9+G{ZQp&j7wfwL;U}!QM=PpRs)rbnK#@%Djz!t1Z#BiD_-5T{%v_ z|MEZvgh$wK1Ej+00000NkvXX Hu0mjfuP=*W diff --git a/packages/app-mobile/MarkdownEditor/utils.js b/packages/app-mobile/MarkdownEditor/utils.js deleted file mode 100644 index d61e0f9de..000000000 --- a/packages/app-mobile/MarkdownEditor/utils.js +++ /dev/null @@ -1,9 +0,0 @@ -import regexValidator from './webLinkValidator'; - -export const replaceBetween = (text: string, selection: Object, what: string) => - text.substring(0, selection.start) + what + text.substring(selection.end); - -export const isStringWebLink = (text: string): boolean => { - const pattern = regexValidator; - return pattern.test(text); -}; diff --git a/packages/app-mobile/MarkdownEditor/webLinkValidator.js b/packages/app-mobile/MarkdownEditor/webLinkValidator.js deleted file mode 100644 index 230e35cf9..000000000 --- a/packages/app-mobile/MarkdownEditor/webLinkValidator.js +++ /dev/null @@ -1,104 +0,0 @@ -// prettier-ignore -/* eslint-disable */ - -// -// Regular Expression for URL validation -// -// Author: Diego Perini -// Updated: 2010/12/05 -// License: MIT -// -// Copyright (c) 2010-2013 Diego Perini (http://www.iport.it) -// -// Permission is hereby granted, free of charge, to any person -// obtaining a copy of this software and associated documentation -// files (the "Software"), to deal in the Software without -// restriction, including without limitation the rights to use, -// copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following -// conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. -// -// the regular expression composed & commented -// could be easily tweaked for RFC compliance, -// it was expressly modified to fit & satisfy -// these test for an URL shortener: -// -// http://mathiasbynens.be/demo/url-regex -// -// Notes on possible differences from a standard/generic validation: -// -// - utf-8 char class take in consideration the full Unicode range -// - TLDs have been made mandatory so single names like "localhost" fails -// - protocols have been restricted to ftp, http and https only as requested -// -// Changes: -// -// - IP address dotted notation validation, range: 1.0.0.0 - 223.255.255.255 -// first and last IP address of each class is considered invalid -// (since they are broadcast/network addresses) -// -// - Added exclusion of private, reserved and/or local networks ranges -// -// - Made starting path slash optional (http://example.com?foo=bar) -// -// - Allow a dot (.) at the end of hostnames (http://example.com.) -// -// Compressed one-line versions: -// -// Javascript version -// -// /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i -// -// PHP version -// -// _^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]-*)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]-*)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$_iuS -// -export default new RegExp( - "^" + - // protocol identifier - "(?:(?:https?|ftp)://)" + - // user:pass authentication - "(?:\\S+(?::\\S*)?@)?" + - "(?:" + - // IP address exclusion - // private & local networks - "(?!(?:10|127)(?:\\.\\d{1,3}){3})" + - "(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})" + - "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" + - // IP address dotted notation octets - // excludes loopback network 0.0.0.0 - // excludes reserved space >= 224.0.0.0 - // excludes network & broacast addresses - // (first & last IP address of each class) - "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" + - "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" + - "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" + - "|" + - // host name - "(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)" + - // domain name - "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*" + - // TLD identifier - "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" + - // TLD may end with dot - "\\.?" + - ")" + - // port number - "(?::\\d{2,5})?" + - // resource path - "(?:[/?#]\\S*)?" + - "$", "i" -);