Просмотр исходного кода

Merge pull request #244 from weseek/master

release v1.3.5
Yuki Takei 8 лет назад
Родитель
Сommit
3495879d0a

+ 3 - 1
CHANGES.md

@@ -1,7 +1,7 @@
 CHANGES
 CHANGES
 ========
 ========
 
 
-## 2.3.4
+## 2.3.5
 
 
 * Feature: Enhanced Editor by CodeMirror
 * Feature: Enhanced Editor by CodeMirror
 * Feature: Emoji AutoComplete
 * Feature: Emoji AutoComplete
@@ -15,6 +15,8 @@ CHANGES
     * mongoose-unique-validator
     * mongoose-unique-validator
     * etc..
     * etc..
 
 
+## 2.3.4 (Missing number)
+
 ## 2.3.3
 ## 2.3.3
 
 
 * Fix: The XSS Library escapes inline code blocks
 * Fix: The XSS Library escapes inline code blocks

+ 3 - 1
config/webpack.common.js

@@ -32,7 +32,8 @@ module.exports = function (options) {
     externals: {
     externals: {
       // require("jquery") is external and available
       // require("jquery") is external and available
       //  on the global var jQuery
       //  on the global var jQuery
-      "jquery": "jQuery"
+      "jquery": "jQuery",
+      "emojione": "emojione",
     },
     },
     resolve: {
     resolve: {
       extensions: ['.js', '.json'],
       extensions: ['.js', '.json'],
@@ -100,6 +101,7 @@ module.exports = function (options) {
         jQuery: "jquery",
         jQuery: "jquery",
         $: "jquery",
         $: "jquery",
         hljs: "reveal.js/plugin/highlight/highlight",
         hljs: "reveal.js/plugin/highlight/highlight",
+        emojione: "emojione",
       }),
       }),
 
 
     ]
     ]

+ 5 - 3
lib/views/layout/layout.html

@@ -33,8 +33,8 @@
     }
     }
   </script>
   </script>
 
 
-  <!-- jQuery -->
-  <script src="https://cdn.jsdelivr.net/jquery/3.2.1/jquery.min.js"></script>
+  <!-- jQuery, emojione -->
+  <script src="https://cdn.jsdelivr.net/combine/npm/emojione@3.1.2,npm/jquery@3.3.1"></script>
 
 
   {% if env === 'development' %}
   {% if env === 'development' %}
     <script src="/dll/vendor.dll.js"></script>
     <script src="/dll/vendor.dll.js"></script>
@@ -54,7 +54,9 @@
   <!-- Google Fonts -->
   <!-- Google Fonts -->
   <link href='https://fonts.googleapis.com/css?family=Lato:400,700' rel='stylesheet' type='text/css'>
   <link href='https://fonts.googleapis.com/css?family=Lato:400,700' rel='stylesheet' type='text/css'>
   <!-- Font Awesome -->
   <!-- Font Awesome -->
-  <link href='https://cdn.jsdelivr.net/fontawesome/4.7.0/css/font-awesome.min.css' rel='stylesheet' type='text/css'>
+  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css">
+  <!-- emojione -->
+  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/emojione@3.1.2/extras/css/emojione.min.css">
 
 
   {% block html_additional_headers %}{% endblock %}
   {% block html_additional_headers %}{% endblock %}
 
 

+ 2 - 3
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "crowi-plus",
   "name": "crowi-plus",
-  "version": "2.3.4-RC",
+  "version": "2.3.5-RC",
   "description": "Enhanced Crowi",
   "description": "Enhanced Crowi",
   "tags": [
   "tags": [
     "wiki",
     "wiki",
@@ -42,7 +42,7 @@
     "server:prod": "env-cmd config/env.prod.js node app.js --production | pino-clf common",
     "server:prod": "env-cmd config/env.prod.js node app.js --production | pino-clf common",
     "server": "npm run server:dev:watch",
     "server": "npm run server:dev:watch",
     "start": "npm run server:prod",
     "start": "npm run server:prod",
-    "test": "mocha -r test/bootstrap.js test/**/*.js",
+    "test": "mocha --timeout 10000 -r test/bootstrap.js test/**/*.js",
     "version": "node -p \"require('./package.json').version\"",
     "version": "node -p \"require('./package.json').version\"",
     "webpack": "webpack"
     "webpack": "webpack"
   },
   },
@@ -73,7 +73,6 @@
     "diff": "^3.3.0",
     "diff": "^3.3.0",
     "diff2html": "^2.3.0",
     "diff2html": "^2.3.0",
     "elasticsearch": "^14.0.0",
     "elasticsearch": "^14.0.0",
-    "emojione": "^3.1.2",
     "entities": "^1.1.1",
     "entities": "^1.1.1",
     "env-cmd": "^7.0.0",
     "env-cmd": "^7.0.0",
     "escape-string-regexp": "^1.0.5",
     "escape-string-regexp": "^1.0.5",

+ 0 - 4
resource/css/_form.scss

@@ -265,10 +265,6 @@
     .img-container {
     .img-container {
       display: inline-block;
       display: inline-block;
       width: 30px;
       width: 30px;
-
-      img.emojione {
-        width: 1.6em;
-      }
     }
     }
   }
   }
   // active line
   // active line

+ 0 - 1
resource/css/_wiki.scss

@@ -145,7 +145,6 @@ div.body {
   }
   }
 
 
   img.emojione {
   img.emojione {
-    width: 1.6em;
     margin-top: -0.3em !important;
     margin-top: -0.3em !important;
     margin-bottom: 0 !important;
     margin-bottom: 0 !important;
     border: none;
     border: none;

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

@@ -39,16 +39,13 @@ export default class PageEditor extends React.Component {
     // create throttled function
     // create throttled function
     this.renderWithDebounce = debounce(50, throttle(100, this.renderPreview));
     this.renderWithDebounce = debounce(50, throttle(100, this.renderPreview));
     this.saveDraftWithDebounce = debounce(300, this.saveDraft);
     this.saveDraftWithDebounce = debounce(300, this.saveDraft);
-
-    // initial rendering
-    this.renderPreview(this.state.markdown);
   }
   }
 
 
   componentWillMount() {
   componentWillMount() {
     // restore draft
     // restore draft
     this.restoreDraft();
     this.restoreDraft();
-    // initial preview
-    this.renderPreview();
+    // initial rendering
+    this.renderPreview(this.state.markdown);
   }
   }
 
 
   focusToEditor() {
   focusToEditor() {
@@ -233,6 +230,8 @@ export default class PageEditor extends React.Component {
   renderPreview(value) {
   renderPreview(value) {
     const config = this.props.crowi.config;
     const config = this.props.crowi.config;
 
 
+    this.setState({ markdown: value });
+
     // generate options obj
     // generate options obj
     const rendererOptions = {
     const rendererOptions = {
       // see: https://www.npmjs.com/package/marked
       // see: https://www.npmjs.com/package/marked
@@ -243,7 +242,7 @@ export default class PageEditor extends React.Component {
 
 
     // render html
     // render html
     var context = {
     var context = {
-      markdown: value,
+      markdown: this.state.markdown,
       dom: this.previewElement,
       dom: this.previewElement,
       currentPagePath: decodeURIComponent(location.pathname)
       currentPagePath: decodeURIComponent(location.pathname)
     };
     };
@@ -261,10 +260,7 @@ export default class PageEditor extends React.Component {
       .then(() => crowi.interceptorManager.process('postRenderPreview', context))
       .then(() => crowi.interceptorManager.process('postRenderPreview', context))
       .then(() => crowi.interceptorManager.process('preRenderPreviewHtml', context))
       .then(() => crowi.interceptorManager.process('preRenderPreviewHtml', context))
       .then(() => {
       .then(() => {
-        this.setState({
-          markdown: value,
-          html: context.parsedHTML,
-        });
+        this.setState({ html: context.parsedHTML });
 
 
         // set html to the hidden input (for submitting to save)
         // set html to the hidden input (for submitting to save)
         $('#form-body').val(this.state.markdown);
         $('#form-body').val(this.state.markdown);

+ 4 - 2
resource/js/components/PageEditor/Editor.js

@@ -253,7 +253,7 @@ export default class Editor extends React.Component {
       flexDirection: 'column',
       flexDirection: 'column',
     }
     }
     const expandHeight = {
     const expandHeight = {
-      height: '100%',
+      height: 'calc(100% - 20px)'
     }
     }
 
 
     return (
     return (
@@ -323,7 +323,9 @@ export default class Editor extends React.Component {
           />
           />
         </Dropzone>
         </Dropzone>
 
 
-        <button type="button" className="btn btn-default btn-block btn-open-dropzone" onClick={() => {this.refs.dropzone.open()}}>
+        <button type="button" className="btn btn-default btn-block btn-open-dropzone"
+            onClick={() => {this.refs.dropzone.open()}}>
+
           <i className="fa fa-paperclip" aria-hidden="true"></i>&nbsp;
           <i className="fa fa-paperclip" aria-hidden="true"></i>&nbsp;
           Attach files by dragging &amp; dropping,&nbsp;
           Attach files by dragging &amp; dropping,&nbsp;
           <span className="btn-link">selecting them</span>,&nbsp;
           <span className="btn-link">selecting them</span>,&nbsp;

+ 23 - 14
resource/js/components/PageEditor/EmojiAutoCompleteHelper.js

@@ -1,23 +1,33 @@
-import emojione from 'emojione';
-import emojiStrategy from 'emojione/emoji_strategy.json';
+import axios from 'axios';
 
 
 class EmojiAutoCompleteHelper {
 class EmojiAutoCompleteHelper {
 
 
   constructor() {
   constructor() {
-    this.initEmojiImageMap = this.initEmojiImageMap.bind(this);
-    this.showHint = this.showHint.bind(this);
+    this.emojiStrategy = {};
+    this.emojiShortnameImageMap = {}
 
 
     this.initEmojiImageMap()
     this.initEmojiImageMap()
+      .then(() => {
+        Object.freeze(this);  // freeze after initializing data
+      })
+
+    this.initEmojiImageMap = this.initEmojiImageMap.bind(this);
+    this.showHint = this.showHint.bind(this);
   }
   }
 
 
   initEmojiImageMap() {
   initEmojiImageMap() {
-    this.emojiShortnameImageMap = {};
-    for (let unicode in emojiStrategy) {
-      const data = emojiStrategy[unicode];
-      const shortname = data.shortname;
-      // add image tag
-      this.emojiShortnameImageMap[shortname] = emojione.shortnameToImage(shortname);
-    }
+    const emojiStrategyUrl = 'https://cdn.jsdelivr.net/npm/emojione@3.1.2/emoji_strategy.json';
+
+    return axios.get(emojiStrategyUrl)
+      .then((res) => {
+        this.emojiStrategy = res.data;
+        for (let unicode in this.emojiStrategy) {
+          const data = this.emojiStrategy[unicode];
+          const shortname = data.shortname;
+          // add image tag
+          this.emojiShortnameImageMap[shortname] = emojione.shortnameToImage(shortname);
+        }
+      });
   }
   }
 
 
   /**
   /**
@@ -96,8 +106,8 @@ class EmojiAutoCompleteHelper {
     const countLen4 = () => { countLen3() + results4.length; }
     const countLen4 = () => { countLen3() + results4.length; }
     // TODO performance tune
     // TODO performance tune
     // when total length of all results is less than `maxLength`
     // when total length of all results is less than `maxLength`
-    for (let unicode in emojiStrategy) {
-      const data = emojiStrategy[unicode];
+    for (let unicode in this.emojiStrategy) {
+      const data = this.emojiStrategy[unicode];
 
 
       if (maxLength <= countLen1()) { break; }
       if (maxLength <= countLen1()) { break; }
       // prefix match to shortname
       // prefix match to shortname
@@ -134,5 +144,4 @@ class EmojiAutoCompleteHelper {
 
 
 // singleton pattern
 // singleton pattern
 const instance = new EmojiAutoCompleteHelper();
 const instance = new EmojiAutoCompleteHelper();
-Object.freeze(instance);
 export default instance;
 export default instance;

+ 9 - 2
resource/js/legacy/crowi.js

@@ -452,12 +452,19 @@ $(function() {
     return false;
     return false;
   });
   });
 
 
-  // list-link
+  /*
+   * wrap short path with <strong></strong> 
+   */
   $('.page-list-link').each(function() {
   $('.page-list-link').each(function() {
     var $link = $(this);
     var $link = $(this);
     var text = $link.text();
     var text = $link.text();
     var path = $link.data('path');
     var path = $link.data('path');
-    var shortPath = new String($link.data('short-path'));
+    var shortPath = String($link.data('short-path')); // convert to string
+
+    if (path == null || shortPath == null) {
+      // continue
+      return;
+    }
 
 
     var escape = function(s) {
     var escape = function(s) {
       return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
       return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');

+ 0 - 2
resource/js/util/PostProcessor/Emoji.js

@@ -1,5 +1,3 @@
-import emojione from 'emojione';
-
 export default class Emoji {
 export default class Emoji {
 
 
   process(markdown) {
   process(markdown) {

+ 5 - 5
test/models/page.test.js

@@ -14,7 +14,7 @@ describe('Page', () => {
     createdUsers;
     createdUsers;
 
 
   before(done => {
   before(done => {
-    Promise.resolve().then(() => {
+    conn.collection('pages').remove().then(() => {
       var userFixture = [
       var userFixture = [
         {name: 'Anon 0', username: 'anonymous0', email: 'anonymous0@example.com'},
         {name: 'Anon 0', username: 'anonymous0', email: 'anonymous0@example.com'},
         {name: 'Anon 1', username: 'anonymous1', email: 'anonymous1@example.com'}
         {name: 'Anon 1', username: 'anonymous1', email: 'anonymous1@example.com'}
@@ -27,7 +27,7 @@ describe('Page', () => {
 
 
       var fixture = [
       var fixture = [
         {
         {
-          path: '/user/anonymous/memo',
+          path: '/user/anonymous0/memo',
           grant: Page.GRANT_RESTRICTED,
           grant: Page.GRANT_RESTRICTED,
           grantedUsers: [testUser0],
           grantedUsers: [testUser0],
           creator: testUser0
           creator: testUser0
@@ -174,7 +174,7 @@ describe('Page', () => {
         User.findOne({email: 'anonymous0@example.com'}, (err, user) => {
         User.findOne({email: 'anonymous0@example.com'}, (err, user) => {
           if (err) { done(err); }
           if (err) { done(err); }
 
 
-          Page.findOne({path: '/user/anonymous/memo'}, (err, page) => {
+          Page.findOne({path: '/user/anonymous0/memo'}, (err, page) => {
             expect(page.isCreator(user)).to.be.equal(true);
             expect(page.isCreator(user)).to.be.equal(true);
             done();
             done();
           })
           })
@@ -187,7 +187,7 @@ describe('Page', () => {
         User.findOne({email: 'anonymous1@example.com'}, (err, user) => {
         User.findOne({email: 'anonymous1@example.com'}, (err, user) => {
           if (err) { done(err); }
           if (err) { done(err); }
 
 
-          Page.findOne({path: '/user/anonymous/memo'}, (err, page) => {
+          Page.findOne({path: '/user/anonymous0/memo'}, (err, page) => {
             expect(page.isCreator(user)).to.be.equal(false);
             expect(page.isCreator(user)).to.be.equal(false);
             done();
             done();
           })
           })
@@ -202,7 +202,7 @@ describe('Page', () => {
         User.findOne({email: 'anonymous0@example.com'}, (err, user) => {
         User.findOne({email: 'anonymous0@example.com'}, (err, user) => {
           if (err) { done(err); }
           if (err) { done(err); }
 
 
-          Page.findOne({path: '/user/anonymous/memo'}, (err, page) => {
+          Page.findOne({path: '/user/anonymous0/memo'}, (err, page) => {
             if (err) { done(err); }
             if (err) { done(err); }
 
 
             expect(page.isGrantedFor(user)).to.be.equal(true);
             expect(page.isGrantedFor(user)).to.be.equal(true);

+ 8 - 0
test/models/user.test.js

@@ -11,6 +11,14 @@ describe('User', function () {
     User   = utils.models.User,
     User   = utils.models.User,
     conn   = utils.mongoose.connection;
     conn   = utils.mongoose.connection;
 
 
+  // clear collection
+  before(done => {
+    conn.collection('users').remove()
+      .then(() => {
+        done();
+      });
+  });
+
   describe('Create and Find.', function () {
   describe('Create and Find.', function () {
     context('The user', function() {
     context('The user', function() {
       it('should created', function(done) {
       it('should created', function(done) {

+ 0 - 4
yarn.lock

@@ -2001,10 +2001,6 @@ elliptic@^6.0.0:
     minimalistic-assert "^1.0.0"
     minimalistic-assert "^1.0.0"
     minimalistic-crypto-utils "^1.0.0"
     minimalistic-crypto-utils "^1.0.0"
 
 
-emojione@^3.1.2:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/emojione/-/emojione-3.1.2.tgz#991e30c80db4b1cf15eacb257620a7edce9c6ef4"
-
 emojis-list@^2.0.0:
 emojis-list@^2.0.0:
   version "2.1.0"
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
   resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"