From f308836264e8e438c2e111b8607c975fce3afe2c Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Tue, 2 Oct 2018 23:48:07 +0200 Subject: [PATCH 1/6] add new fenced block language: gallery --- browser/components/MarkdownPreview.js | 33 ++++++++++++++++++- browser/components/markdown.styl | 46 ++++++++++++++++++++++++++- browser/lib/markdown.js | 6 ++++ package.json | 2 ++ yarn.lock | 38 ++++++++++++++++++++++ 5 files changed, 123 insertions(+), 2 deletions(-) diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index eacc4e219..48951204a 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -21,6 +21,8 @@ import yaml from 'js-yaml' import context from 'browser/lib/context' import i18n from 'browser/lib/i18n' import fs from 'fs' +import { render } from 'react-dom' +import Carousel from 'react-image-carousel' const { remote, shell } = require('electron') const attachmentManagement = require('../main/lib/dataApi/attachmentManagement') @@ -39,7 +41,8 @@ const appPath = fileUrl( ) const CSS_FILES = [ `${appPath}/node_modules/katex/dist/katex.min.css`, - `${appPath}/node_modules/codemirror/lib/codemirror.css` + `${appPath}/node_modules/codemirror/lib/codemirror.css`, + `${appPath}/node_modules/react-image-carousel/lib/css/main.min.css` ] function buildStyle ( @@ -789,6 +792,34 @@ export default class MarkdownPreview extends React.Component { mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML), theme) } ) + + _.forEach( + this.refs.root.contentWindow.document.querySelectorAll('.gallery'), + el => { + const images = el.innerHTML.split(/\n/g).filter(i => i.length > 0) + el.innerHTML = '' + + const height = el.attributes.getNamedItem('data-height') + if (height && height.value !== 'undefined') { + el.style.height = height.value + 'vh' + } + + let autoplay = el.attributes.getNamedItem('data-autoplay') + if (autoplay && autoplay.value !== 'undefined') { + autoplay = parseInt(autoplay.value, 10) || 0 + } else { + autoplay = 0 + } + + render( + , + el + ) + } + ) } focus () { diff --git a/browser/components/markdown.styl b/browser/components/markdown.styl index 2e17a75b2..6e43273e4 100644 --- a/browser/components/markdown.styl +++ b/browser/components/markdown.styl @@ -381,6 +381,26 @@ pre.fence canvas, svg max-width 100% !important + .gallery + width 100% + height 50vh + + .carousel + .carousel-main img + min-width auto + max-width 100% + min-height auto + max-height 100% + + .carousel-footer::-webkit-scrollbar-corner + background-color transparent + + .carousel-main, .carousel-footer + background-color $ui-noteDetail-backgroundColor + .prev, .next + color $ui-text-color + background-color $ui-tag-backgroundColor + themeDarkBackground = darken(#21252B, 10%) themeDarkText = #f9f9f9 themeDarkBorder = lighten(themeDarkBackground, 20%) @@ -432,6 +452,14 @@ body[data-theme="dark"] background-color themeDarkBorder color themeDarkText + pre.fence + .gallery + .carousel-main, .carousel-footer + background-color $ui-dark-noteDetail-backgroundColor + .prev, .next + color $ui-dark-text-color + background-color $ui-dark-tag-backgroundColor + themeSolarizedDarkTableOdd = $ui-solarized-dark-noteDetail-backgroundColor themeSolarizedDarkTableEven = darken($ui-solarized-dark-noteDetail-backgroundColor, 10%) themeSolarizedDarkTableHead = themeSolarizedDarkTableEven @@ -459,6 +487,14 @@ body[data-theme="solarized-dark"] &:last-child border-right solid 1px themeSolarizedDarkTableBorder + pre.fence + .gallery + .carousel-main, .carousel-footer + background-color $ui-solarized-dark-noteDetail-backgroundColor + .prev, .next + color $ui-solarized-dark-text-color + background-color $ui-solarized-dark-tag-backgroundColor + themeMonokaiTableOdd = $ui-monokai-noteDetail-backgroundColor themeMonokaiTableEven = darken($ui-monokai-noteDetail-backgroundColor, 10%) themeMonokaiTableHead = themeMonokaiTableEven @@ -486,4 +522,12 @@ body[data-theme="monokai"] &:last-child border-right solid 1px themeMonokaiTableBorder kbd - background-color themeDarkBackground \ No newline at end of file + background-color themeDarkBackground + + pre.fence + .gallery + .carousel-main, .carousel-footer + background-color $ui-monokai-noteDetail-backgroundColor + .prev, .next + color $ui-monokai-text-color + background-color $ui-monokai-tag-backgroundColor diff --git a/browser/lib/markdown.js b/browser/lib/markdown.js index f8ae7f055..52a13700d 100644 --- a/browser/lib/markdown.js +++ b/browser/lib/markdown.js @@ -143,6 +143,12 @@ class Markdown {
${token.content}
` }, + gallery: token => { + return `
+          ${token.fileName}
+          
+        
` + }, mermaid: token => { return `
           ${token.fileName}
diff --git a/package.json b/package.json
index 3e95603b1..560a2e7da 100644
--- a/package.json
+++ b/package.json
@@ -95,8 +95,10 @@
     "react-codemirror": "^0.3.0",
     "react-debounce-render": "^4.0.1",
     "react-dom": "^15.0.2",
+    "react-image-carousel": "^2.0.18",
     "react-redux": "^4.4.5",
     "react-sortable-hoc": "^0.6.7",
+    "react-transition-group": "^2.5.0",
     "redux": "^3.5.2",
     "sander": "^0.5.1",
     "sanitize-html": "^1.18.2",
diff --git a/yarn.lock b/yarn.lock
index 5c426c92e..55f4102aa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2701,6 +2701,10 @@ doctrine@^2.0.0, doctrine@^2.0.2:
   dependencies:
     esutils "^2.0.2"
 
+dom-helpers@^3.3.1:
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
+
 dom-serializer@0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
@@ -5279,6 +5283,10 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
 
+"js-tokens@^3.0.0 || ^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+
 js-yaml@^3.10.0, js-yaml@^3.5.1, js-yaml@^3.7.0:
   version "3.11.0"
   resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef"
@@ -5729,6 +5737,12 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3
   dependencies:
     js-tokens "^3.0.0"
 
+loose-envify@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+  dependencies:
+    js-tokens "^3.0.0 || ^4.0.0"
+
 loud-rejection@^1.0.0, loud-rejection@^1.2.0:
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
@@ -7155,6 +7169,13 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8,
     loose-envify "^1.3.1"
     object-assign "^4.1.1"
 
+prop-types@^15.6.2:
+  version "15.6.2"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
+  dependencies:
+    loose-envify "^1.3.1"
+    object-assign "^4.1.1"
+
 proxy-addr@~2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
@@ -7330,6 +7351,10 @@ react-dom@^15.0.2:
     object-assign "^4.1.0"
     prop-types "^15.5.10"
 
+react-image-carousel@^2.0.18:
+  version "2.0.18"
+  resolved "https://registry.yarnpkg.com/react-image-carousel/-/react-image-carousel-2.0.18.tgz#5868ea09bd9cca09c4467d3d02695cd4e7792f28"
+
 react-input-autosize@^1.1.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-1.2.0.tgz#87241071159f742123897691da6796ec33b57d05"
@@ -7337,6 +7362,10 @@ react-input-autosize@^1.1.0:
     create-react-class "^15.5.2"
     prop-types "^15.5.8"
 
+react-lifecycles-compat@^3.0.4:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+
 react-proxy@^1.1.7:
   version "1.1.8"
   resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a"
@@ -7402,6 +7431,15 @@ react-transform-hmr@^1.0.3:
     global "^4.3.0"
     react-proxy "^1.1.7"
 
+react-transition-group@^2.5.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.5.0.tgz#70bca0e3546102c4dc5cf3f5f57f73447cce6874"
+  dependencies:
+    dom-helpers "^3.3.1"
+    loose-envify "^1.4.0"
+    prop-types "^15.6.2"
+    react-lifecycles-compat "^3.0.4"
+
 react@^15.5.4:
   version "15.6.2"
   resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72"

From 39eaed260a834e51283cbcc42c002f1152955a36 Mon Sep 17 00:00:00 2001
From: Baptiste Augrain 
Date: Mon, 8 Oct 2018 15:57:42 +0200
Subject: [PATCH 2/6] display correctly attached image

---
 browser/main/lib/dataApi/attachmentManagement.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js
index 912450c18..38648941c 100644
--- a/browser/main/lib/dataApi/attachmentManagement.js
+++ b/browser/main/lib/dataApi/attachmentManagement.js
@@ -227,7 +227,7 @@ function migrateAttachments (markdownContent, storagePath, noteKey) {
  * @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
  */
 function fixLocalURLS (renderedHTML, storagePath) {
-  return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?"', 'g'), function (match) {
+  return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '[\w\/]+', 'g'), function (match) {
     var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
     return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
   })

From 7a5a821f8a8b8919d9c5ae0b0dca377485ec25f2 Mon Sep 17 00:00:00 2001
From: Baptiste Augrain 
Date: Tue, 9 Oct 2018 00:47:37 +0200
Subject: [PATCH 3/6] fix failing test

---
 browser/main/lib/dataApi/attachmentManagement.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js
index 38648941c..a81d3bd44 100644
--- a/browser/main/lib/dataApi/attachmentManagement.js
+++ b/browser/main/lib/dataApi/attachmentManagement.js
@@ -227,7 +227,7 @@ function migrateAttachments (markdownContent, storagePath, noteKey) {
  * @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
  */
 function fixLocalURLS (renderedHTML, storagePath) {
-  return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '[\w\/]+', 'g'), function (match) {
+  return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(?:\\\/|%5C)[\\w.]+', 'g'), function (match) {
     var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
     return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
   })

From 5d9b1abe82a68c51b99564f6f117191c246f98b3 Mon Sep 17 00:00:00 2001
From: Baptiste Augrain 
Date: Tue, 9 Oct 2018 01:18:19 +0200
Subject: [PATCH 4/6] allow markdown image syntax

---
 browser/lib/markdown.js | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/browser/lib/markdown.js b/browser/lib/markdown.js
index 52a13700d..cc5e86dc7 100644
--- a/browser/lib/markdown.js
+++ b/browser/lib/markdown.js
@@ -144,9 +144,18 @@ class Markdown {
         
` }, gallery: token => { + const content = token.content.split('\n').slice(0, -1).map(line => { + const match = /!\[[^\]]*]\(([^\)]*)\)/.exec(line) + if (match) { + return match[1] + } else { + return line + } + }).join('\n') + return `
           ${token.fileName}
-          
+          
         
` }, mermaid: token => { From 9d81e4be2fe810c18003a99425ac1ed42ef2f665 Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Sun, 25 Nov 2018 16:17:01 +0100 Subject: [PATCH 5/6] undo change --- browser/main/lib/dataApi/attachmentManagement.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js index c88acfc5a..59c915402 100644 --- a/browser/main/lib/dataApi/attachmentManagement.js +++ b/browser/main/lib/dataApi/attachmentManagement.js @@ -227,7 +227,7 @@ function migrateAttachments (markdownContent, storagePath, noteKey) { * @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths. */ function fixLocalURLS (renderedHTML, storagePath) { - return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(?:\\\/|%5C)[\\w.]+', 'g'), function (match) { + return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?', 'g'), function (match) { var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g') return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER)) }) From 64f7233bfc8124fc6d89e9c212718f3cdd4d02cb Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Sun, 25 Nov 2018 16:58:11 +0100 Subject: [PATCH 6/6] fix regex to match :storage reference, added comment to explain what it does. --- browser/main/lib/dataApi/attachmentManagement.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js index 59c915402..73bf13037 100644 --- a/browser/main/lib/dataApi/attachmentManagement.js +++ b/browser/main/lib/dataApi/attachmentManagement.js @@ -227,7 +227,15 @@ function migrateAttachments (markdownContent, storagePath, noteKey) { * @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths. */ function fixLocalURLS (renderedHTML, storagePath) { - return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?', 'g'), function (match) { + /* + A :storage reference is like `:storage/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`. + + - `STORAGE_FOLDER_PLACEHOLDER` will match `:storage` + - `(?:(?:\\\/|%5C)[\\w.]+)+` will match `/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg` + - `(?:\\\/|%5C)[\\w.]+` will either match `/3b6f8bd6-4edd-4b15-96e0-eadc4475b564` or `/f939b2c3.jpg` + - `(?:\\\/|%5C)` match the path seperator. `\\\/` for posix systems and `%5C` for windows. + */ + return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(?:(?:\\\/|%5C)[\\w.]+)+', 'g'), function (match) { var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g') return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER)) })