Browse Source

Merge pull request #275 from weseek/master

release v2.4.1
Yuki Takei 8 years ago
parent
commit
9410606b71

+ 13 - 1
CHANGES.md

@@ -1,7 +1,19 @@
 CHANGES
 CHANGES
 ========
 ========
 
 
-## 2.4.0-RC2
+## 2.4.1-RC
+
+* Feature: Custom Header HTML
+* Improvement: Add highlight.js languages
+    * dockerfile, go, gradle, json, less, scss, typescript, yaml
+* Fix: Couldn't connect to PLANTUML_URI
+    * Introduced by 2.4.0
+* Fix: Couldn't render UML which includes CJK
+    * Introduced by 2.4.0
+* Support: Upgrade libs
+    * axios
+
+## 2.4.0
 
 
 * Feature: Support Footnotes
 * Feature: Support Footnotes
 * Feature: Support Task lists
 * Feature: Support Task lists

+ 1 - 6
LICENSE

@@ -1,6 +1,6 @@
 MIT License
 MIT License
 
 
-Copyright (c) 2017 WESEEK, Inc.
+Copyright (c) 2018 WESEEK, Inc.
 
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 of this software and associated documentation files (the "Software"), to deal
@@ -19,8 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 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
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 SOFTWARE.
-
-----
-
-This software is copied and modified from https://github.com/crowi/crowi,
-released under the MIT license, Copyright (c) 2013 Sotaro KARASAWA <sotaro.k@gmail.com>

+ 80 - 0
THIRD-PARTY-NOTICES.md

@@ -0,0 +1,80 @@
+crowi-plus uses third-party libraries or other resources that may  
+be distributed under licenses different than the crowi-plus software.
+
+In the event that we accidentally failed to list a required notice,  
+please bring it to our attention through any of the ways detailed here :
+
+    info@weseek.co.jp
+
+The attached notices are provided for information only.
+
+For any licenses that require disclosure of source, sources are available at  
+https://github.com/weseek/crowi-plus.
+
+
+1. crowi/crowi (https://github.com/crowi/crowi)
+2. Microsoft/vscode (https://github.com/Microsoft/vscode)
+
+
+
+License Notice for Crowi
+-------------------------
+
+https://github.com/crowi/crowi/blob/master/LICENSE
+
+```
+The MIT License (MIT)
+
+Copyright (c) 2013 Sotaro KARASAWA <sotaro.k@gmail.com>
+
+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.
+```
+
+
+License Notice for Visual Studio Code
+-------------------------------------
+
+https://github.com/Microsoft/vscode/blob/master/LICENSE.txt
+
+```
+MIT License
+
+Copyright (c) 2015 - present Microsoft Corporation
+
+All rights reserved.
+
+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.
+
+```

+ 9 - 0
config/webpack.common.js

@@ -10,6 +10,7 @@ const helpers = require('./helpers');
  */
  */
 const AssetsPlugin = require('assets-webpack-plugin');
 const AssetsPlugin = require('assets-webpack-plugin');
 const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
 const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
+const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');;
 
 
 /*
 /*
  * Webpack configuration
  * Webpack configuration
@@ -47,6 +48,9 @@ module.exports = function (options) {
           exclude: /node_modules/,
           exclude: /node_modules/,
           use: [{
           use: [{
             loader: 'babel-loader?cacheDirectory',
             loader: 'babel-loader?cacheDirectory',
+            options: {
+              plugins: ['lodash'],
+            }
           }]
           }]
         },
         },
         {
         {
@@ -98,6 +102,11 @@ module.exports = function (options) {
         chunks: ['commons', 'plugin'],
         chunks: ['commons', 'plugin'],
       }),
       }),
 
 
+      new LodashModuleReplacementPlugin,
+
+      // ignore
+      new webpack.IgnorePlugin(/^\.\/lib\/deflate\.js/, /markdown-it-plantuml/),
+
       new webpack.ProvidePlugin({ // refs externals
       new webpack.ProvidePlugin({ // refs externals
         jQuery: "jquery",
         jQuery: "jquery",
         $: "jquery",
         $: "jquery",

+ 9 - 0
lib/form/admin/customheader.js

@@ -0,0 +1,9 @@
+'use strict';
+
+var form = require('express-form')
+  , field = form.field
+  ;
+
+module.exports = form(
+  field('settingForm[customize:header]')
+);

+ 1 - 0
lib/form/index.js

@@ -22,6 +22,7 @@ module.exports = {
     markdown: require('./admin/markdown'),
     markdown: require('./admin/markdown'),
     customcss: require('./admin/customcss'),
     customcss: require('./admin/customcss'),
     customscript: require('./admin/customscript'),
     customscript: require('./admin/customscript'),
+    customheader: require('./admin/customheader'),
     custombehavior: require('./admin/custombehavior'),
     custombehavior: require('./admin/custombehavior'),
     customlayout: require('./admin/customlayout'),
     customlayout: require('./admin/customlayout'),
     customfeatures: require('./admin/customfeatures'),
     customfeatures: require('./admin/customfeatures'),

+ 7 - 0
lib/models/config.js

@@ -84,6 +84,7 @@ module.exports = function(crowi) {
 
 
       'customize:css' : '',
       'customize:css' : '',
       'customize:script' : '',
       'customize:script' : '',
+      'customize:header' : '',
       'customize:behavior' : 'crowi',
       'customize:behavior' : 'crowi',
       'customize:layout' : 'crowi',
       'customize:layout' : 'crowi',
       'customize:isEnabledTimeline' : true,
       'customize:isEnabledTimeline' : true,
@@ -351,6 +352,12 @@ module.exports = function(crowi) {
     return this._customScript;
     return this._customScript;
   }
   }
 
 
+  configSchema.statics.customHeader = function(config)
+  {
+    const key = 'customize:header';
+    return getValueForCrowiNS(config, key);
+  }
+
   configSchema.statics.behaviorType = function(config)
   configSchema.statics.behaviorType = function(config)
   {
   {
     const key = 'customize:behavior';
     const key = 'customize:behavior';

+ 1 - 0
lib/routes/index.js

@@ -73,6 +73,7 @@ module.exports = function(crowi, app) {
   app.get('/admin/customize'                , loginRequired(crowi, app) , middleware.adminRequired() , admin.customize.index);
   app.get('/admin/customize'                , loginRequired(crowi, app) , middleware.adminRequired() , admin.customize.index);
   app.post('/_api/admin/customize/css'      , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customcss, admin.api.customizeSetting);
   app.post('/_api/admin/customize/css'      , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customcss, admin.api.customizeSetting);
   app.post('/_api/admin/customize/script'   , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customscript, admin.api.customizeSetting);
   app.post('/_api/admin/customize/script'   , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customscript, admin.api.customizeSetting);
+  app.post('/_api/admin/customize/header'   , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customheader, admin.api.customizeSetting);
   app.post('/_api/admin/customize/behavior' , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.custombehavior, admin.api.customizeSetting);
   app.post('/_api/admin/customize/behavior' , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.custombehavior, admin.api.customizeSetting);
   app.post('/_api/admin/customize/layout'   , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customlayout, admin.api.customizeSetting);
   app.post('/_api/admin/customize/layout'   , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customlayout, admin.api.customizeSetting);
   app.post('/_api/admin/customize/features' , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customfeatures, admin.api.customizeSetting);
   app.post('/_api/admin/customize/features' , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.customfeatures, admin.api.customizeSetting);

+ 5 - 0
lib/util/swigFunctions.js

@@ -92,6 +92,11 @@ module.exports = function(crowi, app, req, locals) {
     return Config.customScript();
     return Config.customScript();
   }
   }
 
 
+  locals.customHeader = function() {
+    var config = crowi.getConfig()
+    return Config.customHeader(config);
+  }
+
   locals.behaviorType = function() {
   locals.behaviorType = function() {
     var config = crowi.getConfig()
     var config = crowi.getConfig()
     return Config.behaviorType(config);
     return Config.behaviorType(config);

+ 40 - 4
lib/views/admin/customize.html

@@ -204,13 +204,49 @@
       </fieldset>
       </fieldset>
       </form>
       </form>
 
 
+      <form action="/_api/admin/customize/header" method="post" class="form-horizontal" id="cutomheaderSettingForm" role="form">
+      <fieldset>
+        <legend>カスタムヘッダーHTML</legend>
+
+        <p class="well">
+          システム全体に適用される HTML を記述できます。<code>&lt;header&gt;</code> タグ内の他の <code>&lt;script&gt;</code> タグ読み込み前に展開されます。<br>
+          変更の反映はページの更新が必要です。
+        </p>
+
+        <p class="help-block">
+          Examples:
+          <pre><code>&lt;script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.12.0/build/languages/yaml.min.js" defer&gt;&lt;script&gt;</script></code></pre>
+        </p>
+
+        <div class="form-group">
+          <div class="col-xs-12">
+            <div id="custom-header-editor"></div>
+            <input type="hidden" id="inputCustomHeader" name="settingForm[customize:header]" value="{{ settingForm['customize:header'] }}">
+          </div>
+          <div class="col-xs-12">
+            <p class="help-block text-right">
+              <i class="fa fa-fw fa-keyboard-o" aria-hidden="true"></i>
+              Ctrl+Space でコード補完
+            </p>
+          </div>
+        </div>
+
+        <div class="form-group">
+          <div class="col-xs-offset-5 col-xs-6">
+            <input type="hidden" name="_csrf" value="{{ csrf() }}">
+            <button type="submit" class="btn btn-primary">更新</button>
+          </div>
+        </div>
+
+      </fieldset>
+      </form>
 
 
       <form action="/_api/admin/customize/css" method="post" class="form-horizontal" id="cutomcssSettingForm" role="form">
       <form action="/_api/admin/customize/css" method="post" class="form-horizontal" id="cutomcssSettingForm" role="form">
       <fieldset>
       <fieldset>
-        <legend>カスタムCSS</legend>
+        <legend>カスタムヘッダーCSS</legend>
 
 
         <p class="well">
         <p class="well">
-          システム全体に適用されるCSSを記述できます。<br>
+          システム全体に適用されるCSSを記述できます。<code>&lt;header&gt;</code> タグ内に展開されます。<br>
           変更の反映はページの更新が必要です。
           変更の反映はページの更新が必要です。
         </p>
         </p>
 
 
@@ -243,7 +279,7 @@
         <legend>カスタムスクリプト</legend>
         <legend>カスタムスクリプト</legend>
 
 
         <p class="well">
         <p class="well">
-          システム全体に適用されるJavaScriptを記述できます。<br>
+          システム全体に適用されるJavaScriptを記述できます。<code>&lt;body&gt;</code> タグ内の最後に展開されます。<br>
           変更の反映はページの更新が必要です。
           変更の反映はページの更新が必要です。
         </p>
         </p>
 
 
@@ -299,7 +335,7 @@ window.addEventListener('load', (event) => {
   </div>
   </div>
 
 
   <script>
   <script>
-    $('#cutomcssSettingForm, #cutomscriptSettingForm, #cutomlayoutSettingForm, #cutombehaviorSettingForm, #customfeaturesSettingForm').each(function() {
+    $('#cutomcssSettingForm, #cutomscriptSettingForm, #cutomlayoutSettingForm, #cutombehaviorSettingForm, #customfeaturesSettingForm, #cutomheaderSettingForm').each(function() {
       $(this).submit(function()
       $(this).submit(function()
       {
       {
         function showMessage(formId, msg, status) {
         function showMessage(formId, msg, status) {

+ 13 - 0
lib/views/layout/layout.html

@@ -22,6 +22,8 @@
   <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
   <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
   <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
   <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
 
 
+  {{ customHeader() }}
+
   <!-- polyfills for IE11 -->
   <!-- polyfills for IE11 -->
   <script>
   <script>
     var userAgent = window.navigator.userAgent.toLowerCase();
     var userAgent = window.navigator.userAgent.toLowerCase();
@@ -37,6 +39,17 @@
   <script src="https://cdn.jsdelivr.net/combine/npm/emojione@3.1.2,npm/jquery@3.3.1"></script>
   <script src="https://cdn.jsdelivr.net/combine/npm/emojione@3.1.2,npm/jquery@3.3.1"></script>
   <!-- highlight.js -->
   <!-- highlight.js -->
   <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.12.0/build/highlight.min.js"></script>
   <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.12.0/build/highlight.min.js"></script>
+  <script src="https://cdn.jsdelivr.net/combine/
+gh/highlightjs/cdn-release@9.12.0/build/languages/dockerfile.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/go.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/gradle.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/json.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/less.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/scss.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/typescript.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/yaml.min.js
+" defer></script>
+
   {% if local_config.env.MATHJAX %}
   {% if local_config.env.MATHJAX %}
     <!-- Mathjax -->
     <!-- Mathjax -->
     <script type="text/x-mathjax-config" async>
     <script type="text/x-mathjax-config" async>

+ 12 - 0
lib/views/page_presentation.html

@@ -6,6 +6,8 @@
     <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
     <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
 
 
+    {{ customHeader() }}
+
     <!-- polyfills for IE11 -->
     <!-- polyfills for IE11 -->
     <script>
     <script>
       var userAgent = window.navigator.userAgent.toLowerCase();
       var userAgent = window.navigator.userAgent.toLowerCase();
@@ -21,6 +23,16 @@
     <script src="https://cdn.jsdelivr.net/combine/npm/emojione@3.1.2,npm/jquery@3.3.1"></script>
     <script src="https://cdn.jsdelivr.net/combine/npm/emojione@3.1.2,npm/jquery@3.3.1"></script>
     <!-- highlight.js -->
     <!-- highlight.js -->
     <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.12.0/build/highlight.min.js"></script>
     <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@9.12.0/build/highlight.min.js"></script>
+    <script src="https://cdn.jsdelivr.net/combine/
+gh/highlightjs/cdn-release@9.12.0/build/languages/dockerfile.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/go.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/gradle.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/json.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/less.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/scss.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/typescript.min.js,
+gh/highlightjs/cdn-release@9.12.0/build/languages/yaml.min.js
+" defer></script>
 
 
     {% if env === 'development' %}
     {% if env === 'development' %}
       <script src="/dll/vendor.dll.js"></script>
       <script src="/dll/vendor.dll.js"></script>

+ 6 - 3
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "crowi-plus",
   "name": "crowi-plus",
-  "version": "2.4.0-RC2",
+  "version": "2.4.1-RC",
   "description": "Enhanced Crowi",
   "description": "Enhanced Crowi",
   "tags": [
   "tags": [
     "wiki",
     "wiki",
@@ -51,9 +51,10 @@
     "assets-webpack-plugin": "~3.5.1",
     "assets-webpack-plugin": "~3.5.1",
     "async": "^2.3.0",
     "async": "^2.3.0",
     "aws-sdk": "^2.88.0",
     "aws-sdk": "^2.88.0",
-    "axios": "^0.17.0",
+    "axios": "^0.18.0",
     "babel-core": "^6.25.0",
     "babel-core": "^6.25.0",
     "babel-loader": "^7.1.1",
     "babel-loader": "^7.1.1",
+    "babel-plugin-lodash": "^3.3.2",
     "babel-preset-env": "^1.6.0",
     "babel-preset-env": "^1.6.0",
     "babel-preset-react": "^6.24.1",
     "babel-preset-react": "^6.24.1",
     "basic-auth-connect": "~1.0.0",
     "basic-auth-connect": "~1.0.0",
@@ -72,7 +73,7 @@
     "date-fns": "^1.29.0",
     "date-fns": "^1.29.0",
     "debug": "^3.1.0",
     "debug": "^3.1.0",
     "diff": "^3.3.0",
     "diff": "^3.3.0",
-    "diff2html": "^2.3.0",
+    "diff2html": "^2.3.3",
     "elasticsearch": "^14.0.0",
     "elasticsearch": "^14.0.0",
     "entities": "^1.1.1",
     "entities": "^1.1.1",
     "env-cmd": "^7.0.0",
     "env-cmd": "^7.0.0",
@@ -91,6 +92,7 @@
     "i18next-sprintf-postprocessor": "^0.2.2",
     "i18next-sprintf-postprocessor": "^0.2.2",
     "jquery-ui": "^1.12.1",
     "jquery-ui": "^1.12.1",
     "jquery.cookie": "~1.4.1",
     "jquery.cookie": "~1.4.1",
+    "lodash-webpack-plugin": "^0.11.4",
     "markdown-it": "^8.4.0",
     "markdown-it": "^8.4.0",
     "markdown-it-emoji": "^1.4.0",
     "markdown-it-emoji": "^1.4.0",
     "markdown-it-footnote": "^3.0.1",
     "markdown-it-footnote": "^3.0.1",
@@ -115,6 +117,7 @@
     "passport-ldapauth": "^2.0.0",
     "passport-ldapauth": "^2.0.0",
     "passport-local": "^1.0.0",
     "passport-local": "^1.0.0",
     "pino-clf": "^1.0.2",
     "pino-clf": "^1.0.2",
+    "plantuml-encoder": "^1.2.5",
     "react": "^16.0.0",
     "react": "^16.0.0",
     "react-bootstrap": "^0.32.0",
     "react-bootstrap": "^0.32.0",
     "react-bootstrap-typeahead": "^2.0.2",
     "react-bootstrap-typeahead": "^2.0.2",

+ 11 - 0
resource/js/app.js

@@ -25,6 +25,7 @@ import SearchTypeahead  from './components/SearchTypeahead';
 
 
 import CustomCssEditor  from './components/Admin/CustomCssEditor';
 import CustomCssEditor  from './components/Admin/CustomCssEditor';
 import CustomScriptEditor from './components/Admin/CustomScriptEditor';
 import CustomScriptEditor from './components/Admin/CustomScriptEditor';
+import CustomHeaderEditor from './components/Admin/CustomHeaderEditor';
 
 
 import * as entities from 'entities';
 import * as entities from 'entities';
 
 
@@ -193,6 +194,16 @@ if (customScriptEditorElem != null) {
     customScriptEditorElem
     customScriptEditorElem
   )
   )
 }
 }
+const customHeaderEditorElem = document.getElementById('custom-header-editor');
+if (customHeaderEditorElem != null) {
+  // get input[type=hidden] element
+  const customHeaderInputElem = document.getElementById('inputCustomHeader');
+
+  ReactDOM.render(
+    <CustomHeaderEditor inputElem={customHeaderInputElem} />,
+    customHeaderEditorElem
+  )
+}
 
 
 // うわーもうー
 // うわーもうー
 $('a[data-toggle="tab"][href="#revision-history"]').on('show.bs.tab', function() {
 $('a[data-toggle="tab"][href="#revision-history"]').on('show.bs.tab', function() {

+ 59 - 0
resource/js/components/Admin/CustomHeaderEditor.js

@@ -0,0 +1,59 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { UnControlled as CodeMirror } from 'react-codemirror2';
+require('codemirror/lib/codemirror.css');
+require('codemirror/addon/display/autorefresh');
+require('codemirror/addon/hint/show-hint');
+require('codemirror/addon/edit/matchbrackets');
+require('codemirror/addon/edit/closebrackets');
+require('codemirror/mode/htmlmixed/htmlmixed');
+require('codemirror/theme/eclipse.css');
+
+require('jquery-ui/ui/widgets/resizable');
+
+export default class CustomHeaderEditor extends React.Component {
+
+  constructor(props) {
+    super(props);
+  }
+
+  render() {
+    // get initial value from inputElem
+    const value = this.props.inputElem.value;
+
+    return (
+      <CodeMirror
+        value={value}
+        autoFocus={true}
+        options={{
+          mode: 'htmlmixed',
+          lineNumbers: true,
+          tabSize: 2,
+          indentUnit: 2,
+          theme: 'eclipse',
+          autoRefresh: true,
+          matchBrackets: true,
+          autoCloseBrackets: true,
+          extraKeys: {"Ctrl-Space": "autocomplete"},
+        }}
+        editorDidMount={(editor, next) => {
+          // resizable with jquery.ui
+          $(editor.getWrapperElement()).resizable({
+            resize: function() {
+              editor.setSize($(this).width(), $(this).height());
+            }
+          });
+        }}
+        onChange={(editor, data, value) => {
+          this.props.inputElem.value = value;
+        }}
+      />
+    )
+  }
+
+}
+
+CustomHeaderEditor.propTypes = {
+  inputElem: PropTypes.object.isRequired,
+};

+ 4 - 1
resource/js/util/GrowiRenderer.js

@@ -152,12 +152,15 @@ export default class GrowiRenderer {
         return this.langProcessors[lang].process(code, langExt);
         return this.langProcessors[lang].process(code, langExt);
       }
       }
 
 
+      const citeTag = (langFn) ? `<cite>${langFn}</cite>` : '';
       if (hljs.getLanguage(lang)) {
       if (hljs.getLanguage(lang)) {
-        let citeTag = (langFn) ? `<cite>${langFn}</cite>` : '';
         try {
         try {
           return `<pre class="hljs">${citeTag}<code class="language-${lang}">${hljs.highlight(lang, code, true).value}</code></pre>`;
           return `<pre class="hljs">${citeTag}<code class="language-${lang}">${hljs.highlight(lang, code, true).value}</code></pre>`;
         } catch (__) {}
         } catch (__) {}
       }
       }
+      else {
+        return `<pre class="hljs">${citeTag}<code>${code}</code></pre>`;
+      }
     }
     }
 
 
     return '';
     return '';

+ 4 - 5
resource/js/util/markdown-it/plantuml.js

@@ -1,3 +1,4 @@
+import plantumlEncoder from 'plantuml-encoder';
 import urljoin from 'url-join';
 import urljoin from 'url-join';
 
 
 export default class PlantUMLConfigurer {
 export default class PlantUMLConfigurer {
@@ -6,8 +7,7 @@ export default class PlantUMLConfigurer {
     this.crowi = crowi;
     this.crowi = crowi;
     const config = crowi.getConfig();
     const config = crowi.getConfig();
 
 
-    this.deflate = require('markdown-it-plantuml/lib/deflate.js');
-    this.serverUrl = config.env.PLANTUML_URI || 'http://plantuml.com';
+    this.serverUrl = config.env.PLANTUML_URI || 'http://plantuml.com/plantuml';
 
 
     this.generateSource = this.generateSource.bind(this);
     this.generateSource = this.generateSource.bind(this);
   }
   }
@@ -19,8 +19,7 @@ export default class PlantUMLConfigurer {
   }
   }
 
 
   generateSource(umlCode) {
   generateSource(umlCode) {
-    const zippedCode =
-      this.deflate.encode64(this.deflate.zip_deflate('@startuml\n' + umlCode + '\n@enduml', 9));
-    return urljoin(this.serverUrl, 'plantuml', 'svg' , zippedCode);
+    const zippedCode = plantumlEncoder.encode(`@startuml\n${umlCode}\n@enduml`);
+    return urljoin(this.serverUrl, 'svg' , zippedCode);
   }
   }
 }
 }

+ 74 - 3
yarn.lock

@@ -376,6 +376,13 @@ axios@^0.17.0, axios@^0.17.1:
     follow-redirects "^1.2.5"
     follow-redirects "^1.2.5"
     is-buffer "^1.1.5"
     is-buffer "^1.1.5"
 
 
+axios@^0.18.0:
+  version "0.18.0"
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
+  dependencies:
+    follow-redirects "^1.3.0"
+    is-buffer "^1.1.5"
+
 babel-code-frame@^6.26.0:
 babel-code-frame@^6.26.0:
   version "6.26.0"
   version "6.26.0"
   resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
   resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
@@ -487,6 +494,13 @@ babel-helper-hoist-variables@^6.24.1:
     babel-runtime "^6.22.0"
     babel-runtime "^6.22.0"
     babel-types "^6.24.1"
     babel-types "^6.24.1"
 
 
+babel-helper-module-imports@^7.0.0-beta.3:
+  version "7.0.0-beta.3"
+  resolved "https://registry.yarnpkg.com/babel-helper-module-imports/-/babel-helper-module-imports-7.0.0-beta.3.tgz#e15764e3af9c8e11810c09f78f498a2bdc71585a"
+  dependencies:
+    babel-types "7.0.0-beta.3"
+    lodash "^4.2.0"
+
 babel-helper-optimise-call-expression@^6.24.1:
 babel-helper-optimise-call-expression@^6.24.1:
   version "6.24.1"
   version "6.24.1"
   resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
   resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
@@ -550,6 +564,16 @@ babel-plugin-check-es2015-constants@^6.22.0:
   dependencies:
   dependencies:
     babel-runtime "^6.22.0"
     babel-runtime "^6.22.0"
 
 
+babel-plugin-lodash@^3.3.2:
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.2.tgz#da3a5b49ba27447f54463f6c4fa81396ccdd463f"
+  dependencies:
+    babel-helper-module-imports "^7.0.0-beta.3"
+    babel-types "^6.26.0"
+    glob "^7.1.1"
+    lodash "^4.17.4"
+    require-package-name "^2.0.1"
+
 babel-plugin-syntax-async-functions@^6.8.0:
 babel-plugin-syntax-async-functions@^6.8.0:
   version "6.13.0"
   version "6.13.0"
   resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
   resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
@@ -897,6 +921,14 @@ babel-traverse@^6.24.1, babel-traverse@^6.26.0:
     invariant "^2.2.2"
     invariant "^2.2.2"
     lodash "^4.17.4"
     lodash "^4.17.4"
 
 
+babel-types@7.0.0-beta.3:
+  version "7.0.0-beta.3"
+  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-7.0.0-beta.3.tgz#cd927ca70e0ae8ab05f4aab83778cfb3e6eb20b4"
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.2.0"
+    to-fast-properties "^2.0.0"
+
 babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
 babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
   version "6.26.0"
   version "6.26.0"
   resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
   resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
@@ -1887,9 +1919,9 @@ dicer@0.2.5:
     readable-stream "1.1.x"
     readable-stream "1.1.x"
     streamsearch "0.1.2"
     streamsearch "0.1.2"
 
 
-diff2html@^2.3.0:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/diff2html/-/diff2html-2.3.2.tgz#1c5864266d437148bc66fdd66d4ad750102d7fed"
+diff2html@^2.3.3:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/diff2html/-/diff2html-2.3.3.tgz#31bb815881c975634c7f3907a5e789341e1560bc"
   dependencies:
   dependencies:
     diff "^3.3.1"
     diff "^3.3.1"
     hogan.js "^3.0.2"
     hogan.js "^3.0.2"
@@ -2456,6 +2488,12 @@ follow-redirects@^1.2.5:
   dependencies:
   dependencies:
     debug "^3.1.0"
     debug "^3.1.0"
 
 
+follow-redirects@^1.3.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.4.1.tgz#d8120f4518190f55aac65bb6fc7b85fcd666d6aa"
+  dependencies:
+    debug "^3.1.0"
+
 for-in@^0.1.3:
 for-in@^0.1.3:
   version "0.1.8"
   version "0.1.8"
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
@@ -3419,6 +3457,12 @@ locate-path@^2.0.0:
     p-locate "^2.0.0"
     p-locate "^2.0.0"
     path-exists "^3.0.0"
     path-exists "^3.0.0"
 
 
+lodash-webpack-plugin@^0.11.4:
+  version "0.11.4"
+  resolved "https://registry.yarnpkg.com/lodash-webpack-plugin/-/lodash-webpack-plugin-0.11.4.tgz#6c3ecba3d4b8d24b53940b63542715c5ed3c4ac5"
+  dependencies:
+    lodash "^4.17.4"
+
 lodash._arraycopy@^3.0.0:
 lodash._arraycopy@^3.0.0:
   version "3.0.0"
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1"
   resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1"
@@ -3610,6 +3654,10 @@ lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, l
   version "4.17.4"
   version "4.17.4"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
 
 
+lodash@^4.2.0:
+  version "4.17.5"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511"
+
 lolex@^1.6.0:
 lolex@^1.6.0:
   version "1.6.0"
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6"
   resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6"
@@ -4396,6 +4444,10 @@ p-try@^1.0.0:
   version "1.0.0"
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
 
 
+pako@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.3.tgz#5f515b0c6722e1982920ae8005eacb0b7ca73ccf"
+
 pako@~1.0.5:
 pako@~1.0.5:
   version "1.0.6"
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
   resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
@@ -4610,6 +4662,13 @@ pkginfo@^0.4.0:
   version "0.4.1"
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff"
   resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff"
 
 
+plantuml-encoder@^1.2.5:
+  version "1.2.5"
+  resolved "https://registry.yarnpkg.com/plantuml-encoder/-/plantuml-encoder-1.2.5.tgz#6b8e5b9e1a1dbd88b3fd9fb46f734eec7d44b548"
+  dependencies:
+    pako "1.0.3"
+    utf8-bytes "0.0.1"
+
 postcss-calc@^5.2.0:
 postcss-calc@^5.2.0:
   version "5.3.1"
   version "5.3.1"
   resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
   resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
@@ -5421,6 +5480,10 @@ require-main-filename@^1.0.1:
   version "1.0.1"
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
   resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
 
 
+require-package-name@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9"
+
 require_optional@^1.0.1:
 require_optional@^1.0.1:
   version "1.0.1"
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e"
   resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e"
@@ -6024,6 +6087,10 @@ to-fast-properties@^1.0.3:
   version "1.0.3"
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
   resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
 
 
+to-fast-properties@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+
 toastr@^2.1.2:
 toastr@^2.1.2:
   version "2.1.4"
   version "2.1.4"
   resolved "https://registry.yarnpkg.com/toastr/-/toastr-2.1.4.tgz#8b43be64fb9d0c414871446f2db8e8ca4e95f181"
   resolved "https://registry.yarnpkg.com/toastr/-/toastr-2.1.4.tgz#8b43be64fb9d0c414871446f2db8e8ca4e95f181"
@@ -6209,6 +6276,10 @@ uslug@^1.0.4:
   dependencies:
   dependencies:
     unorm ">= 1.0.0"
     unorm ">= 1.0.0"
 
 
+utf8-bytes@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/utf8-bytes/-/utf8-bytes-0.0.1.tgz#116b025448c9b500081cdfbf1f4d6c6c37d8837d"
+
 util-deprecate@~1.0.1:
 util-deprecate@~1.0.1:
   version "1.0.2"
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"