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

Merge pull request #27 from weseek/rc/1.0.x

merge rc/1.0.x into release
Yuki Takei 9 лет назад
Родитель
Сommit
b3601719e1

+ 2 - 2
README.md

@@ -1,7 +1,7 @@
 ![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>
+  <a href="https://heroku.com/deploy?template=https://github.com/weseek/crowi-plus/tree/v1.0.1"><img src="https://www.herokucdn.com/deploy/button.png"></a>
 </p>
 
 
@@ -141,7 +141,7 @@ Documentation
 --------------
 
 * [github wiki pages](https://github.com/weseek/crowi-plus/wiki)
-  * [Question and Answers](https://github.com/weseek/crowi-plus/wiki/Question-and-Answers)
+  * [Questions and Answers](https://github.com/weseek/crowi-plus/wiki/Questions-and-Answers)
 
 
 License

+ 4 - 20
bin/wercker/trigger-crowi-plus-docker.sh

@@ -10,19 +10,6 @@
 #   - $CROWI_PLUS_DOCKER_PIPELINE_ID
 #   - $RELEASE_VERSION
 #
-DATA=`echo '{ \
-    "pipelineId": "'$CROWI_PLUS_DOCKER_PIPELINE_ID'", \
-    "branch": "release", \
-    "envVars": [ \
-      { \
-        "key": "RELEASE_VERSION", \
-        "value": "'$RELEASE_VERSION'" \
-      } \
-    ] \
-  }' \
-`
-echo $DATA
-
 RESPONSE=`curl -X POST \
   -H "Content-Type: application/json" \
   -H "Authorization: Bearer $WERCKER_TOKEN" \
@@ -40,12 +27,9 @@ RESPONSE=`curl -X POST \
 
 echo $RESPONSE | jq .
 
-# get http status code
-STATUS_CODE=`echo $RESPONSE | jq .statusCode`
-
-# exit
-if [ "$STATUS_CODE" = 200 ]; then
-  exit 0
-else
+# get wercker run id
+RUN_ID=`echo $RESPONSE | jq .id`
+# exit with failure status
+if [ "$RUN_ID" = "null" ]; then
   exit 1
 fi

+ 3 - 2
config/webpack.common.js

@@ -22,7 +22,8 @@ module.exports = function (options) {
   return {
     entry: {
       'app':                  './resource/js/app',
-      'legacy':               ['./resource/js/legacy/crowi', './resource/js/legacy/crowi-form'],
+      'legacy':               './resource/js/legacy/crowi',
+      'legacy-form':          './resource/js/legacy/crowi-form',
       'legacy-admin':         './resource/js/legacy/crowi-admin',
       'legacy-presentation':  './resource/js/legacy/crowi-presentation',
       'plugin':               './resource/js/plugin',
@@ -84,7 +85,7 @@ module.exports = function (options) {
 
       new CommonsChunkPlugin({
         name: 'commons',
-        chunks: ['app', 'legacy', 'legacy-admin'],
+        chunks: ['app', 'legacy', 'legacy-form', 'legacy-admin'],
         minChunks: module => /node_modules/.test(module.resource),
       }),
       new CommonsChunkPlugin({

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

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

+ 1 - 0
lib/form/index.js

@@ -17,6 +17,7 @@ module.exports = {
     google: require('./admin/google'),
     plugin: require('./admin/plugin'),
     markdown: require('./admin/markdown'),
+    customcss: require('./admin/customcss'),
     userInvite: require('./admin/userInvite'),
     slackSetting: require('./admin/slackSetting'),
   },

+ 23 - 0
lib/models/config.js

@@ -1,6 +1,7 @@
 module.exports = function(crowi) {
   var mongoose = require('mongoose')
     , debug = require('debug')('crowi:models:config')
+    , uglifycss = require('uglifycss')
     , ObjectId = mongoose.Schema.Types.ObjectId
     , configSchema
     , Config
@@ -44,6 +45,7 @@ module.exports = function(crowi) {
 
       'plugin:isEnabledPlugins' : true,
 
+      'customize:css' : '',
     };
   }
 
@@ -76,6 +78,9 @@ module.exports = function(crowi) {
 
     originalConfig[ns] = newNSConfig;
     crowi.setConfig(originalConfig);
+
+    // uglify and store
+    Config.generateUglifiedCustomCss(originalConfig);
   };
 
   // Execute only once for installing application
@@ -175,6 +180,10 @@ module.exports = function(crowi) {
         });
 
         debug('Config loaded', config);
+
+        // uglify and store
+        Config.generateUglifiedCustomCss(config);
+
         return callback(null, config);
       });
   };
@@ -230,6 +239,20 @@ module.exports = function(crowi) {
     return config.markdown['markdown:isEnabledLinebreaksInComments'];
   };
 
+  /**
+   * uglify store custom css strings
+   */
+  configSchema.statics.generateUglifiedCustomCss = function(config)
+  {
+    var rawCss = config.crowi['customize:css'] || getArrayForInstalling()['customize:css'];
+    this.uglifiedCustomCss = uglifycss.processString(rawCss);
+  }
+
+  configSchema.statics.customCss = function(config)
+  {
+    return this.uglifiedCustomCss;
+  }
+
   configSchema.statics.hasSlackConfig = function(config)
   {
     if (!config.notification) {

+ 22 - 0
lib/routes/admin.js

@@ -114,6 +114,17 @@ module.exports = function(crowi, app) {
     }
   };
 
+  // app.get('/admin/customize' , admin.customize.index);
+  actions.customize = {};
+  actions.customize.index = function(req, res) {
+    var settingForm;
+    settingForm = Config.setupCofigFormData('crowi', req.config);
+
+    return res.render('admin/customize', {
+      settingForm: settingForm,
+    });
+  };
+
   // app.get('/admin/notification'               , admin.notification.index);
   actions.notification = {};
   actions.notification.index = function(req, res) {
@@ -408,6 +419,17 @@ module.exports = function(crowi, app) {
     }
   };
 
+  actions.api.customizeSetting = function(req, res) {
+    var form = req.form.settingForm;
+
+    if (req.form.isValid) {
+      debug('form content', form);
+      return saveSetting(req, res, form);
+    } else {
+      return res.json({status: false, message: req.form.errors.join('\n')});
+    }
+  }
+
   // app.post('/_api/admin/notifications.add'    , admin.api.notificationAdd);
   actions.api.notificationAdd = function(req, res) {
     var UpdatePost = crowi.model('UpdatePost');

+ 4 - 0
lib/routes/index.js

@@ -51,6 +51,10 @@ module.exports = function(crowi, app) {
   app.get('/admin/markdown'                   , loginRequired(crowi, app) , middleware.adminRequired() , admin.markdown.index);
   app.post('/admin/markdown/lineBreaksSetting', loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.markdown, admin.markdown.lineBreaksSetting);
 
+  // markdown admin
+  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);
+
   // search admin
   app.get('/admin/search'              , loginRequired(crowi, app) , middleware.adminRequired() , admin.search.index);
   app.post('/admin/search/build'       , loginRequired(crowi, app) , middleware.adminRequired() , csrf, admin.search.buildIndex);

+ 4 - 0
lib/util/swigFunctions.js

@@ -37,6 +37,10 @@ module.exports = function(crowi, app, req, locals) {
     return Config.isEnabledLinebreaksInComments(config);
   }
 
+  locals.customCss = function() {
+    return Config.customCss();
+  }
+
   locals.slackConfigured = function() {
     var config = crowi.getConfig()
     if (Config.hasSlackToken(config)) {

+ 5 - 0
lib/views/_form.html

@@ -1,3 +1,8 @@
+{% block html_head_loading_legacy %}
+  <script src="{{ webpack_asset('legacy-form').js }}" defer></script>
+  {% parent %}
+{% endblock %}
+
 {% if req.form.errors %}
 <div class="alert alert-danger">
   <ul>

+ 161 - 0
lib/views/admin/customize.html

@@ -0,0 +1,161 @@
+{% extends '../layout/admin.html' %}
+
+{% block html_title %}カスタマイズ · {% endblock %}
+
+{% block html_additional_headers %}
+  <!-- CodeMirror -->
+  <link rel="stylesheet" href="https://cdn.jsdelivr.net/g/codemirror@4.5.0(codemirror.css+addon/hint/show-hint.css)">
+  <link rel="stylesheet" href="https://cdn.jsdelivr.net/jquery.ui/1.11.4/jquery-ui.min.css">
+  <link rel="stylesheet" href="https://cdn.jsdelivr.net/codemirror/4.5.0/theme/eclipse.css">
+  <style>
+    .CodeMirror {
+      border: 1px solid #eee;
+    }
+  </style>
+{% endblock %}
+
+
+{% block content_head %}
+<div class="header-wrap">
+  <header id="page-header">
+    <h1 class="title" id="">カスタマイズ</h1>
+  </header>
+</div>
+{% endblock %}
+
+{% block content_main %}
+<div class="content-main">
+  {% set smessage = req.flash('successMessage') %}
+  {% if smessage.length %}
+  <div class="alert alert-success">
+    {{ smessage }}
+  </div>
+  {% endif %}
+
+  {% set emessage = req.flash('errorMessage') %}
+  {% if emessage.length %}
+  <div class="alert alert-danger">
+    {{ emessage }}
+  </div>
+  {% endif %}
+
+  <div class="row">
+    <div class="col-md-3">
+      {% include './widget/menu.html' with {current: 'customize'} %}
+    </div>
+    <div class="col-md-9">
+
+      <form action="/_api/admin/customize/css" method="post" class="form-horizontal" id="cutomcssSettingForm" role="form">
+      <fieldset>
+        <legend>カスタムCSS</legend>
+
+        <p class="help-block">
+          システム全体に適用されるCSSを記述できます。<br>
+          変更の反映はページの更新が必要です。
+        </p>
+
+        <div class="form-group">
+          <div class="col-xs-12">
+            <textarea id="taCustomCss" class="form-control" type="textarea" name="settingForm[customize:css]" rows="20">{{ settingForm['customize:css'] }}</textarea>
+          </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>
+
+    </div>
+  </div>
+
+  <script>
+    $('#cutomcssSettingForm').each(function() {
+      $(this).submit(function()
+      {
+        function showMessage(formId, msg, status) {
+          $('#' + formId + ' .alert').remove();
+
+          if (!status) {
+            status = 'success';
+          }
+          var $message = $('<p class="alert"></p>');
+          $message.addClass('alert-' + status);
+          $message.html(msg.replace('\n', '<br>'));
+          $message.insertAfter('#' + formId + ' legend');
+
+          if (status == 'success') {
+            setTimeout(function()
+            {
+              $message.fadeOut({
+                complete: function() {
+                  $message.remove();
+                }
+              });
+            }, 5000);
+          }
+        }
+
+        var $form = $(this);
+        var $id = $form.attr('id');
+        var $button = $('button', this);
+        $button.attr('disabled', 'disabled');
+        var jqxhr = $.post($form.attr('action'), $form.serialize(), function(data)
+          {
+            if (data.status) {
+              showMessage($id, '更新しました');
+            } else {
+              showMessage($id, data.message, 'danger');
+            }
+          })
+          .fail(function() {
+            showMessage($id, 'エラーが発生しました', 'danger');
+          })
+          .always(function() {
+            $button.prop('disabled', false);
+        });
+        return false;
+      });
+    });
+
+  </script>
+
+  <!-- CodeMirror -->
+  <script src="https://cdn.jsdelivr.net/g/codemirror@4.5.0(codemirror.min.js+addon/lint/css-lint.js+mode/css/css.js+addon/hint/css-hint.js+addon/hint/show-hint.js+addon/edit/matchbrackets.js+addon/edit/closebrackets.js),jquery.ui@1.11.4"></script>
+  <script>
+    var editor = CodeMirror.fromTextArea(document.getElementById('taCustomCss'), {
+      mode: "css",
+      lineNumbers: true,
+      tabSize: 2,
+      indentUnit: 2,
+      theme: 'eclipse',
+      matchBrackets: true,
+      autoCloseBrackets: true,
+      extraKeys: {"Ctrl-Space": "autocomplete"},
+    });
+    editor.on('change', function(cm, change) {
+      cm.save();
+    });
+    // resizable with jquery.ui
+    $(editor.getWrapperElement()).resizable({
+      resize: function() {
+        editor.setSize($(this).width(), $(this).height());
+      }
+    });
+  </script>
+
+</div>
+{% endblock content_main %}
+
+{% block content_footer %}
+{% endblock content_footer %}

+ 2 - 1
lib/views/admin/widget/menu.html

@@ -4,7 +4,8 @@
 <ul class="nav nav-pills nav-stacked">
   <li class="{% if current == 'index'%}active{% endif %}"><a href="/admin"><i class="fa fa-cube"></i> Wiki管理トップ</a></li>
   <li class="{% if current == 'app'%}active{% endif %}"><a href="/admin/app"><i class="fa fa-gears"></i> アプリ設定</a></li>
-  <li class="{% if current == 'markdown'%}active{% endif %}"><a href="/admin/markdown"><i class="fa fa-gears"></i> Markdown設定</a></li>
+  <li class="{% if current == 'markdown'%}active{% endif %}"><a href="/admin/markdown"><i class="fa fa-pencil"></i> Markdown設定</a></li>
+  <li class="{% if current == 'customize'%}active{% endif %}"><a href="/admin/customize"><i class="fa fa-object-group"></i> カスタマイズ</a></li>
   <li class="{% if current == 'notification'%}active{% endif %}"><a href="/admin/notification"><i class="fa fa-bell"></i> 通知設定</a></li>
   <li class="{% if current == 'user'%}active{% endif %}"><a href="/admin/users"><i class="fa fa-users"></i> ユーザー管理</a></li>
   {% if searchConfigured() %}

+ 7 - 1
lib/views/layout/layout.html

@@ -35,7 +35,9 @@
   {% if isEnabledPlugins() %}
     <script src="{{ webpack_asset('plugin').js }}" defer></script>
   {% endif %}
-  <script src="{{ webpack_asset('legacy').js }}" defer></script>
+  {% block html_head_loading_legacy %}
+    <script src="{{ webpack_asset('legacy').js }}" defer></script>
+  {% endblock %}
   <script src="{{ webpack_asset('app').js }}" defer></script>
 
   <!-- Google Fonts -->
@@ -44,6 +46,10 @@
   <link href='//cdn.jsdelivr.net/fontawesome/4.7.0/css/font-awesome.min.css' rel='stylesheet' type='text/css'>
 
   {% block html_additional_headers %}{% endblock %}
+
+  <style>
+    {{ customCss() }}
+  </style>
 </head>
 {% endblock %}
 

+ 2 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "crowi-plus",
-  "version": "1.0.0-RC11",
+  "version": "1.0.1-RC",
   "description": "Enhanced Crowi",
   "tags": [
     "wiki",
@@ -109,6 +109,7 @@
     "sprintf": "~0.1.5",
     "style-loader": "^0.16.1",
     "swig": "~1.4.0",
+    "uglifycss": "^0.0.25",
     "webpack": "~2.3.1",
     "webpack-dll-bundles-plugin": "^1.0.0-beta.5",
     "webpack-merge": "~3.0.0"

+ 7 - 0
resource/css/_wiki.scss

@@ -108,6 +108,7 @@ div.body {
     }
   }
 
+/* ensure to disable in crowi-plus
   pre {
     line-height: 1.4em;
     font-size: .9em;
@@ -117,6 +118,10 @@ div.body {
     font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
     word-wrap: break-word;
   }
+*/
+  pre {
+    border: none;
+  }
 
   img {
     margin: 5px 0;
@@ -151,6 +156,7 @@ div.body {
     }
   }
 
+/* ensure to disable in crowi-plus
   .wiki-code {
     position: relative;
 
@@ -165,6 +171,7 @@ div.body {
 
     }
   };
+*/
 
   .page-template-builder {
     position: relative;

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

@@ -78,7 +78,11 @@ $(function() {
     var parsedHTML = crowiRenderer.render(markdown, rendererOptions);
 
     // create context object
-    var context = {markdown, parsedHTML, currentPagePath: location.pathname};
+    var context = {
+      markdown,
+      parsedHTML,
+      currentPagePath: decodeURIComponent(location.pathname)
+    };
 
     // process interceptors for pre rendering
     crowi.interceptorManager.process('preRenderPreview', context)   // process with the context

+ 5 - 1
resource/js/legacy/crowi.js

@@ -429,7 +429,11 @@ $(function() {
       var parsedHTML = crowiRenderer.render(markdown, rendererOptions);
 
       // create context object
-      var context = {markdown, parsedHTML, currentPagePath: location.pathname};
+      var context = {
+        markdown,
+        parsedHTML,
+        currentPagePath: decodeURIComponent(location.pathname)
+      };
 
       // process interceptors for pre rendering
       crowi.interceptorManager.process('preRender', context)   // process with the context

+ 1 - 0
resource/styles/index.js

@@ -1 +1,2 @@
 import '../css/crowi.scss';
+import 'highlight.js/styles/github.css';

Разница между файлами не показана из-за своего большого размера
+ 271 - 276
yarn.lock


Некоторые файлы не были показаны из-за большого количества измененных файлов