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

Merge pull request #20 from weseek/master

merge master into release
Yuki Takei 9 лет назад
Родитель
Сommit
118f7b7f3e

+ 5 - 3
CHANGES.md

@@ -4,8 +4,10 @@ CHANGES
 ## 1.0.0
 ## 1.0.0
 
 
 * Feature: Plugin mechanism
 * Feature: Plugin mechanism
+* Feature: Switchable LineBreaks ON/OFF from admin page
 * Improvement: Exclude Environment-dependency
 * Improvement: Exclude Environment-dependency
-* Support: abolish gulp
+* Improvement: Enhanced linker
+* Support: Add Dockerfile
+* Support: Abolish gulp
 * Support: LiveReload
 * Support: LiveReload
-* Support: update libs
-
+* Support: Update libs

+ 11 - 6
LICENSE

@@ -1,6 +1,6 @@
-The MIT License (MIT)
+MIT License
 
 
-Copyright (c) 2013 Sotaro KARASAWA <sotaro.k@gmail.com>
+Copyright (c) 2017 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
@@ -9,13 +9,18 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 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 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
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 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 SOFTWARE.
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+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>

+ 41 - 10
README.md

@@ -1,14 +1,18 @@
 ![Crowi](http://res.cloudinary.com/hrscywv4p/image/upload/c_limit,f_auto,h_900,q_80,w_1200/v1/199673/https_www_filepicker_io_api_file_VpYEP32ZQyCZ85u6XCXo_zskpra.png)
 ![Crowi](http://res.cloudinary.com/hrscywv4p/image/upload/c_limit,f_auto,h_900,q_80,w_1200/v1/199673/https_www_filepicker_io_api_file_VpYEP32ZQyCZ85u6XCXo_zskpra.png)
 
 
+<p align="center">
+  <a href="https://heroku.com/deploy?template=https://github.com/weseek/crowi-plus/tree/v1.0.0-RC11"><img src="https://www.herokucdn.com/deploy/button.png"></a>
+</p>
+
+
 crowi-plus
 crowi-plus
 ===========
 ===========
 
 
-[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/weseek/crowi-plus/tree/v1.0.0-RC2)
+[Chat on Slack](https://crowi-plus.slack.com/)
 
 
 [![wercker status](https://app.wercker.com/status/39cdc49d067d65c39cb35d52ceae6dc1/s/master "wercker status")](https://app.wercker.com/project/byKey/39cdc49d067d65c39cb35d52ceae6dc1)
 [![wercker status](https://app.wercker.com/status/39cdc49d067d65c39cb35d52ceae6dc1/s/master "wercker status")](https://app.wercker.com/project/byKey/39cdc49d067d65c39cb35d52ceae6dc1)
 [![dependencies status](https://david-dm.org/weseek/crowi-plus.svg)](https://david-dm.org/weseek/crowi-plus)
 [![dependencies status](https://david-dm.org/weseek/crowi-plus.svg)](https://david-dm.org/weseek/crowi-plus)
 [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
 [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
-[![Join the chat at https://gitter.im/weseek/crowi-plus](https://badges.gitter.im/weseek/crowi-plus.svg)](https://gitter.im/weseek/crowi-plus?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
 
 This is **crowi-plus** that is the fork of [Crowi](https://github.com/crowi/crowi), is [perfectly compatible with official](https://github.com/weseek/crowi-plus/wiki/Question-and-Answers#does-crowi-plus-have-compatibility-with-official-crowi), and has been enhanced with the following points:
 This is **crowi-plus** that is the fork of [Crowi](https://github.com/crowi/crowi), is [perfectly compatible with official](https://github.com/weseek/crowi-plus/wiki/Question-and-Answers#does-crowi-plus-have-compatibility-with-official-crowi), and has been enhanced with the following points:
 
 
@@ -20,7 +24,9 @@ This is **crowi-plus** that is the fork of [Crowi](https://github.com/crowi/crow
 * Secure
 * Secure
   * Upgrade jQuery to 3.x
   * Upgrade jQuery to 3.x
   * Upgrade other insecure libs
   * Upgrade other insecure libs
-* Added miscellaneous features
+* [Docker Ready](https://hub.docker.com/r/weseek/crowi-plus/)
+* [Docker Compose Ready](https://github.com/weseek/crowi-plus-docker-compose)
+* [Added miscellaneous features](https://github.com/weseek/crowi-plus/wiki/Additional-Features)
 * Developer-friendly
 * Developer-friendly
   * Less compile time
   * Less compile time
   * LiveReload separately available by server/client code change
   * LiveReload separately available by server/client code change
@@ -29,25 +35,50 @@ This is **crowi-plus** that is the fork of [Crowi](https://github.com/crowi/crow
 Quick Start for Production
 Quick Start for Production
 ===========================
 ===========================
 
 
+Using docker-compose
+---------------------
+
+```bash
+git clone https://github.com/weseek/crowi-plus-docker-compose.git crowi-plus
+cd crowi-plus
+docker-compose up
+```
+
+see also [weseek/crowi-plus-docker-compose](https://github.com/weseek/crowi-plus-docker-compose)
+
+Using Heroku
+------------
+
 (TBD)
 (TBD)
 
 
-More info are [here](https://github.com/crowi/crowi/wiki/Install-and-Configuration).
+On-premise
+----------
 
 
-Install plugins
-================
+```bash
+git clone https://github.com/weseek/crowi-plus.git
+cd crowi-plus
+yarn
+MONGO_URI=mongodb://example.com/crowi npm start
+```
+
+### Install plugins
 
 
 * Stop server if running
 * Stop server if running
 * `npm install --save` to install plugin or `yarn add`
 * `npm install --save` to install plugin or `yarn add`
   * **Don't forget `--save` option if you use npm** or crowi-plus doesn't detect plugins
   * **Don't forget `--save` option if you use npm** or crowi-plus doesn't detect plugins
 * `npm start` to build client app and start server
 * `npm start` to build client app and start server
 
 
-## Example
+#### Example
 
 
 ```bash
 ```bash
 yarn add crowi-plugin-lsx
 yarn add crowi-plugin-lsx
 npm start
 npm start
 ```
 ```
 
 
+## Other documents
+
+More info are [here](https://github.com/crowi/crowi/wiki/Install-and-Configuration).
+
 Getting Started to Develop
 Getting Started to Develop
 ==========================
 ==========================
 
 
@@ -92,7 +123,7 @@ npm run server:prod
 ```bash
 ```bash
 # development
 # development
 npm run build:dev
 npm run build:dev
-# production (jit)
+# production
 npm run build:prod
 npm run build:prod
 ```
 ```
 
 
@@ -106,8 +137,8 @@ npm run build:dev:watch
 npm test
 npm test
 ```
 ```
 
 
-Documents
-----------
+Documentation
+--------------
 
 
 * [github wiki pages](https://github.com/weseek/crowi-plus/wiki)
 * [github wiki pages](https://github.com/weseek/crowi-plus/wiki)
   * [Question and Answers](https://github.com/weseek/crowi-plus/wiki/Question-and-Answers)
   * [Question and Answers](https://github.com/weseek/crowi-plus/wiki/Question-and-Answers)

+ 9 - 0
bin/wercker/init-git.sh

@@ -0,0 +1,9 @@
+#!/bin/sh
+
+git config --global user.name "wercker"
+git config --global user.email "info@weseek.co.jp"
+
+# reconfigure origin
+GITHUB_ORIGIN=https://yuki-takei:$GITHUB_TOKEN@$WERCKER_GIT_DOMAIN/$WERCKER_GIT_OWNER/$WERCKER_GIT_REPOSITORY.git
+git remote rm origin
+git remote add origin $GITHUB_ORIGIN

+ 6 - 3
config/webpack.common.js

@@ -22,12 +22,12 @@ module.exports = function (options) {
   return {
   return {
     entry: {
     entry: {
       'app':                  './resource/js/app',
       'app':                  './resource/js/app',
-      'legacy':               './resource/js/legacy/crowi',
-      'legacy-form':          './resource/js/legacy/crowi-form',
+      'legacy':               ['./resource/js/legacy/crowi', './resource/js/legacy/crowi-form'],
       'legacy-admin':         './resource/js/legacy/crowi-admin',
       'legacy-admin':         './resource/js/legacy/crowi-admin',
       'legacy-presentation':  './resource/js/legacy/crowi-presentation',
       'legacy-presentation':  './resource/js/legacy/crowi-presentation',
       'plugin':               './resource/js/plugin',
       'plugin':               './resource/js/plugin',
       'style':                './resource/styles',
       'style':                './resource/styles',
+      'style-presentation':   './resource/styles/presentation',
     },
     },
     externals: {
     externals: {
       // require("jquery") is external and available
       // require("jquery") is external and available
@@ -84,7 +84,7 @@ module.exports = function (options) {
 
 
       new CommonsChunkPlugin({
       new CommonsChunkPlugin({
         name: 'commons',
         name: 'commons',
-        chunks: ['app', 'legacy', 'legacy-form', 'legacy-admin'],
+        chunks: ['app', 'legacy', 'legacy-admin'],
         minChunks: module => /node_modules/.test(module.resource),
         minChunks: module => /node_modules/.test(module.resource),
       }),
       }),
       new CommonsChunkPlugin({
       new CommonsChunkPlugin({
@@ -101,6 +101,9 @@ module.exports = function (options) {
         $: "jquery",
         $: "jquery",
       }),
       }),
 
 
+      // omit moment/locale/*.js
+      new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /ja/),
+
     ]
     ]
   };
   };
 }
 }

+ 1 - 1
config/webpack.dev.js

@@ -59,7 +59,7 @@ module.exports = function (options) {
             'react-dom'
             'react-dom'
           ],
           ],
         },
         },
-        dllDir: helpers.root('public/js/dll'),
+        dllDir: helpers.root('public/dll'),
         webpackConfig: webpackMergeDll(commonConfig({env: ENV}), {
         webpackConfig: webpackMergeDll(commonConfig({env: ENV}), {
           devtool: 'cheap-module-source-map',
           devtool: 'cheap-module-source-map',
           plugins: [],
           plugins: [],

+ 7 - 0
config/webpack.prod.js

@@ -3,6 +3,7 @@
  */
  */
 
 
 const helpers = require('./helpers');
 const helpers = require('./helpers');
+const webpack = require('webpack');
 const webpackMerge = require('webpack-merge'); // used to merge webpack configs
 const webpackMerge = require('webpack-merge'); // used to merge webpack configs
 const commonConfig = require('./webpack.common.js'); // the settings that are common to prod and dev
 const commonConfig = require('./webpack.common.js'); // the settings that are common to prod and dev
 
 
@@ -36,6 +37,12 @@ module.exports = function (env) {
     },
     },
     plugins: [
     plugins: [
 
 
+      new webpack.DefinePlugin({
+        'process.env': {
+          NODE_ENV: JSON.stringify(ENV),
+        }
+      }),
+
       new OptimizeJsPlugin({
       new OptimizeJsPlugin({
         sourceMap: false
         sourceMap: false
       }),
       }),

+ 2 - 1
lib/crowi/index.js

@@ -337,7 +337,8 @@ Crowi.prototype.buildServer = function() {
   require('./express-init')(this, app);
   require('./express-init')(this, app);
 
 
   // import plugins
   // import plugins
-  var isEnabledPlugins = this.config.crowi['plugin:isEnabledPlugins'] || false;
+  var Config = this.model('Config');
+  var isEnabledPlugins = Config.isEnabledPlugins(this.config);
   if (isEnabledPlugins) {
   if (isEnabledPlugins) {
     debug('plugins enabled');
     debug('plugins enabled');
     require('../plugins')(this, app);
     require('../plugins')(this, app);

+ 14 - 0
lib/models/config.js

@@ -194,10 +194,23 @@ module.exports = function(crowi) {
     return method != 'none';
     return method != 'none';
   };
   };
 
 
+  configSchema.statics.isEnabledPlugins = function(config)
+  {
+    var defaultValue = getArrayForInstalling()['plugin:isEnabledPlugins'];
+
+    // return defaultValue if undefined
+    if (undefined === config.crowi || undefined === config.crowi['plugin:isEnabledPlugins']) {
+      return defaultValue;
+    }
+
+    return config.crowi['plugin:isEnabledPlugins'];
+  };
+
   configSchema.statics.isEnabledLinebreaks = function(config)
   configSchema.statics.isEnabledLinebreaks = function(config)
   {
   {
     var defaultValue = getDefaultMarkdownConfigs()['markdown:isEnabledLinebreaks'];
     var defaultValue = getDefaultMarkdownConfigs()['markdown:isEnabledLinebreaks'];
 
 
+    // return defaultValue if undefined
     if (undefined === config.markdown || undefined === config.markdown['markdown:isEnabledLinebreaks']) {
     if (undefined === config.markdown || undefined === config.markdown['markdown:isEnabledLinebreaks']) {
       return defaultValue;
       return defaultValue;
     }
     }
@@ -209,6 +222,7 @@ module.exports = function(crowi) {
   {
   {
     var defaultValue = getDefaultMarkdownConfigs()['markdown:isEnabledLinebreaksInComments'];
     var defaultValue = getDefaultMarkdownConfigs()['markdown:isEnabledLinebreaksInComments'];
 
 
+    // return defaultValue if undefined
     if (undefined === config.markdown || undefined === config.markdown['markdown:isEnabledLinebreaksInComments']) {
     if (undefined === config.markdown || undefined === config.markdown['markdown:isEnabledLinebreaksInComments']) {
       return defaultValue;
       return defaultValue;
     }
     }

+ 28 - 6
lib/plugins/plugin-utils.js

@@ -31,14 +31,19 @@ class PluginUtils {
   }
   }
 
 
   /**
   /**
-   * list plugin module names that starts with 'crowi-plugin-'
+   * list plugin module objects that starts with 'crowi-plugin-'
    * borrowing from: https://github.com/hexojs/hexo/blob/d1db459c92a4765620343b95789361cbbc6414c5/lib/hexo/load_plugins.js#L17
    * borrowing from: https://github.com/hexojs/hexo/blob/d1db459c92a4765620343b95789361cbbc6414c5/lib/hexo/load_plugins.js#L17
    *
    *
-   * @returns
+   * @returns array of objects
+   *   [
+   *     { name: 'crowi-plugin-...', version: '1.0.0' },
+   *     { name: 'crowi-plugin-...', version: '1.0.0' },
+   *     ...
+   *   ]
    *
    *
    * @memberOf PluginService
    * @memberOf PluginService
    */
    */
-  listPluginNames(rootDir) {
+  listPlugins(rootDir) {
     var packagePath = path.join(rootDir, 'package.json');
     var packagePath = path.join(rootDir, 'package.json');
 
 
     // Make sure package.json exists
     // Make sure package.json exists
@@ -50,10 +55,27 @@ class PluginUtils {
     const content = fs.readFileSync(packagePath);
     const content = fs.readFileSync(packagePath);
     const json = JSON.parse(content);
     const json = JSON.parse(content);
     const deps = json.dependencies || {};
     const deps = json.dependencies || {};
-    return Object.keys(deps).filter((name) => {
-      // Ignore plugins whose name is not started with "crowi-"
-      return /^crowi-plugin-/.test(name);
+
+    let objs = {};
+    Object.keys(deps).forEach((name) => {
+      if (/^crowi-plugin-/.test(name)) {
+        objs[name] = deps[name];
+      }
     });
     });
+
+    return objs;
+  }
+
+  /**
+   * list plugin module names that starts with 'crowi-plugin-'
+   *
+   * @returns array of plugin names
+   *
+   * @memberOf PluginService
+   */
+  listPluginNames(rootDir) {
+    const plugins = this.listPlugins(rootDir);
+    return Object.keys(plugins);
   }
   }
 }
 }
 
 

+ 3 - 0
lib/routes/admin.js

@@ -6,6 +6,8 @@ module.exports = function(crowi, app) {
     , Page = models.Page
     , Page = models.Page
     , User = models.User
     , User = models.User
     , Config = models.Config
     , Config = models.Config
+    , PluginUtils = require('../plugins/plugin-utils')
+    , pluginUtils = new PluginUtils()
     , ApiResponse = require('../util/apiResponse')
     , ApiResponse = require('../util/apiResponse')
 
 
     , MAX_PAGE_LIST = 5
     , MAX_PAGE_LIST = 5
@@ -77,6 +79,7 @@ module.exports = function(crowi, app) {
 
 
     return res.render('admin/app', {
     return res.render('admin/app', {
       settingForm: settingForm,
       settingForm: settingForm,
+      plugins: pluginUtils.listPlugins(crowi.rootDir),
     });
     });
   };
   };
 
 

+ 15 - 12
lib/util/middlewares.js

@@ -40,6 +40,7 @@ exports.csrfVerify = function(crowi, app) {
     }
     }
 
 
     if (crowi.getTokens().verify(csrfKey, token)) {
     if (crowi.getTokens().verify(csrfKey, token)) {
+      debug('csrf successfully verified');
       return next();
       return next();
     }
     }
 
 
@@ -190,23 +191,25 @@ exports.loginRequired = function(crowi, app) {
 exports.accessTokenParser = function(crowi, app) {
 exports.accessTokenParser = function(crowi, app) {
   return function(req, res, next) {
   return function(req, res, next) {
     var accessToken = req.query.access_token || req.body.access_token || req.get('Authorization') || null;
     var accessToken = req.query.access_token || req.body.access_token || req.get('Authorization') || null;
+
+    debug(`accessToken=${accessToken}`);
+
     if (!accessToken) {
     if (!accessToken) {
       return next();
       return next();
     }
     }
 
 
-    var User = crowi.model('User')
-
-    debug('accessToken is', accessToken);
+    var User = crowi.model('User');
     User.findUserByApiToken(accessToken)
     User.findUserByApiToken(accessToken)
-    .then(function(userData) {
-      req.user = userData;
-      req.skipCsrfVerify = true;
-      debug('Access token parsed: skipCsrfVerify');
-
-      next();
-    }).catch(function(err) {
-      next();
-    });
+      .then((userData) => {
+        if (userData !== null) {
+          req.user = userData;
+          req.skipCsrfVerify = true;
+          debug('Access token parsed: skipCsrfVerify');
+        }
+        next();
+      }).catch(function(err) {
+        next();
+      });
   };
   };
 };
 };
 
 

+ 5 - 0
lib/util/swigFunctions.js

@@ -22,6 +22,11 @@ module.exports = function(crowi, app, req, locals) {
     return false;
     return false;
   };
   };
 
 
+  locals.isEnabledPlugins = function() {
+    var config = crowi.getConfig()
+    return Config.isEnabledPlugins(config);
+  }
+
   locals.isEnabledLinebreaks = function() {
   locals.isEnabledLinebreaks = function() {
     var config = crowi.getConfig()
     var config = crowi.getConfig()
     return Config.isEnabledLinebreaks(config);
     return Config.isEnabledLinebreaks(config);

+ 0 - 1
lib/views/_form.html

@@ -61,4 +61,3 @@
   <div class="file-module hidden">
   <div class="file-module hidden">
   </div>
   </div>
 </div>
 </div>
-<script src="{{ webpack_asset('legacy-form').js }}" defer></script>

+ 20 - 0
lib/views/admin/app.html

@@ -268,6 +268,26 @@
       </fieldset>
       </fieldset>
       </form>
       </form>
 
 
+      <h4>インストールされているプラグイン一覧</h4>
+      <table class="table table-bordered">
+        <th class="text-center">
+          パッケージ名
+        </th>
+        <th class="text-center">
+          指定バージョン
+        </th>
+        <th class="text-center">
+          インストールされているバージョン
+        </th>
+        {% for pluginName in Object.keys(plugins) %}
+        <tr>
+          <td>{{ pluginName }}</td>
+          <td class="text-center">{{ plugins[pluginName] }}</td>
+          <td class="text-center">(TBD)</td>
+        </tr>
+        {% endfor %}
+      </table>
+
     </div>
     </div>
   </div>
   </div>
 
 

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

@@ -26,13 +26,13 @@
   <script src="//cdn.jsdelivr.net/jquery/3.2.1/jquery.min.js"></script>
   <script src="//cdn.jsdelivr.net/jquery/3.2.1/jquery.min.js"></script>
 
 
   {% if env === 'development' %}
   {% if env === 'development' %}
-    <script src="/js/dll/vendor.dll.js"></script>
+    <script src="/dll/vendor.dll.js"></script>
     <script src="{{ webpack_asset('dev').js }}" async></script>
     <script src="{{ webpack_asset('dev').js }}" async></script>
   {% endif %}
   {% endif %}
 
 
   <script src="{{ webpack_asset('style').js }}"></script>
   <script src="{{ webpack_asset('style').js }}"></script>
   <script src="{{ webpack_asset('commons').js }}" defer></script>
   <script src="{{ webpack_asset('commons').js }}" defer></script>
-  {% if config.crowi['plugin:isEnabledPlugins'] %}
+  {% if isEnabledPlugins() %}
     <script src="{{ webpack_asset('plugin').js }}" defer></script>
     <script src="{{ webpack_asset('plugin').js }}" defer></script>
   {% endif %}
   {% endif %}
   <script src="{{ webpack_asset('legacy').js }}" defer></script>
   <script src="{{ webpack_asset('legacy').js }}" defer></script>
@@ -51,7 +51,7 @@
 <body
 <body
   class="crowi main-container {% block html_base_css %}{% endblock %}"
   class="crowi main-container {% block html_base_css %}{% endblock %}"
   data-me="{{ user._id.toString() }}"
   data-me="{{ user._id.toString() }}"
-  data-plugin-enabled="{{ config.crowi['plugin:isEnabledPlugins'] }}"
+  data-plugin-enabled="{{ isEnabledPlugins() }}"
  {% block html_base_attr %}{% endblock %}
  {% block html_base_attr %}{% endblock %}
  >
  >
 
 

+ 0 - 2
lib/views/modal/create_page.html

@@ -27,7 +27,6 @@
         </form>
         </form>
         <hr>
         <hr>
 
 
-        {% if !isTopPage() %}
         <form class="form-horizontal" id="create-page-under-tree" role="form">
         <form class="form-horizontal" id="create-page-under-tree" role="form">
           <fieldset>
           <fieldset>
             <div class="col-xs-12">
             <div class="col-xs-12">
@@ -42,7 +41,6 @@
           </fieldset>
           </fieldset>
         </form>
         </form>
         <hr>
         <hr>
-        {% endif  %}
 
 
       </div><!-- /.modal-body -->
       </div><!-- /.modal-body -->
 
 

+ 7 - 7
lib/views/page_presentation.html

@@ -6,18 +6,18 @@
     <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">
 
 
-
-    <link rel="stylesheet" type="text/css" href="/css/crowi-reveal{% if env  == 'production' %}.min{% endif %}.css">
-    <link rel="stylesheet" type="text/css" href="/js/reveal/lib/css/zenburn.css">
+    <!-- jQuery -->
+    <script src="//cdn.jsdelivr.net/jquery/3.2.1/jquery.min.js"></script>
 
 
     {% if env === 'development' %}
     {% if env === 'development' %}
-      <script src="{{ webpack_asset('style').js }}"></script>
-      <!--<script src="{{ webpack_asset('dev').js }}" async></script>-->
-      <script src="/js/dll/vendor.dll.js" defer></script>
+      <script src="/dll/vendor.dll.js"></script>
+      <script src="{{ webpack_asset('dev').js }}" async></script>
     {% endif %}
     {% endif %}
 
 
+    <script src="{{ webpack_asset('style').js }}"></script>
+    <script src="{{ webpack_asset('style-presentation').js }}"></script>
     <script src="{{ webpack_asset('commons').js }}" defer></script>
     <script src="{{ webpack_asset('commons').js }}" defer></script>
-    <script src="{{ webpack_asset('presentation').js }}" defer></script>
+    <script src="{{ webpack_asset('legacy-presentation').js }}" defer></script>
 
 
     <title>{{ path|path2name }} | {{ path }}</title>
     <title>{{ path|path2name }} | {{ path }}</title>
   </head>
   </head>

+ 1 - 1
lib/views/user_page.html

@@ -10,7 +10,7 @@
   <h1 class="title" id="revision-path">{{ path|insertSpaceToEachSlashes }}</h1>
   <h1 class="title" id="revision-path">{{ path|insertSpaceToEachSlashes }}</h1>
   <div class="user-page-header">
   <div class="user-page-header">
   {% if page %}
   {% if page %}
-    <a href="#" title="Bookmark" class="bookmark-link" id="bookmark-button" data-bookmarked="0"><i class="fa fa-star-o"></i></a>
+    <a href="#" title="Bookmark" class="bookmark-link" id="bookmark-button" data-csrftoken="{{ csrf() }}" data-bookmarked="0"><i class="fa fa-star-o"></i></a>
   {% endif %}
   {% endif %}
     <div class="pull-left user-page-picture">
     <div class="pull-left user-page-picture">
       <img src="{{ pageUser|picture }}" class="picture picture-rounded">
       <img src="{{ pageUser|picture }}" class="picture picture-rounded">

+ 14 - 10
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "crowi-plus",
   "name": "crowi-plus",
-  "version": "1.0.0-RC3",
+  "version": "1.0.0-RC11",
   "description": "Enhanced Crowi",
   "description": "Enhanced Crowi",
   "tags": [
   "tags": [
     "wiki",
     "wiki",
@@ -20,19 +20,22 @@
   },
   },
   "scripts": {
   "scripts": {
     "build:dev:watch": "npm run build:dev -- --watch",
     "build:dev:watch": "npm run build:dev -- --watch",
-    "build:dev": "npm run clean:public && webpack --config config/webpack.dev.js  --progress --profile",
-    "build:prod": "npm run clean:public && webpack --config config/webpack.prod.js  --progress --profile --bail",
+    "build:dev": "npm run clean:js && webpack --config config/webpack.dev.js  --progress --profile",
+    "build:prod": "npm run clean && webpack --config config/webpack.prod.js  --progress --profile --bail",
     "build": "npm run build:dev",
     "build": "npm run build:dev",
-    "clean:public": "rimraf -- public/js",
-    "clean:dll": "rimraf -- dll",
-    "clean": "npm cache clean && npm run rimraf -- public/js dll",
-    "generate-plugin-definitions-source": "mkdirp tmp/plugins && node bin/generate-plugin-definitions-source.js",
-    "prebuild:dev": "npm run generate-plugin-definitions-source",
-    "prebuild:prod": "npm run generate-plugin-definitions-source",
+    "clean:js": "rimraf -- public/js",
+    "clean:dll": "rimraf -- public/dll",
+    "clean": "npm run clean:js && npm run clean:dll",
+    "mkdirp": "mkdirp",
+    "plugin:def": "node bin/generate-plugin-definitions-source.js",
+    "prebuild:dev": "npm run plugin:def",
+    "prebuild:prod": "npm run plugin:def",
     "prestart": "npm run build:prod",
     "prestart": "npm run build:prod",
     "server:dev:watch": "node-dev app.js --watch",
     "server:dev:watch": "node-dev app.js --watch",
     "server:dev": "node app.js",
     "server:dev": "node app.js",
-    "server:prod": "node app.js --production",
+    "server:prod:container": "node app.js --production --container",
+    "server:prod:onpremise": "mkdirp logs && node app.js --production --onpremise",
+    "server:prod": "npm run server:prod:onpremise",
     "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 -r test/bootstrap.js test/**/*.js",
@@ -72,6 +75,7 @@
     "express-form": "~0.12.0",
     "express-form": "~0.12.0",
     "express-session": "~1.15.0",
     "express-session": "~1.15.0",
     "express-webpack-assets": "0.0.2",
     "express-webpack-assets": "0.0.2",
+    "file-loader": "^0.11.1",
     "googleapis": "=12.3.0",
     "googleapis": "=12.3.0",
     "graceful-fs": "^4.1.11",
     "graceful-fs": "^4.1.11",
     "highlight.js": "^9.10.0",
     "highlight.js": "^9.10.0",

+ 0 - 3
resource/css/crowi-reveal.scss

@@ -1,6 +1,3 @@
-@import 'reveal.scss';
-@import 'theme/source/black';
-
 .reveal {
 .reveal {
   font-size: 32px;
   font-size: 32px;
   section * {
   section * {

+ 14 - 7
resource/css/crowi.scss

@@ -6,16 +6,16 @@ $bootstrap-sass-asset-helper: true;
 @import "~bootstrap-sass/assets/stylesheets/bootstrap";
 @import "~bootstrap-sass/assets/stylesheets/bootstrap";
 
 
 // crowi component
 // crowi component
-@import 'layout';
-@import 'page';
-@import 'page_list';
-@import 'form';
-@import 'wiki';
 @import 'admin';
 @import 'admin';
 @import 'comment';
 @import 'comment';
-@import 'user';
+@import 'form';
+@import 'layout';
+@import 'page_list';
+@import 'page';
 @import 'portal';
 @import 'portal';
 @import 'search';
 @import 'search';
+@import 'user';
+@import 'wiki';
 
 
 
 
 ul {
 ul {
@@ -102,6 +102,13 @@ footer {
 }
 }
 
 
 .modal.create-page {
 .modal.create-page {
+
+  @media (min-width: 768px) {
+    .modal-dialog {
+      width: 750px;
+    }
+  }
+
   .modal-body {
   .modal-body {
     h3, h4 {
     h3, h4 {
       margin-bottom: 10px;
       margin-bottom: 10px;
@@ -142,7 +149,7 @@ footer {
         display: inline-block;
         display: inline-block;
       }
       }
       .page-today-input2 {
       .page-today-input2 {
-        width: 100%;
+        // width: 100%;
         display: inline-block;
         display: inline-block;
       }
       }
     }
     }

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

@@ -1,4 +1,3 @@
-$(function() {
   var pageId = $('#content-main').data('page-id');
   var pageId = $('#content-main').data('page-id');
   var pagePath= $('#content-main').data('path');
   var pagePath= $('#content-main').data('path');
   var isEnabledLineBreaks = $('#content-main').data('linebreaks-enabled');
   var isEnabledLineBreaks = $('#content-main').data('linebreaks-enabled');
@@ -56,6 +55,10 @@ $(function() {
     $('.content-main').removeClass('on-edit');
     $('.content-main').removeClass('on-edit');
   });
   });
 
 
+/**
+ * DOM ready
+ */
+$(function() {
   // preview watch
   // preview watch
   var originalContent = $('#form-body').val();
   var originalContent = $('#form-body').val();
 
 

+ 19 - 8
resource/js/legacy/crowi-presentation.js

@@ -1,5 +1,7 @@
 var Reveal = require('reveal.js');
 var Reveal = require('reveal.js');
 
 
+require("reveal.js/css/reveal.css");
+require("reveal.js/css/theme/black.css");
 require('reveal.js/lib/js/head.min.js');
 require('reveal.js/lib/js/head.min.js');
 require('reveal.js/lib/js/html5shiv.js');
 require('reveal.js/lib/js/html5shiv.js');
 
 
@@ -16,16 +18,25 @@ Reveal.initialize({
   transition: 'slide',
   transition: 'slide',
 
 
   // Optional libraries used to extend on reveal.js
   // Optional libraries used to extend on reveal.js
-  dependencies: [
-    { src: '/js/reveal/lib/js/classList.js', condition: function() { return !document.body.classList; } },
-    { src: '/js/reveal/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
-    { src: '/js/reveal/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
-    { src: '/js/reveal/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
-    { src: '/js/reveal/plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
-    { src: '/js/reveal/plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
-  ]
+  // dependencies: [
+  //   { src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
+  //   { src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
+  //   { src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
+  //   { src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
+  //   { src: 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
+  //   { src: 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
+  // ]
 });
 });
 
 
+require.ensure([], () => {
+  require('reveal.js/lib/js/classList.js');
+  require('reveal.js/plugin/markdown/marked.js');
+  require('reveal.js/plugin/markdown/markdown.js');
+  require('reveal.js/plugin/highlight/highlight.js');
+  require('reveal.js/plugin/zoom-js/zoom.js');
+  require('reveal.js/plugin/notes/notes.js');
+})
+
 Reveal.addEventListener('ready', function(event) {
 Reveal.addEventListener('ready', function(event) {
   // event.currentSlide, event.indexh, event.indexv
   // event.currentSlide, event.indexh, event.indexv
   $('.reveal section').each(function(e) {
   $('.reveal section').each(function(e) {

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

@@ -223,7 +223,7 @@ $(function() {
 
 
   $('#create-page').on('shown.bs.modal', function (e) {
   $('#create-page').on('shown.bs.modal', function (e) {
 
 
-    var input2Width = $('#create-page-today .col-xs-10').outerWidth();
+    var input2Width = $('#create-page-today .col-xs-10').outerWidth() - 1;
     var newWidth = input2Width
     var newWidth = input2Width
       - $('#create-page-today .page-today-prefix').outerWidth()
       - $('#create-page-today .page-today-prefix').outerWidth()
       - $('#create-page-today .page-today-input1').outerWidth()
       - $('#create-page-today .page-today-input1').outerWidth()
@@ -749,7 +749,7 @@ $(function() {
 
 
     //
     //
     var me = $('body').data('me');
     var me = $('body').data('me');
-    var socket = io('localhost', {forceNew: true});
+    var socket = io();
     socket.on('page edited', function (data) {
     socket.on('page edited', function (data) {
       if (data.user._id != me
       if (data.user._id != me
         && data.page.path == pagePath) {
         && data.page.path == pagePath) {

+ 4 - 3
resource/js/util/PreProcessor/Linker.js

@@ -4,10 +4,11 @@ export default class Linker {
 
 
     return markdown
     return markdown
       // process angle branckets like '</Level1/Level2>'
       // process angle branckets like '</Level1/Level2>'
-      .replace(/<((\/[^>]+?){2,})>/g, '<a href="$1">$1</a>') // ページ間リンク: <> でかこまれてて / から始まり、 / が2個以上
+      // see: https://regex101.com/r/rxAy4F/2
+      .replace(/<((\/[^>\n]+?){2,})>/g, '<a href="$1">$1</a>') // ページ間リンク: <> でかこまれてて / から始まり、 / が2個以上
       // process square branckets like '[/Level1]'
       // process square branckets like '[/Level1]'
-      // see: https://regex101.com/r/QSt1yu/3
-      .replace(/\[(\/[^\]]+?)\](?!\()/g, '<a href="$1">$1</a>')
+      // see: https://regex101.com/r/QSt1yu/5
+      .replace(/\[(\/[^\]\n]+?)\](?!\()/g, '<a href="$1">$1</a>')
       ;
       ;
   }
   }
 }
 }

+ 1 - 0
resource/styles/presentation.js

@@ -0,0 +1 @@
+import '../css/crowi-reveal.scss';

+ 1 - 0
tmp/plugins/.gitignore

@@ -0,0 +1 @@
+*

+ 33 - 35
wercker.yml

@@ -72,57 +72,55 @@ build-dev:
         npm run build:dev
         npm run build:dev
 
 
 
 
-prepare-to-release: # would be run on release branch
+release: # would be run on release branch
   steps:
   steps:
     - script:
     - script:
       name: bump version
       name: bump version
       code: |
       code: |
-        git config --global user.name "wercker"
-        git config --global user.email "info@weseek.co.jp"
+        sh ./bin/wercker/init-git.sh
         # npm version to bump version
         # npm version to bump version
         npm version patch
         npm version patch
-        # export $RELEASE_VERSION
-        export RELEASE_VERSION=`npm run version --silent`
-        echo "export RELEASE_VERSION=$RELEASE_VERSION"
+        # get version
+        RELEASE_VERSION=`npm run version --silent`
+        echo "RELEASE_VERSION=$RELEASE_VERSION"
 
 
     - script:
     - script:
-      name: push to github to create new branch
+      name: commit and push
       code: |
       code: |
-        # reconfigure origin
-        GITHUB_ORIGIN=https://yuki-takei:$GITHUB_TOKEN@$WERCKER_GIT_DOMAIN/$WERCKER_GIT_OWNER/$WERCKER_GIT_REPOSITORY.git
-        git remote set-url origin $GITHUB_ORIGIN
-        git checkout -B tmp/release-$RELEASE_VERSION
-        git push -u origin HEAD:tmp/release-$RELEASE_VERSION
-
-
-release-to-github: # would be run on temporary release branch
-  steps:
-    - script:
-      name: get version
-      code: |
-        export RELEASE_VERSION=`npm run version --silent`
-        echo "export RELEASE_VERSION=$RELEASE_VERSION"
+        TMP_RELEASE_BRANCH=tmp/release-$RELEASE_VERSION
+        git checkout -B $TMP_RELEASE_BRANCH
+        git push -u origin HEAD:$TMP_RELEASE_BRANCH
+        TARGET_COMMITISH=`git rev-parse HEAD`
 
 
     - github-create-release:
     - github-create-release:
       token: $GITHUB_TOKEN
       token: $GITHUB_TOKEN
       tag: v$RELEASE_VERSION
       tag: v$RELEASE_VERSION
+      target-commitish: $TARGET_COMMITISH
 
 
     - script:
     - script:
       name: remove temporary release branch
       name: remove temporary release branch
       code: |
       code: |
-        git config --global user.name "wercker"
-        git config --global user.email "info@weseek.co.jp"
-        # reconfigure origin
-        GITHUB_ORIGIN=https://yuki-takei:$GITHUB_TOKEN@$WERCKER_GIT_DOMAIN/$WERCKER_GIT_OWNER/$WERCKER_GIT_REPOSITORY.git
-        git remote rm origin
-        git remote add origin $GITHUB_ORIGIN
-        # remove branch
-        git push --delete origin $WERCKER_GIT_BRANCH
-
-
-# the pipeline that do nothing
-#  this is needed while wercker can't detect specified branch pushed
-empty:
+        git push --delete origin $TMP_RELEASE_BRANCH
+
+
+trigger-crowi-plus-docker:
   steps:
   steps:
     - script:
     - script:
-      code: echo "this is $WERCKER_GIT_BRANCH branch"
+      name: trigger crowi-plus-docker release pipeline
+      code: |-  # strip linebreak
+        curl -X POST
+          -H "Content-Type: application/json"
+          -H "Authorization: Bearer $WERCKER_TOKEN"
+          https://app.wercker.com/api/v3/runs
+          -d
+            '{
+              "pipelineId": "$TARGET_PIPELINE_ID",
+              "sourceRunId": "$WERCKER_RUN_ID",
+              "branch": "release",
+              "envVars": [
+                {
+                  "key": "RELEASE_VERSION",
+                  "value": "$RELEASE_VERSION"
+                }
+              ]
+            }'

+ 6 - 0
yarn.lock

@@ -2172,6 +2172,12 @@ feature-detect-es6@^1.2.0:
   dependencies:
   dependencies:
     array-back "^1.0.3"
     array-back "^1.0.3"
 
 
+file-loader@^0.11.1:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.1.tgz#6b328ee1234a729e4e47d36375dd6d35c0e1db84"
+  dependencies:
+    loader-utils "^1.0.2"
+
 filename-regex@^2.0.0:
 filename-regex@^2.0.0:
   version "2.0.0"
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
   resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"