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

Merge pull request #34 from crowi/move-to-gulp

Move Grunt to gulp
Sotaro KARASAWA 10 лет назад
Родитель
Сommit
8096d7498e

+ 0 - 149
Gruntfile.js

@@ -1,149 +0,0 @@
-/*
- * @package Crowi
- */
-
-module.exports = function(grunt) {
-
-  var paths = {
-        scripts: ['Gruntfile.js', 'app.js', 'lib/**/*.js', 'resource/js/**/*.js'],
-        tests: ['test/**/*.test.js'],
-        styles: ['resource/css/*.scss'],
-        all: []
-      };
-
-  Object.keys(paths).forEach(function(name) {
-    paths[name].forEach(function(path) {
-      paths.all[paths.all.length] = path;
-    });
-  });
-
-  // Project configuration.
-  grunt.initConfig({
-    pkg: grunt.file.readJSON('package.json'),
-    dirs: {
-      js: 'resource/js',
-      jsDest: 'public/js',
-      css: 'resource/css',
-      cssDest: 'public/css',
-      web: 'public/'
-    },
-    sass: {
-      dev: {
-        options: {
-          outputStyle: 'nested',
-          includePaths: [
-            'bower_components/bootstrap-sass-official/assets/stylesheets',
-            'bower_components/fontawesome/scss',
-            'bower_components/reveal.js/css'
-          ]
-        },
-        files: {
-          '<%= dirs.cssDest %>/<%= pkg.name %>-main.css': '<%= dirs.css %>/<%= pkg.name %>.scss',
-          '<%= dirs.cssDest %>/<%= pkg.name %>-reveal.css': '<%= dirs.css %>/<%= pkg.name %>-reveal.scss'
-        }
-      },
-      default: {
-        options: {
-          outputStyle: 'compressed',
-          includePaths: [
-            'bower_components/bootstrap-sass-official/assets/stylesheets',
-            'bower_components/fontawesome/scss',
-            'bower_components/reveal.js/css'
-          ]
-        },
-        files: {
-          '<%= dirs.cssDest %>/<%= pkg.name %>-main.min.css': '<%= dirs.css %>/<%= pkg.name %>.scss',
-          '<%= dirs.cssDest %>/<%= pkg.name %>-reveal.min.css': '<%= dirs.css %>/<%= pkg.name %>-reveal.scss'
-        }
-      }
-    },
-    concat: {
-      dist: {
-        files: {
-          '<%= dirs.cssDest %>/<%= pkg.name %>.css': [
-            'bower_components/highlightjs/styles/tomorrow-night.css',
-            '<%= dirs.cssDest %>/<%= pkg.name %>-main.css',
-          ],
-          '<%= dirs.cssDest %>/<%= pkg.name %>.min.css': [
-            'bower_components/highlightjs/styles/tomorrow-night.css', // TODO minimize
-            '<%= dirs.cssDest %>/<%= pkg.name %>-main.min.css',
-          ],
-          '<%= dirs.jsDest %>/<%= pkg.name %>.js': [
-            'bower_components/jquery/dist/jquery.js',
-            'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap.js',
-            'node_modules/socket.io-client/socket.io.js',
-            'bower_components/marked/lib/marked.js',
-            'bower_components/jquery.cookie/jquery.cookie.js',
-            'bower_components/highlightjs/highlight.pack.js',
-            'resource/js/crowi.js'
-          ],
-          '<%= dirs.jsDest %>/<%= pkg.name %>-reveal.js': [
-            'bower_components/jquery/dist/jquery.js',
-            'bower_components/reveal.js/lib/js/head.min.js',
-            'bower_components/reveal.js/lib/js/html5shiv.js',
-            'bower_components/reveal.js/js/reveal.js'
-          ],
-        }
-      },
-    },
-    uglify: {
-      build: {
-        files: {
-          '<%= dirs.jsDest %>/<%= pkg.name %>.min.js': '<%= dirs.jsDest %>/<%= pkg.name %>.js',
-          '<%= dirs.jsDest %>/<%= pkg.name %>-reveal.min.js': '<%= dirs.jsDest %>/<%= pkg.name %>-reveal.js'
-        }
-      }
-    },
-    jshint: {
-      options: {
-        jshintrc: true
-      },
-      all: paths.scripts
-    },
-    mochaTest: {
-      all: {
-        src: ['test/**/*.test.js'],
-        options: {
-          globals: ['chai'],
-          require: ['test/bootstrap.js'],
-          timeout: 3000,
-          quiet: false,
-          clearRequireCache: true,
-          reporter: 'dot',
-        },
-      }
-    },
-    watch: {
-      css: {
-        files: paths.styles,
-        tasks: ['sass'],
-      },
-      dev: {
-        files: paths.all,
-        tasks: ['dev'],
-      },
-      test: {
-        files: paths.all,
-        tasks: ['test'],
-      },
-      default: {
-        files: paths.all,
-        tasks: ['default'],
-      },
-    },
-  });
-
-
-  grunt.loadNpmTasks('grunt-contrib-uglify');
-  grunt.loadNpmTasks('grunt-contrib-watch');
-  grunt.loadNpmTasks('grunt-contrib-concat');
-  grunt.loadNpmTasks('grunt-contrib-jshint');
-  grunt.loadNpmTasks('grunt-sass');
-  grunt.loadNpmTasks('grunt-mocha-test');
-
-  // grunt watch dev
-  grunt.registerTask('default', ['sass', 'concat', 'uglify']);
-  grunt.registerTask('dev', ['sass:dev', 'concat', 'jshint']);
-  grunt.registerTask('test', ['mochaTest']);
-
-};

+ 141 - 0
gulpfile.js

@@ -0,0 +1,141 @@
+'use strict';
+
+var gulp   = require('gulp');
+var sass   = require('gulp-sass');
+var cssmin = require('gulp-cssmin');
+var mocha  = require('gulp-spawn-mocha');
+var concat = require('gulp-concat');
+var rename = require('gulp-rename');
+var uglify = require('gulp-uglify');
+var jshint = require('gulp-jshint');
+
+var stylish = require('jshint-stylish');
+
+var pkg = require('./package.json');
+
+
+var dirs = {
+  cssSrc: './resource/css',
+  cssDist: './public/css',
+  jsSrc: './resource/js',
+  jsDist: './public/js',
+};
+
+var tests = {
+  watch: ['test/**/*.test.js'],
+}
+
+var css = {
+  src: dirs.cssSrc + '/' + pkg.name + '.scss',
+  main: dirs.cssDist + '/crowi-main.css',
+  dist: dirs.cssDist + '/crowi.css',
+  watch: ['resource/css/*.scss'],
+};
+
+var js = {
+  src: [
+    'bower_components/jquery/dist/jquery.js',
+    'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap.js',
+    'node_modules/socket.io-client/socket.io.js',
+    'bower_components/marked/lib/marked.js',
+    'bower_components/jquery.cookie/jquery.cookie.js',
+    'bower_components/highlightjs/highlight.pack.js',
+    'resource/js/crowi.js'
+  ],
+  dist: dirs.jsDist + '/crowi.js',
+  revealSrc: [
+    'bower_components/reveal.js/lib/js/head.min.js',
+    'bower_components/reveal.js/lib/js/html5shiv.js',
+    'bower_components/reveal.js/js/reveal.js'
+  ],
+  revealDist: dirs.jsDist + '/crowi-reveal.js',
+  clientWatch: ['resource/js/**/*.js'],
+  watch: ['test/**/*.test.js', 'app.js', 'lib/**/*.js'],
+  lint: ['app.js', 'lib/**/*.js'],
+  tests: tests.watch,
+};
+
+var cssIncludePaths = [
+  'bower_components/bootstrap-sass-official/assets/stylesheets',
+  'bower_components/fontawesome/scss',
+  'bower_components/reveal.js/css'
+];
+
+gulp.task('js:concat', function() {
+  gulp.src(js.revealSrc)
+    .pipe(concat('crowi-reveal.js'))
+    .pipe(gulp.dest(dirs.jsDist));
+
+  return gulp.src(js.src)
+    .pipe(concat('crowi.js'))
+    .pipe(gulp.dest(dirs.jsDist));
+});
+
+gulp.task('js:min', ['js:concat'], function() {
+  gulp.src(js.revealDist)
+    .pipe(uglify())
+    .pipe(rename({suffix: '.min'}))
+    .pipe(gulp.dest(dirs.jsDist));
+
+  return gulp.src(js.dist)
+    .pipe(uglify())
+    .pipe(rename({suffix: '.min'}))
+    .pipe(gulp.dest(dirs.jsDist));
+});
+
+gulp.task('jshint', function() {
+  return gulp.src(js.lint)
+    .pipe(jshint())
+    .pipe(jshint.reporter(stylish));
+});
+
+gulp.task('test', function() {
+  return gulp.src(js.tests)
+    .pipe(mocha({
+      r: 'test/bootstrap.js',
+      globals: ['chai'],
+      R: 'dot',
+    }));
+});
+
+gulp.task('css:sass', function() {
+  return gulp.src(css.src)
+    .pipe(sass({
+        outputStyle: 'nesed',
+        sourceComments: 'map',
+        includePaths: cssIncludePaths
+    }).on('error', sass.logError))
+    .pipe(rename({suffix: '-main'}))
+    .pipe(gulp.dest(dirs.cssDist));
+});
+
+gulp.task('css:concat', ['css:sass'], function() {
+  return gulp.src([css.main, 'bower_components/highlightjs/styles/tomorrow-night.css'])
+    .pipe(concat('crowi.css'))
+    .pipe(gulp.dest(dirs.cssDist))
+});
+
+gulp.task('css:min', ['css:concat'], function() {
+  return gulp.src(css.dist)
+    .pipe(cssmin())
+    .pipe(rename({suffix: '.min'}))
+    .pipe(gulp.dest(dirs.cssDist));
+});
+
+gulp.task('watch', function() {
+  var watchLogger = function(event) {
+    console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
+  };
+
+  var cssWatcher = gulp.watch(css.watch, ['css:concat']);
+  cssWatcher.on('change', watchLogger);
+  var jsWatcher = gulp.watch(js.clientWatch, ['js:concat']);
+  jsWatcher.on('change', watchLogger);
+  var testWatcher = gulp.watch(js.watch, ['test']);
+  testWatcher.on('change', watchLogger);
+});
+
+gulp.task('css', ['css:sass', 'css:concat',]);
+gulp.task('default', ['css:min', 'js:min',]);
+gulp.task('dev', ['css:concat', 'js:concat','jshint', 'test']);
+

+ 1 - 2
lib/models/page.js

@@ -12,11 +12,10 @@ module.exports = function(crowi) {
   function populatePageData(pageData, revisionId, callback) {
     var Page = crowi.model('Page');
 
+    pageData.latestRevision = pageData.revision;
     if (revisionId) {
       pageData.revision = revisionId;
     }
-
-    pageData.latestRevision = pageData.revision;
     pageData.likerCount = pageData.liker.length || 0;
     pageData.seenUsersCount = pageData.seenUsers.length || 0;
 

+ 6 - 3
lib/routes/admin.js

@@ -203,6 +203,7 @@ module.exports = function(crowi, app) {
       // mail setting ならここで validation
       if (form['mail:from']) {
         validateMailSetting(req, form, function(err, data) {
+          debug('Error validate mail setting: ', err, data);
           if (err) {
             req.form.errors.push('SMTPを利用したテストメール送信に失敗しました。設定をみなおしてください。');
             return res.json({status: false, message: req.form.errors.join('\n')});
@@ -232,11 +233,13 @@ module.exports = function(crowi, app) {
     var option = {
       host: form['mail:smtpHost'],
       port: form['mail:smtpPort'],
-      auth: {
+    };
+    if (form['mail:smtpUser'] && form['mail:smtpPassword']) {
+      option.auth = {
         user: form['mail:smtpUser'],
         pass: form['mail:smtpPassword'],
-      }
-    };
+      };
+    }
     if (option.port === 465) {
       option.secure = true;
     }

+ 3 - 3
lib/routes/login.js

@@ -82,7 +82,7 @@ module.exports = function(crowi, app) {
   };
 
   actions.loginGoogle = function(req, res) {
-    var googleAuth = require('../util/googleAuth')(app);
+    var googleAuth = require('../util/googleAuth')(config);
     var code = req.session.googleAuthCode || null;
 
     if (!code) {
@@ -134,7 +134,7 @@ module.exports = function(crowi, app) {
   };
 
   actions.register = function(req, res) {
-    var googleAuth = require('../util/googleAuth')(app);
+    var googleAuth = require('../util/googleAuth')(config);
 
     // ログイン済みならさようなら
     if (req.user) {
@@ -269,7 +269,7 @@ module.exports = function(crowi, app) {
   };
 
   actions.registerGoogle = function(req, res) {
-    var googleAuth = require('../util/googleAuth')(app);
+    var googleAuth = require('../util/googleAuth')(config);
     googleAuth.createAuthUrl(req, function(err, redirectUrl) {
       if (err) {
         // TODO

+ 2 - 2
lib/routes/me.js

@@ -179,7 +179,7 @@ module.exports = function(crowi, app) {
   };
 
   actions.authGoogle = function(req, res) {
-    var googleAuth = require('../util/googleAuth')(app);
+    var googleAuth = require('../util/googleAuth')(config);
 
     var userData = req.user;
 
@@ -206,7 +206,7 @@ module.exports = function(crowi, app) {
   };
 
   actions.authGoogleCallback = function(req, res) {
-    var googleAuth = require('../util/googleAuth')(app);
+    var googleAuth = require('../util/googleAuth')(config);
     var userData = req.user;
 
     googleAuth.handleCallback(req, function(err, tokenInfo) {

+ 5 - 5
lib/routes/page.js

@@ -69,7 +69,7 @@ module.exports = function(crowi, app) {
     }
 
     if (pageData.redirectTo) {
-      return res.redirect(pageData.redirectTo + '?renamed=' + pageData.path);
+      return res.redirect(encodeURI(pageData.redirectTo + '?renamed=' + pageData.path));
     }
 
     Revision.findRevisionList(pageData.path, {}, function(err, tree) {
@@ -92,7 +92,7 @@ module.exports = function(crowi, app) {
     // pageShow は /* にマッチしてる最後の砦なので、creatableName でない routing は
     // これ以前に定義されているはずなので、こうしてしまって問題ない。
     if (!Page.isCreatableName(path)) {
-      debug('Page is not creatable name.');
+      debug('Page is not creatable name.', path);
       res.redirect('/');
       return ;
     }
@@ -104,7 +104,7 @@ module.exports = function(crowi, app) {
 
     Page.findPage(path, req.user, req.query.revision, options, function(err, pageData) {
       if (req.query.revision && err) {
-        res.redirect(path);
+        res.redirect(encodeURI(path));
         return ;
       }
 
@@ -134,7 +134,7 @@ module.exports = function(crowi, app) {
     var grant = pageForm.grant;
 
     if (!Page.isCreatableName(path)) {
-      res.redirect(path);
+      res.redirect(encodeURI(path));
       return ;
     }
 
@@ -185,7 +185,7 @@ module.exports = function(crowi, app) {
       if (err) {
         return res.redirect('/');
       }
-      return res.redirect(d.path);
+      return res.redirect(encodeURI(d.path));
     };
 
     Page.findPageById(id, function(err, pageData) {

+ 1 - 2
lib/util/googleAuth.js

@@ -2,12 +2,11 @@
  * googleAuth utility
  */
 
-module.exports = function(app) {
+module.exports = function(config) {
   'use strict';
 
   var googleapis = require('googleapis')
     , debug = require('debug')('crowi:lib:googleAuth')
-    , config = app.set('config')
     , lib = {}
     ;
 

+ 9 - 5
lib/util/mailer.js

@@ -24,19 +24,23 @@ module.exports = function(crowi) {
       option = {
         host: config.crowi['mail:smtpHost'],
         port: config.crowi['mail:smtpPort'],
-        auth: {
+      };
+
+      if (config.crowi['mail:smtpUser'] && config.crowi['mail:smtpPassword']) {
+        option.auth =  {
           user: config.crowi['mail:smtpUser'],
           pass: config.crowi['mail:smtpPassword']
-        }
-      };
+        };
+      }
       if (option.port === 465) {
         option.secure = true;
       }
     }
+    option.tls = {rejectUnauthorized: false};
 
     client = nodemailer.createTransport(option);
 
-    debug('mailer setted up for SMTP', client);
+    debug('mailer set up for SMTP', client);
     return client;
   }
 
@@ -54,7 +58,7 @@ module.exports = function(crowi) {
     var ses = require('nodemailer-ses-transport');
     client = nodemailer.createTransport(ses(option));
 
-    debug('mailer setted up for SES', client);
+    debug('mailer set up for SES', client);
     return client;
   }
 

+ 13 - 11
package.json

@@ -29,9 +29,9 @@
     "async": "~0.9.0",
     "aws-sdk": "~2.0.0-rc.19",
     "basic-auth-connect": "~1.0.0",
+    "bluebird": "^2.9.12",
     "body-parser": "~1.12.0",
     "bower": "~1.4.0",
-    "bluebird": "^2.9.12",
     "cli": "~0.6.0",
     "connect-flash": "~0.1.1",
     "connect-redis": "~2.1.0",
@@ -44,14 +44,16 @@
     "express-session": "~1.10.0",
     "facebook-node-sdk": "=0.1.10",
     "googleapis": "=0.4.7",
-    "grunt": "~0.4.5",
-    "grunt-cli": "~0.1.13",
-    "grunt-contrib-concat": "~0.5.0",
-    "grunt-contrib-jshint": "~0.11.0",
-    "grunt-contrib-uglify": "~0.8.0",
-    "grunt-contrib-watch": "~0.6.1",
-    "grunt-mocha-test": "~0.12.7",
-    "grunt-sass": "~0.18.0",
+    "gulp": "~3.8.11",
+    "gulp-concat": "^2.5.2",
+    "gulp-cssmin": "^0.1.7",
+    "gulp-jshint": "~1.10.0",
+    "gulp-rename": "^1.2.2",
+    "gulp-sass": "~2.0.4",
+    "gulp-spawn-mocha": "^2.2.1",
+    "gulp-uglify": "~1.2.0",
+    "gulp-watch": "~4.2.4",
+    "jshint-stylish": "^2.0.0",
     "method-override": "~2.3.1",
     "mongoose": "~3.8.0",
     "mongoose-paginate": "~3.1.0",
@@ -80,8 +82,8 @@
   ],
   "scripts": {
     "start": "node app.js",
-    "test": "grunt test",
-    "postinstall": "bower cache clean && bower install && grunt"
+    "test": "gulp test",
+    "postinstall": "bower cache clean && bower install && gulp"
   },
   "env": {
     "NODE_ENV": "production"

+ 671 - 0
resource/css/_utilities.scss

@@ -0,0 +1,671 @@
+// crowi
+$brand-primary:         #43676b;
+
+$crowiHeaderBackground: darken($brand-primary, 15%);
+$crowiHeaderHeight: 50px;
+
+// $crowiAsideBackground:   darken($crowiHeaderBackground, 5%);
+$crowiAsideBackground: #fcfcfc;
+
+$crowiFooterBackground:  $crowiHeaderBackground;
+$crowiFooterHeight: 34px;
+
+
+
+//
+// Variables
+// --------------------------------------------------
+
+
+// Global values
+// --------------------------------------------------
+
+// Grays
+// -------------------------
+
+$gray-darker:            lighten(#000, 13.5%); // #222
+$gray-dark:              lighten(#000, 20%);   // #333
+// $gray:                   lighten(#000, 33.5%); // #555
+// $gray-light:             lighten(#000, 60%);   // #999
+// $gray-lighter:           lighten(#000, 93.5%); // #eee
+//
+// // Brand colors
+// // -------------------------
+//
+//$brand-primary: #4d4398;
+//$brand-primary: #622d18;
+//$brand-primary: #e5a323;
+// $brand-success:         #5cb85c;
+// $brand-warning:         #f0ad4e;
+// $brand-danger:          #d9534f;
+// $brand-info:            #5bc0de;
+
+//
+// // Scaffolding
+// // -------------------------
+//
+//$body-bg:              $crowiHeaderBackground;
+// $text-color:            $gray-dark;
+//
+// // Links
+// // -------------------------
+//
+$link-color:            $brand-primary;
+$link-hover-color:      darken($link-color, 15%);
+//
+// // Typography
+// // -------------------------
+//
+// $font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif;
+// $font-family-serif:       Georgia, "Times New Roman", Times, serif;
+// $font-family-monospace:   Monaco, Menlo, Consolas, "Courier New", monospace;
+// $font-family-base:        $font-family-sans-serif;
+//
+// $font-size-base:          14px;
+// $font-size-large:         ceil($font-size-base * 1.25); // ~18px
+// $font-size-small:         ceil($font-size-base * 0.85); // ~12px
+//
+// $font-size-h1:            floor($font-size-base * 2.6); // ~36px
+// $font-size-h2:            floor($font-size-base * 2.15); // ~30px
+// $font-size-h3:            ceil($font-size-base * 1.7); // ~24px
+// $font-size-h4:            ceil($font-size-base * 1.25); // ~18px
+// $font-size-h5:            $font-size-base;
+// $font-size-h6:            ceil($font-size-base * 0.85); // ~12px
+//
+// $line-height-base:        1.428571429; // 20/14
+// $line-height-computed:    floor($font-size-base * $line-height-base); // ~20px
+//
+// $headings-font-family:    $font-family-base;
+// $headings-font-weight:    500;
+// $headings-line-height:    1.1;
+// $headings-color:          inherit;
+//
+//
+// // Iconography
+// // -------------------------
+//
+// $icon-font-path:          "../fonts/";
+// $icon-font-name:          "glyphicons-halflings-regular";
+//
+//
+// // Components
+// // -------------------------
+// // Based on 14px font-size and 1.428 line-height (~20px to start)
+//
+// $padding-base-vertical:          6px;
+// $padding-base-horizontal:        12px;
+//
+// $padding-large-vertical:         10px;
+// $padding-large-horizontal:       16px;
+//
+// $padding-small-vertical:         5px;
+// $padding-small-horizontal:       10px;
+//
+// $line-height-large:              1.33;
+// $line-height-small:              1.5;
+//
+// $border-radius-base:             4px;
+// $border-radius-large:            6px;
+// $border-radius-small:            3px;
+//
+// $component-active-color:         #fff;
+// $component-active-bg:            $brand-primary;
+//
+// $caret-width-base:               4px;
+// $caret-width-large:              5px;
+//
+// // Tables
+// // -------------------------
+//
+// $table-cell-padding:                 8px;
+// $table-condensed-cell-padding:       5px;
+//
+// $table-bg:                           transparent; // overall background-color
+// $table-bg-accent:                    #f9f9f9; // for striping
+// $table-bg-hover:                     #f5f5f5;
+// $table-bg-active:                    $table-bg-hover;
+//
+// $table-border-color:                 #ddd; // table and cell border
+//
+//
+// // Buttons
+// // -------------------------
+//
+// $btn-font-weight:                normal;
+//
+// $btn-default-color:              #333;
+// $btn-default-bg:                 #fff;
+// $btn-default-border:             #ccc;
+//
+// $btn-primary-color:              #fff;
+// $btn-primary-bg:                 $brand-primary;
+// $btn-primary-border:             darken($btn-primary-bg, 5%);
+//
+// $btn-success-color:              #fff;
+// $btn-success-bg:                 $brand-success;
+// $btn-success-border:             darken($btn-success-bg, 5%);
+//
+// $btn-warning-color:              #fff;
+// $btn-warning-bg:                 $brand-warning;
+// $btn-warning-border:             darken($btn-warning-bg, 5%);
+//
+// $btn-danger-color:               #fff;
+// $btn-danger-bg:                  $brand-danger;
+// $btn-danger-border:              darken($btn-danger-bg, 5%);
+//
+// $btn-info-color:                 #fff;
+// $btn-info-bg:                    $brand-info;
+// $btn-info-border:                darken($btn-info-bg, 5%);
+//
+// $btn-link-disabled-color:        $gray-light;
+//
+//
+// // Forms
+// // -------------------------
+//
+// $input-bg:                       #fff;
+// $input-bg-disabled:              $gray-lighter;
+//
+// $input-color:                    $gray;
+// $input-border:                   #ccc;
+// $input-border-radius:            $border-radius-base;
+// $input-border-focus:             #66afe9;
+//
+// $input-color-placeholder:        $gray-light;
+//
+// $input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2);
+// $input-height-large:             (floor($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2);
+// $input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2);
+//
+// $legend-color:                   $gray-dark;
+// $legend-border-color:            #e5e5e5;
+//
+// $input-group-addon-bg:           $gray-lighter;
+// $input-group-addon-border-color: $input-border;
+//
+//
+// // Dropdowns
+// // -------------------------
+//
+// $dropdown-bg:                    #fff;
+// $dropdown-border:                rgba(0,0,0,.15);
+// $dropdown-fallback-border:       #ccc;
+// $dropdown-divider-bg:            #e5e5e5;
+//
+$dropdown-link-color:            $gray-dark;
+$dropdown-link-hover-color:      darken($gray-dark, 5%);
+$dropdown-link-hover-bg:         #f5f5f5;
+//
+// $dropdown-link-active-color:     $component-active-color;
+// $dropdown-link-active-bg:        $component-active-bg;
+//
+// $dropdown-link-disabled-color:   $gray-light;
+//
+// $dropdown-header-color:          $gray-light;
+//
+// $dropdown-caret-color:           #000;
+//
+//
+// // COMPONENT VARIABLES
+// // --------------------------------------------------
+//
+//
+// // Z-index master list
+// // -------------------------
+// // Used for a bird's eye view of components dependent on the z-axis
+// // Try to avoid customizing these :)
+//
+// $zindex-navbar:            1000;
+// $zindex-dropdown:          1000;
+// $zindex-popover:           1010;
+// $zindex-tooltip:           1030;
+// $zindex-navbar-fixed:      1030;
+// $zindex-modal-background:  1040;
+// $zindex-modal:             1050;
+//
+// // Media queries breakpoints
+// // --------------------------------------------------
+//
+// // Extra small screen / phone
+// // Note: Deprecated $screen-xs and $screen-phone as of v3.0.1
+// $screen-xs:                  480px;
+// $screen-xs-min:              $screen-xs;
+// $screen-phone:               $screen-xs-min;
+//
+// // Small screen / tablet
+// // Note: Deprecated $screen-sm and $screen-tablet as of v3.0.1
+// $screen-sm:                  768px;
+// $screen-sm-min:              $screen-sm;
+// $screen-tablet:              $screen-sm-min;
+//
+// // Medium screen / desktop
+// // Note: Deprecated $screen-md and $screen-desktop as of v3.0.1
+// $screen-md:                  992px;
+// $screen-md-min:              $screen-md;
+// $screen-desktop:             $screen-md-min;
+//
+// // Large screen / wide desktop
+// // Note: Deprecated $screen-lg and $screen-lg-desktop as of v3.0.1
+// $screen-lg:                  1200px;
+// $screen-lg-min:              $screen-lg;
+// $screen-lg-desktop:          $screen-lg-min;
+//
+// // So media queries don't overlap when required, provide a maximum
+// $screen-xs-max:              ($screen-sm-min - 1);
+// $screen-sm-max:              ($screen-md-min - 1);
+// $screen-md-max:              ($screen-lg-min - 1);
+//
+//
+// // Grid system
+// // --------------------------------------------------
+//
+// // Number of columns in the grid system
+// $grid-columns:              12;
+// // Padding, to be divided by two and applied to the left and right of all columns
+// $grid-gutter-width:         30px;
+// // Point at which the navbar stops collapsing
+// $grid-float-breakpoint:     $screen-sm-min;
+//
+//
+// // Navbar
+// // -------------------------
+//
+// // Basics of a navbar
+// $navbar-height:                    50px;
+// $navbar-margin-bottom:             $line-height-computed;
+// $navbar-border-radius:             $border-radius-base;
+// $navbar-padding-horizontal:        floor($grid-gutter-width / 2);
+// $navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2);
+//
+// $navbar-default-color:             #777;
+// $navbar-default-bg:                #f8f8f8;
+// $navbar-default-border:            darken($navbar-default-bg, 6.5%);
+//
+// // Navbar links
+// $navbar-default-link-color:                #777;
+// $navbar-default-link-hover-color:          #333;
+// $navbar-default-link-hover-bg:             transparent;
+// $navbar-default-link-active-color:         #555;
+// $navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%);
+// $navbar-default-link-disabled-color:       #ccc;
+// $navbar-default-link-disabled-bg:          transparent;
+//
+// // Navbar brand label
+// $navbar-default-brand-color:               $navbar-default-link-color;
+// $navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%);
+// $navbar-default-brand-hover-bg:            transparent;
+//
+// // Navbar toggle
+// $navbar-default-toggle-hover-bg:           #ddd;
+// $navbar-default-toggle-icon-bar-bg:        #ccc;
+// $navbar-default-toggle-border-color:       #ddd;
+//
+//
+// // Inverted navbar
+// //
+// // Reset inverted navbar basics
+// $navbar-inverse-color:                      $gray-light;
+// $navbar-inverse-bg:                         #222;
+// $navbar-inverse-border:                     darken($navbar-inverse-bg, 10%);
+//
+// // Inverted navbar links
+// $navbar-inverse-link-color:                 $gray-light;
+// $navbar-inverse-link-hover-color:           #fff;
+// $navbar-inverse-link-hover-bg:              transparent;
+// $navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color;
+// $navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 10%);
+// $navbar-inverse-link-disabled-color:        #444;
+// $navbar-inverse-link-disabled-bg:           transparent;
+//
+// // Inverted navbar brand label
+// $navbar-inverse-brand-color:                $navbar-inverse-link-color;
+// $navbar-inverse-brand-hover-color:          #fff;
+// $navbar-inverse-brand-hover-bg:             transparent;
+//
+// // Inverted navbar toggle
+// $navbar-inverse-toggle-hover-bg:            #333;
+// $navbar-inverse-toggle-icon-bar-bg:         #fff;
+// $navbar-inverse-toggle-border-color:        #333;
+//
+//
+// // Navs
+// // -------------------------
+//
+// $nav-link-padding:                          10px 15px;
+// $nav-link-hover-bg:                         $gray-lighter;
+//
+// $nav-disabled-link-color:                   $gray-light;
+// $nav-disabled-link-hover-color:             $gray-light;
+//
+// $nav-open-link-hover-color:                 #fff;
+// $nav-open-caret-border-color:               #fff;
+//
+// // Tabs
+// $nav-tabs-border-color:                     #ddd;
+//
+// $nav-tabs-link-hover-border-color:          $gray-lighter;
+//
+// $nav-tabs-active-link-hover-bg:             $body-bg;
+// $nav-tabs-active-link-hover-color:          $gray;
+// $nav-tabs-active-link-hover-border-color:   #ddd;
+//
+// $nav-tabs-justified-link-border-color:            #ddd;
+// $nav-tabs-justified-active-link-border-color:     $body-bg;
+//
+// // Pills
+// $nav-pills-border-radius:                   $border-radius-base;
+// $nav-pills-active-link-hover-bg:            $component-active-bg;
+// $nav-pills-active-link-hover-color:         $component-active-color;
+//
+//
+// // Pagination
+// // -------------------------
+//
+// $pagination-bg:                        #fff;
+// $pagination-border:                    #ddd;
+//
+// $pagination-hover-bg:                  $gray-lighter;
+//
+// $pagination-active-bg:                 $brand-primary;
+// $pagination-active-color:              #fff;
+//
+// $pagination-disabled-color:            $gray-light;
+//
+//
+// // Pager
+// // -------------------------
+//
+// $pager-border-radius:                  15px;
+// $pager-disabled-color:                 $gray-light;
+//
+//
+// // Jumbotron
+// // -------------------------
+//
+// $jumbotron-padding:              30px;
+// $jumbotron-color:                inherit;
+// $jumbotron-bg:                   $gray-lighter;
+// $jumbotron-heading-color:        inherit;
+// $jumbotron-font-size:            ceil($font-size-base * 1.5);
+//
+//
+// // Form states and alerts
+// // -------------------------
+//
+// $state-success-text:             #468847;
+// $state-success-bg:               #dff0d8;
+// $state-success-border:           darken(spin($state-success-bg, -10), 5%);
+//
+// $state-info-text:                #3a87ad;
+// $state-info-bg:                  #d9edf7;
+// $state-info-border:              darken(spin($state-info-bg, -10), 7%);
+//
+// $state-warning-text:             #c09853;
+// $state-warning-bg:               #fcf8e3;
+// $state-warning-border:           darken(spin($state-warning-bg, -10), 5%);
+//
+// $state-danger-text:              #b94a48;
+// $state-danger-bg:                #f2dede;
+// $state-danger-border:            darken(spin($state-danger-bg, -10), 5%);
+//
+//
+// // Tooltips
+// // -------------------------
+// $tooltip-max-width:           200px;
+// $tooltip-color:               #fff;
+// $tooltip-bg:                  #000;
+//
+// $tooltip-arrow-width:         5px;
+// $tooltip-arrow-color:         $tooltip-bg;
+//
+//
+// // Popovers
+// // -------------------------
+// $popover-bg:                          #fff;
+// $popover-max-width:                   276px;
+// $popover-border-color:                rgba(0,0,0,.2);
+// $popover-fallback-border-color:       #ccc;
+//
+// $popover-title-bg:                    darken($popover-bg, 3%);
+//
+// $popover-arrow-width:                 10px;
+// $popover-arrow-color:                 #fff;
+//
+// $popover-arrow-outer-width:           ($popover-arrow-width + 1);
+// $popover-arrow-outer-color:           rgba(0,0,0,.25);
+// $popover-arrow-outer-fallback-color:  #999;
+//
+//
+// // Labels
+// // -------------------------
+//
+// $label-default-bg:            $gray-light;
+// $label-primary-bg:            $brand-primary;
+// $label-success-bg:            $brand-success;
+// $label-info-bg:               $brand-info;
+// $label-warning-bg:            $brand-warning;
+// $label-danger-bg:             $brand-danger;
+//
+// $label-color:                 #fff;
+// $label-link-hover-color:      #fff;
+//
+//
+// // Modals
+// // -------------------------
+// $modal-inner-padding:         20px;
+//
+// $modal-title-padding:         15px;
+// $modal-title-line-height:     $line-height-base;
+//
+// $modal-content-bg:                             #fff;
+// $modal-content-border-color:                   rgba(0,0,0,.2);
+// $modal-content-fallback-border-color:          #999;
+//
+// $modal-backdrop-bg:           #000;
+// $modal-header-border-color:   #e5e5e5;
+// $modal-footer-border-color:   $modal-header-border-color;
+//
+//
+// // Alerts
+// // -------------------------
+// $alert-padding:               15px;
+// $alert-border-radius:         $border-radius-base;
+// $alert-link-font-weight:      bold;
+//
+// $alert-success-bg:            $state-success-bg;
+// $alert-success-text:          $state-success-text;
+// $alert-success-border:        $state-success-border;
+//
+// $alert-info-bg:               $state-info-bg;
+// $alert-info-text:             $state-info-text;
+// $alert-info-border:           $state-info-border;
+//
+// $alert-warning-bg:            $state-warning-bg;
+// $alert-warning-text:          $state-warning-text;
+// $alert-warning-border:        $state-warning-border;
+//
+// $alert-danger-bg:             $state-danger-bg;
+// $alert-danger-text:           $state-danger-text;
+// $alert-danger-border:         $state-danger-border;
+//
+//
+// // Progress bars
+// // -------------------------
+// $progress-bg:                 #f5f5f5;
+// $progress-bar-color:          #fff;
+//
+// $progress-bar-bg:             $brand-primary;
+// $progress-bar-success-bg:     $brand-success;
+// $progress-bar-warning-bg:     $brand-warning;
+// $progress-bar-danger-bg:      $brand-danger;
+// $progress-bar-info-bg:        $brand-info;
+//
+//
+// // List group
+// // -------------------------
+// $list-group-bg:               #fff;
+// $list-group-border:           #ddd;
+// $list-group-border-radius:    $border-radius-base;
+//
+// $list-group-hover-bg:         #f5f5f5;
+// $list-group-active-color:     $component-active-color;
+// $list-group-active-bg:        $component-active-bg;
+// $list-group-active-border:    $list-group-active-bg;
+//
+// $list-group-link-color:          #555;
+// $list-group-link-heading-color:  #333;
+//
+//
+// // Panels
+// // -------------------------
+// $panel-bg:                    #fff;
+// $panel-inner-border:          #ddd;
+// $panel-border-radius:         $border-radius-base;
+// $panel-footer-bg:             #f5f5f5;
+//
+// $panel-default-text:          $gray-dark;
+// $panel-default-border:        #ddd;
+// $panel-default-heading-bg:    #f5f5f5;
+//
+// $panel-primary-text:          #fff;
+// $panel-primary-border:        $brand-primary;
+// $panel-primary-heading-bg:    $brand-primary;
+//
+// $panel-success-text:          $state-success-text;
+// $panel-success-border:        $state-success-border;
+// $panel-success-heading-bg:    $state-success-bg;
+//
+// $panel-warning-text:          $state-warning-text;
+// $panel-warning-border:        $state-warning-border;
+// $panel-warning-heading-bg:    $state-warning-bg;
+//
+// $panel-danger-text:           $state-danger-text;
+// $panel-danger-border:         $state-danger-border;
+// $panel-danger-heading-bg:     $state-danger-bg;
+//
+// $panel-info-text:             $state-info-text;
+// $panel-info-border:           $state-info-border;
+// $panel-info-heading-bg:       $state-info-bg;
+//
+//
+// // Thumbnails
+// // -------------------------
+// $thumbnail-padding:           4px;
+// $thumbnail-bg:                $body-bg;
+// $thumbnail-border:            #ddd;
+// $thumbnail-border-radius:     $border-radius-base;
+//
+// $thumbnail-caption-color:     $text-color;
+// $thumbnail-caption-padding:   9px;
+//
+//
+// // Wells
+// // -------------------------
+// $well-bg:                     #f5f5f5;
+//
+//
+// // Badges
+// // -------------------------
+// $badge-color:                 #fff;
+// $badge-link-hover-color:      #fff;
+// $badge-bg:                    $gray-light;
+//
+// $badge-active-color:          $link-color;
+// $badge-active-bg:             #fff;
+//
+// $badge-font-weight:           bold;
+// $badge-line-height:           1;
+// $badge-border-radius:         10px;
+//
+//
+// // Breadcrumbs
+// // -------------------------
+// $breadcrumb-bg:               #f5f5f5;
+// $breadcrumb-color:            #ccc;
+// $breadcrumb-active-color:     $gray-light;
+// $breadcrumb-separator:        "/";
+//
+//
+// // Carousel
+// // ------------------------
+//
+// $carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);
+//
+// $carousel-control-color:                      #fff;
+// $carousel-control-width:                      15%;
+// $carousel-control-opacity:                    .5;
+// $carousel-control-font-size:                  20px;
+//
+// $carousel-indicator-active-bg:                #fff;
+// $carousel-indicator-border-color:             #fff;
+//
+// $carousel-caption-color:                      #fff;
+//
+//
+// // Close
+// // ------------------------
+// $close-font-weight:           bold;
+// $close-color:                 #000;
+// $close-text-shadow:           0 1px 0 #fff;
+//
+//
+// // Code
+// // ------------------------
+// $code-color:                  #c7254e;
+// $code-bg:                     #f9f2f4;
+//
+// $pre-bg:                      #f5f5f5;
+// $pre-color:                   $gray-dark;
+// $pre-border-color:            #ccc;
+// $pre-scrollable-max-height:   340px;
+//
+// // Type
+// // ------------------------
+// $text-muted:                  $gray-light;
+// $abbr-border-color:           $gray-light;
+// $headings-small-color:        $gray-light;
+// $blockquote-small-color:      $gray-light;
+// $blockquote-border-color:     $gray-lighter;
+// $page-header-border-color:    $gray-lighter;
+//
+// // Miscellaneous
+// // -------------------------
+//
+// // Hr border color
+// $hr-border:                   $gray-lighter;
+//
+// // Horizontal forms & lists
+// $component-offset-horizontal: 180px;
+//
+//
+// // Container sizes
+// // --------------------------------------------------
+//
+// // Small screen / tablet
+// $container-tablet:             ((720px + $grid-gutter-width));
+// $container-sm:                 $container-tablet;
+//
+// // Medium screen / desktop
+// $container-desktop:            ((940px + $grid-gutter-width));
+// $container-md:                 $container-desktop;
+//
+// // Large screen / wide desktop
+// $container-large-desktop:      ((1140px + $grid-gutter-width));
+// $container-lg:                 $container-large-desktop;
+
+
+//
+// mixins
+//
+
+// Badget
+@mixin badge-variant($color) {
+  background-color: $color;
+
+  &[href] {
+    &:hover,
+    &:focus {
+      background-color: darken($color, 10%);
+    }
+  }
+}

+ 1 - 4
resource/css/crowi.scss

@@ -1,15 +1,12 @@
 // import crowi variable
-@import 'variables';
+@import 'utilities';
 
 // import bootstrap
 @import 'bootstrap';
 
 @import 'font-awesome';
 
-@import 'mixins';
-
 // crowi component
-@import 'mixins';
 @import 'layout';
 @import 'form';
 @import 'wiki';

+ 2 - 3
test/models/config.test.js

@@ -38,9 +38,8 @@ describe('Config model test', function () {
 
   after(function (done) {
     if (mongoUri) {
-      testDBUtil.cleanUpDb(conn, 'Config', function(err, doc) {
-        conn.close();
-        done();
+      return testDBUtil.cleanUpDb(conn, 'Config', function(err, doc) {
+        return conn.close(done);
       });
     }
   });

+ 2 - 3
test/models/page.test.js

@@ -59,9 +59,8 @@ describe('Page', function () {
   });
 
   after(function (done) {
-    testDBUtil.cleanUpDb(conn, 'Page', function(err, doc) {
-      conn.close();
-      done();
+    return testDBUtil.cleanUpDb(conn, 'Page', function(err, doc) {
+      return conn.close(done);
     });
   });