Jelajahi Sumber

Merge pull request #138 from crowi/wip-v1.5.2

Prepare: v1.5.2
Sotaro KARASAWA 9 tahun lalu
induk
melakukan
6ef92d6b1e

+ 11 - 0
CHANGES.md

@@ -1,6 +1,17 @@
 CHANGES
 ========
 
+## 1.5.2
+
+* Fix: Edit button on smartphone.
+* Fix: Avoid timeout on rebuilding search index.
+* Improve: Search screen on smartphone.
+* Improve: New page dialog.
+* Improve: Update link color.
+* Add node version for CI.
+* Changed assets loader.
+* And some fixes. (Thank you @suzuki @kdmsnr @crow-misia)
+
 ## 1.5.1
 
 * Fix: Broken corwi.min.js (thank you @Bakudankun #135)

+ 1 - 1
README.md

@@ -4,7 +4,7 @@ Crowi - The Simple & Powerful Communication Tool Based on Wiki
 ================================================================
 
 
-[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/crowi/crowi/tree/v1.5.1)
+[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/crowi/crowi/tree/v1.5.2)
 
 [![Circle CI](https://circleci.com/gh/crowi/crowi.svg?style=svg)](https://circleci.com/gh/crowi/crowi)
 [![Join the chat at https://gitter.im/crowi/general](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/crowi/general)

+ 13 - 10
gulpfile.js

@@ -1,5 +1,7 @@
 'use strict';
 
+var fs = require('fs');
+
 var gulp   = require('gulp');
 var sass   = require('gulp-sass');
 var cssmin = require('gulp-cssmin');
@@ -48,10 +50,10 @@ var js = {
 
   bundled:      dirs.jsDist + '/bundled.js',
   dist:         dirs.jsDist + '/crowi.js',
+  app:          dirs.jsDist + '/app.js',
   admin:        dirs.jsDist + '/admin.js',
   form:         dirs.jsDist + '/form.js',
   presentation: dirs.jsDist + '/presentation.js',
-  app:          dirs.jsDist + '/app.js',
 
   clientWatch: ['resource/js/**/*.js'],
   watch: ['test/**/*.test.js', 'app.js', 'lib/**/*.js'],
@@ -66,15 +68,16 @@ var cssIncludePaths = [
 ];
 
 gulp.task('js:del', function() {
-  var fileList = [
-    js.dist,
-    js.bundled,
-    js.admin,
-    js.form,
-    js.presentation,
-    js.app,
-  ];
-  fileList = fileList.concat(fileList.map(function(fn){ return fn.replace(/\.js/, '.min.js');}));
+  var fileList = [];
+
+  var actualFiles = fs.readdirSync(dirs.jsDist);
+  fileList = actualFiles.map(function(fn){
+    if (!fn.match(/.js(on)?$/)) {
+      return false
+    }
+    return dirs.jsDist + '/' + fn;
+  }).filter(function(v) { return v; });
+
   return del(fileList);
 });
 

+ 23 - 0
lib/crowi/index.js

@@ -4,6 +4,7 @@
 var debug = require('debug')('crowi:crowi')
   , pkg = require('../../package.json')
   , path = require('path')
+  , fs = require('fs')
   , sep = path.sep
   , Promise = require('bluebird')
 
@@ -27,6 +28,13 @@ function Crowi (rootdir, env)
   this.viewsDir  = path.join(this.libDir, 'views') + sep;
   this.mailDir   = path.join(this.viewsDir, 'mail') + sep;
 
+  this.assets    = {};
+  try {
+    this.assets = require(this.publicDir + '/js/manifest.json') || {};
+  } catch (e) {
+    // ignore
+  }
+
   this.config = {};
   this.searcher = null;
   this.mailer = {};
@@ -97,6 +105,21 @@ Crowi.prototype.getConfig = function() {
   return this.config;
 };
 
+Crowi.prototype.getAssetList = function() {
+  if (this.node_env !== 'development') {
+    return this.assets;
+  }
+
+  // reload manifest
+  try {
+    this.assets = JSON.parse(fs.readFileSync(this.publicDir + '/js/manifest.json'))|| {};
+  } catch (e) {
+    // ignore
+    debug('Failed to reload assets on development', e);
+  }
+  return this.assets;
+};
+
 // getter/setter of model instance
 //
 Crowi.prototype.model = function(name, model) {

+ 4 - 1
lib/util/search.js

@@ -226,7 +226,10 @@ SearchClient.prototype.addAllPages = function()
       // all done
 
       // 最後に送信
-      self.client.bulk({ body: body, })
+      self.client.bulk({
+        body: body,
+        requestTimeout: Infinity,
+      })
       .then(function(res) {
         debug('Reponse from es:', res);
         return resolve(res);

+ 14 - 0
lib/util/swigFunctions.js

@@ -10,6 +10,20 @@ module.exports = function(crowi, app, req, locals) {
     return req.csrfToken;
   };
 
+  locals.assets = function(file) {
+    var assetList = crowi.getAssetList();
+    var baseName = file.match(/\/([^\/]+)$/)[1];
+
+    var baseNameWithHash = '';
+    if (assetList[baseName]) {
+      baseNameWithHash = assetList[baseName];
+    } else {
+      return file;
+    }
+
+    return file.replace(baseName, baseNameWithHash);
+  };
+
   locals.googleLoginEnabled = function() {
     var config = crowi.getConfig()
     return config.crowi['google:clientId'] && config.crowi['google:clientSecret'];

+ 1 - 1
lib/views/_form.html

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

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

@@ -1,6 +1,6 @@
 {% extends '2column.html' %}
 
 {% block footer %}
-  <script src="/js/admin.js"></script>
+  <script src="{{ assets('/js/admin.js') }}"></script>
 {% endblock footer %}
 

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

@@ -12,7 +12,8 @@
   <meta name="viewport" content="width=device-width,initial-scale=1">
 
   <link rel="stylesheet" href="/css/crowi{% if env  == 'production' %}.min{% endif %}.css">
-  <script src="/js/bundled.js"></script>
+
+  <script src="{{ assets('/js/bundled.js') }}"></script>
   <link href='//fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
 </head>
 {% endblock %}
@@ -30,10 +31,10 @@
   <div class="navbar-header">
     <a class="navbar-brand" href="/">
       <img alt="Crowi" src="/logo/32x32.png" width="16">
-      {% block title %}{{ config.crowi['app:title']|default('Crowi') }}{% endblock %}
+      <span class="hidden-xs">{% block title %}{{ config.crowi['app:title']|default('Crowi') }}{% endblock %}</span>
     </a>
   {% if searchConfigured() %}
-  <div class="navbar-form navbar-left search-top visible-lg visible-md" role="search" id="search-top">
+  <div class="navbar-form navbar-left search-top" role="search" id="search-top">
   </div>
   {% endif %}
   </div>
@@ -130,6 +131,6 @@
 </body>
 {% endblock %}
 
-<script src="/js/crowi.js"></script>
-<script src="/js/app.js"></script>
+<script src="{{ assets('/js/crowi.js') }}"></script>
+<script src="{{ assets('/js/app.js') }}"></script>
 </html>

+ 2 - 2
lib/views/page_presentation.html

@@ -10,7 +10,7 @@
     <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">
 
-    <script src="/js/bundled.js"></script>
+    <script src="{{ assets('/js/bundled.js') }}"></script>
 
     <title>{{ path|path2name }} | {{ path }}</title>
   </head>
@@ -29,6 +29,6 @@
       </div>
     </div>
 
-    <script src="/js/presentation.js"></script>
+    <script src="{{ assets('/js/presentation.js') }}"></script>
   </body>
 </html>

+ 2 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "crowi",
-  "version": "1.5.1",
+  "version": "1.5.2",
   "description": "The simple & powerful Wiki",
   "tags": [
     "wiki",
@@ -95,6 +95,7 @@
     "time": "~0.11.0",
     "vinyl-source-stream": "~1.1.0",
     "webpack": "~1.13.0",
+    "webpack-manifest-plugin": "~1.0.1",
     "webpack-stream": "~3.1.0"
   },
   "devDependencies": {

+ 8 - 2
resource/css/_form.scss

@@ -99,7 +99,7 @@
     width: 100%;
     left: 0;
     padding: 8px;
-    height: 50px;
+    min-height: 50px;
     background: rgba(255,255,255,.8);
     border-top: solid 1px #ccc;
     margin-bottom: 0;
@@ -150,9 +150,15 @@ input:-moz-placeholder {
     .form-group.form-submit-group {
       select.form-control {
         display: inline-block;
-        width: auto;
+        max-width: 50%;
       }
     }
   }
 
 } // }}}
+
+@media (max-width: $screen-xs-max) { // {{{ less than smartphone size
+  #edit-form-submit {
+    float: right;
+  }
+} // }}}

+ 55 - 0
resource/css/_search.scss

@@ -126,3 +126,58 @@
     }
   }
 }
+
+// Smartphone and Tablet
+@media (max-width: $screen-sm-max) {
+  .search-top {
+    margin-top: 4px 0 0 0;
+    padding: 0;
+    border-style: none !important;
+    box-shadow: none !important;
+    -webkit-box-shadow: none !important;
+
+    .search-form {
+      width: 76%;
+    }
+
+    .search-top-input-group {
+      .search-top-input {
+        width: 100%;
+      }
+      .btn {
+        z-index: 10;
+      }
+    }
+  }
+
+  .search-result {
+    .search-result-content {
+      .search-result-page {
+        .wiki {
+          h1, h2, h3, h4, h5, h6 {
+            font-size: medium;
+          }
+          height: 250px;
+          overflow: scroll;
+        }
+      }
+    }
+  }
+}
+
+// Smartphone
+@media (max-width: $screen-xs-max) {
+  .search-top {
+    .search-form {
+      min-width: 40%;
+      max-width: 50%;
+      width: 50%;
+    }
+    .search-box {
+      .search-suggest {
+        left: 2%;
+        width: 94%;
+      }
+    }
+  }
+}

+ 10 - 0
resource/css/_wiki.scss

@@ -97,6 +97,16 @@ div.body {
     font-size: .9em;
   }
 
+  a {
+    text-decoration: underline;
+    color: #38ad9e;
+
+    &:hover {
+      text-decoration: none;
+      color: darken(#38ad9e, 10%);
+    }
+  }
+
   pre {
     line-height: 1.4em;
     font-size: .9em;

+ 16 - 0
resource/css/crowi.scss

@@ -109,6 +109,22 @@ footer {
     }
 
     form {
+
+      input.form-control {
+        border: none;
+        box-shadow: none;
+        border-bottom: dotted 1px #444;
+        border-radius: 0;
+        padding: 6px;
+        height: 34px;
+        font-weight: bold;
+        background: #f0f0f0;
+
+        &:focus {
+          background: #ddd;
+        }
+      }
+
       .page-name-addons {
         position: absolute;
         top: 7px;

+ 0 - 2
resource/js/app.js

@@ -33,5 +33,3 @@ Object.keys(componentMappings).forEach((key) => {
     ReactDOM.render(componentMappings[key], elem);
   }
 });
-
-

+ 1 - 2
resource/js/components/SearchPage/SearchResult.js

@@ -78,7 +78,7 @@ export default class SearchResult extends React.Component {
     return (
       <div className="content-main">
         <div className="search-result row" id="search-result">
-          <div className="col-md-4 page-list search-result-list" id="search-result-list">
+          <div className="col-md-4 hidden-xs hidden-sm page-list search-result-list" id="search-result-list">
             <nav data-spy="affix" data-offset-top="120">
               <ul className="page-list-ul nav">
                 {listView}
@@ -111,4 +111,3 @@ SearchResult.defaultProps = {
   searchResultMeta: {},
   searchError: null,
 };
-

+ 2 - 2
resource/js/crowi.js

@@ -215,12 +215,12 @@ $(function() {
 
   $('#create-page').on('shown.bs.modal', function (e) {
 
-    var input2Width = $('#create-page-today .page-today-input2').outerWidth();
+    var input2Width = $('#create-page-today .col-xs-10').outerWidth();
     var newWidth = input2Width
       - $('#create-page-today .page-today-prefix').outerWidth()
       - $('#create-page-today .page-today-input1').outerWidth()
       - $('#create-page-today .page-today-suffix').outerWidth()
-      - 10
+      - 40
       ;
     $('#create-page-today .form-control.page-today-input2').css({width: newWidth}).focus();
 

+ 10 - 5
webpack.config.js

@@ -1,17 +1,19 @@
 var path = require('path');
 var webpack = require('webpack');
 
+var ManifestPlugin = require('webpack-manifest-plugin');
+
 var config = {
   entry: {
-    app: './resource/js/app.js',
-    crowi: './resource/js/crowi.js',
+    app:          './resource/js/app.js',
+    crowi:        './resource/js/crowi.js',
     presentation: './resource/js/crowi-presentation.js',
-    form: './resource/js/crowi-form.js',
-    admin: './resource/js/crowi-admin.js',
+    form:         './resource/js/crowi-form.js',
+    admin:        './resource/js/crowi-admin.js',
   },
   output: {
     path: path.join(__dirname + "/public/js"),
-    filename: "[name].js"
+    filename: "[name].[hash].js"
   },
   resolve: {
     modulesDirectories: [
@@ -47,4 +49,7 @@ if (process.env && process.env.NODE_ENV !== 'development') {
     }),
   ];
 }
+
+config.plugins.push(new ManifestPlugin());
+
 module.exports = config;