فهرست منبع

WIP: replace inline-attachment with Dropzone.js

Yuki Takei 8 سال پیش
والد
کامیت
8c3462e2b8
5فایلهای تغییر یافته به همراه130 افزوده شده و 50 حذف شده
  1. 1 1
      package.json
  2. 10 0
      resource/js/components/PageEditor.js
  3. 107 43
      resource/js/components/PageEditor/Editor.js
  4. 0 1
      resource/js/legacy/crowi-form.js
  5. 12 5
      yarn.lock

+ 1 - 1
package.json

@@ -91,7 +91,6 @@
     "i18next-express-middleware": "^1.0.5",
     "i18next-node-fs-backend": "^1.0.0",
     "i18next-sprintf-postprocessor": "^0.2.2",
-    "inline-attachment": "~2.0.3",
     "jquery-ui": "^1.12.1",
     "jquery.cookie": "~1.4.1",
     "marked": "^0.3.12",
@@ -118,6 +117,7 @@
     "react-clipboard.js": "^1.1.2",
     "react-codemirror2": "^3.0.7",
     "react-dom": "^16.0.0",
+    "react-dropzone": "^4.2.7",
     "redis": "^2.7.1",
     "reveal.js": "^3.5.0",
     "rimraf": "^2.6.1",

+ 10 - 0
resource/js/components/PageEditor.js

@@ -21,6 +21,7 @@ export default class PageEditor extends React.Component {
     this.focusToEditor = this.focusToEditor.bind(this);
     this.onMarkdownChanged = this.onMarkdownChanged.bind(this);
     this.onSave = this.onSave.bind(this);
+    this.onUpload = this.onUpload.bind(this);
     this.onEditorScroll = this.onEditorScroll.bind(this);
     this.getMaxScrollTop = this.getMaxScrollTop.bind(this);
     this.getScrollTop = this.getScrollTop.bind(this);
@@ -128,6 +129,14 @@ export default class PageEditor extends React.Component {
       });
   }
 
+  /**
+   * the upload event handler
+   * @param {any} files
+   */
+  onUpload(files) {
+    console.log(files);
+  }
+
   /**
    * the scroll event handler from codemirror
    * @param {any} data {left, top, width, height, clientWidth, clientHeight} object that represents the current scroll position, the size of the scrollable area, and the size of the visible area (minus scrollbars).
@@ -232,6 +241,7 @@ export default class PageEditor extends React.Component {
               onScroll={this.onEditorScroll}
               onChange={this.onMarkdownChanged}
               onSave={this.onSave}
+              onUpload={this.onUpload}
           />
         </div>
         <div className="col-md-6 hidden-sm hidden-xs page-editor-preview-container">

+ 107 - 43
resource/js/components/PageEditor/Editor.js

@@ -18,6 +18,8 @@ require('codemirror/addon/scroll/annotatescrollbar');
 require('codemirror/mode/gfm/gfm');
 require('codemirror/theme/eclipse.css');
 
+import Dropzone from 'react-dropzone';
+
 import pasteHelper from './PasteHelper';
 import emojiAutoCompleteHelper from './EmojiAutoCompleteHelper';
 
@@ -32,12 +34,18 @@ export default class Editor extends React.Component {
 
     this.state = {
       value: this.props.value,
+      dropzoneAccept: '',
+      dropzoneActive: false,
     };
 
     this.getCodeMirror = this.getCodeMirror.bind(this);
     this.setCaretLine = this.setCaretLine.bind(this);
     this.forceToFocus = this.forceToFocus.bind(this);
     this.dispatchSave = this.dispatchSave.bind(this);
+
+    this.onDragEnter = this.onDragEnter.bind(this);
+    this.onDragLeave = this.onDragLeave.bind(this);
+    this.onDrop = this.onDrop.bind(this);
   }
 
   componentDidMount() {
@@ -80,51 +88,106 @@ export default class Editor extends React.Component {
     }
   }
 
+  /**
+   * dispatch onUpload event
+   */
+  dispatchUpload(files) {
+    if (this.props.onUpload != null) {
+      this.props.onUpload(files);
+    }
+  }
+
+  onDragEnter() {
+    this.setState({
+      dropzoneActive: true
+    });
+  }
+
+  onDragLeave() {
+    this.setState({
+      dropzoneActive: false
+    });
+  }
+
+  onDrop(files) {
+    this.setState({
+      dropzoneActive: false
+    });
+    this.dispatchUpload(files);
+  }
+
   render() {
+    const dropzoneStyle = {
+      height: '100%'
+    }
+
+    const overlayStyle = {
+      position: 'absolute',
+      zIndex: 1060,
+      top: 0,
+      right: 0,
+      bottom: 0,
+      left: 0,
+      padding: '2.5em 0',
+      background: 'rgba(0,0,0,0.5)',
+      textAlign: 'center',
+      color: '#fff'
+    };
+
     return (
-      <ReactCodeMirror
-        ref="cm"
-        editorDidMount={(editor) => {
-          // add paste event handler
-          editor.on('paste', pasteHelper.pasteHandler);
-        }}
-        value={this.state.value}
-        options={{
-          mode: 'gfm',
-          theme: 'eclipse',
-          lineNumbers: true,
-          tabSize: 4,
-          indentUnit: 4,
-          lineWrapping: true,
-          autoRefresh: true,
-          autoCloseTags: true,
-          matchBrackets: true,
-          matchTags: {bothTags: true},
-          // match-highlighter, matchesonscrollbar, annotatescrollbar options
-          highlightSelectionMatches: {annotateScrollbar: true},
-          // markdown mode options
-          highlightFormatting: true,
-          // continuelist, indentlist
-          extraKeys: {
-            "Enter": "newlineAndIndentContinueMarkdownList",
-            "Tab": "indentMore",
-            "Shift-Tab": "indentLess",
-          }
-        }}
-        onScroll={(editor, data) => {
-          if (this.props.onScroll != null) {
-            this.props.onScroll(data);
-          }
-        }}
-        onChange={(editor, data, value) => {
-          if (this.props.onChange != null) {
-            this.props.onChange(value);
-          }
-
-          // Emoji AutoComplete
-          emojiAutoCompleteHelper.showHint(editor);
-        }}
-      />
+      <Dropzone
+        disableClick
+        style={dropzoneStyle}
+        accept={this.state.accept}
+        onDragLeave={this.onDragLeave}
+        onDrop={this.onDrop}
+      >
+        { this.state.dropzoneActive && <div style={overlayStyle}>Drop files...</div> }
+        <ReactCodeMirror
+          ref="cm"
+          editorDidMount={(editor) => {
+            // add paste event handler
+            editor.on('paste', pasteHelper.pasteHandler);
+          }}
+          value={this.state.value}
+          options={{
+            mode: 'gfm',
+            theme: 'eclipse',
+            lineNumbers: true,
+            tabSize: 4,
+            indentUnit: 4,
+            lineWrapping: true,
+            autoRefresh: true,
+            autoCloseTags: true,
+            matchBrackets: true,
+            matchTags: {bothTags: true},
+            // match-highlighter, matchesonscrollbar, annotatescrollbar options
+            highlightSelectionMatches: {annotateScrollbar: true},
+            // markdown mode options
+            highlightFormatting: true,
+            // continuelist, indentlist
+            extraKeys: {
+              "Enter": "newlineAndIndentContinueMarkdownList",
+              "Tab": "indentMore",
+              "Shift-Tab": "indentLess",
+            }
+          }}
+          onScroll={(editor, data) => {
+            if (this.props.onScroll != null) {
+              this.props.onScroll(data);
+            }
+          }}
+          onChange={(editor, data, value) => {
+            if (this.props.onChange != null) {
+              this.props.onChange(value);
+            }
+
+            // Emoji AutoComplete
+            emojiAutoCompleteHelper.showHint(editor);
+          }}
+          onDragEnter={this.onDragEnter}
+        />
+      </Dropzone>
     )
   }
 
@@ -135,4 +198,5 @@ Editor.propTypes = {
   onChange: PropTypes.func,
   onScroll: PropTypes.func,
   onSave: PropTypes.func,
+  onUpload: PropTypes.func,
 };

+ 0 - 1
resource/js/legacy/crowi-form.js

@@ -2,7 +2,6 @@
   var pagePath= $('#content-main').data('path');
 
   require('bootstrap-sass');
-  require('inline-attachment/src/inline-attachment');
   require('./thirdparty-js/jquery.selection');
 
   // show/hide

+ 12 - 5
yarn.lock

@@ -326,6 +326,10 @@ asynckit@^0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
 
+attr-accept@^1.0.3:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-1.1.0.tgz#b5cd35227f163935a8f1de10ed3eba16941f6be6"
+
 autoprefixer@^6.3.1:
   version "6.7.7"
   resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
@@ -2962,10 +2966,6 @@ ini@~1.3.0:
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
 
-inline-attachment@~2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/inline-attachment/-/inline-attachment-2.0.3.tgz#5ee32374583fabd3b7206df2e20f251ba20c4306"
-
 interpret@^1.0.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
@@ -4855,7 +4855,7 @@ prop-types-extra@^1.0.1:
   dependencies:
     warning "^3.0.0"
 
-prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0:
+prop-types@^15.5.0, prop-types@^15.5.10, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0:
   version "15.6.0"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
   dependencies:
@@ -5045,6 +5045,13 @@ react-dom@^16.0.0:
     object-assign "^4.1.1"
     prop-types "^15.6.0"
 
+react-dropzone@^4.2.7:
+  version "4.2.7"
+  resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-4.2.7.tgz#a4963b1f725d5a91e63cd1c2b55ddce537953d46"
+  dependencies:
+    attr-accept "^1.0.3"
+    prop-types "^15.5.7"
+
 react-input-autosize@^2.0.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.1.tgz#ec428fa15b1592994fb5f9aa15bb1eb6baf420f8"