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

Merge pull request #13 from crowi/wip-v1.1.1

v1.1.1
Sotaro KARASAWA 11 лет назад
Родитель
Сommit
466ebfd3ca

+ 6 - 0
CHANGES.md

@@ -1,6 +1,12 @@
 CHANGES
 CHANGES
 ========
 ========
 
 
+## 1.1.1
+
+* Fix: Error on accessing restricted page.
+* Fix: JS Error when section title includes colon.
+* Fix: Typo on Facebook setting page (Facebook setting is now available).
+* Fix and Feature: Add creator property to Page Object and show creator info in sidebar instead of last update user.
 
 
 ## 1.1.0
 ## 1.1.0
 
 

+ 38 - 22
Gruntfile.js

@@ -32,11 +32,12 @@ module.exports = function(grunt) {
           outputStyle: 'nested',
           outputStyle: 'nested',
           includePaths: [
           includePaths: [
             'bower_components/bootstrap-sass-official/assets/stylesheets',
             'bower_components/bootstrap-sass-official/assets/stylesheets',
-            'bower_components/fontawesome/scss'
+            'bower_components/fontawesome/scss',
+            'bower_components/reveal.js/css'
           ]
           ]
         },
         },
         files: {
         files: {
-          '<%= dirs.cssDest %>/<%= pkg.name %>.css': '<%= dirs.css %>/<%= pkg.name %>.scss',
+          '<%= dirs.cssDest %>/<%= pkg.name %>-main.css': '<%= dirs.css %>/<%= pkg.name %>.scss',
           '<%= dirs.cssDest %>/<%= pkg.name %>-reveal.css': '<%= dirs.css %>/<%= pkg.name %>-reveal.scss'
           '<%= dirs.cssDest %>/<%= pkg.name %>-reveal.css': '<%= dirs.css %>/<%= pkg.name %>-reveal.scss'
         }
         }
       },
       },
@@ -45,43 +46,58 @@ module.exports = function(grunt) {
           outputStyle: 'compressed',
           outputStyle: 'compressed',
           includePaths: [
           includePaths: [
             'bower_components/bootstrap-sass-official/assets/stylesheets',
             'bower_components/bootstrap-sass-official/assets/stylesheets',
-            'bower_components/fontawesome/scss'
+            'bower_components/fontawesome/scss',
+            'bower_components/reveal.js/css'
           ]
           ]
         },
         },
         files: {
         files: {
-          '<%= dirs.cssDest %>/<%= pkg.name %>.min.css': '<%= dirs.css %>/<%= pkg.name %>.scss',
+          '<%= 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'
           '<%= dirs.cssDest %>/<%= pkg.name %>-reveal.min.css': '<%= dirs.css %>/<%= pkg.name %>-reveal.scss'
         }
         }
       }
       }
     },
     },
     concat: {
     concat: {
       dist: {
       dist: {
-        src: [
-          // Bootstrap
-          'bower_components/bootstrap-sass-official/assets/javascripts/bootstrap.js',
-          // socket.io
-          'node_modules/socket.io-client/dist/socket.io.js',
-          // markd
-          'node_modules/marked/lib/marked.js',
-          // jquery.cookie
-          'node_modules/jquery.cookie/jquery.cookie.js',
-          // crowi
-          'resource/js/crowi.js'
-        ],
-        dest: '<%= dirs.jsDest %>/<%= pkg.name %>.js'
-      }
+        files: {
+          '<%= dirs.cssDest %>/<%= pkg.name %>.css': [
+            'bower_components/highlightjs/styles/default.css',
+            '<%= dirs.cssDest %>/<%= pkg.name %>-main.css',
+          ],
+          '<%= dirs.cssDest %>/<%= pkg.name %>.min.css': [
+            'bower_components/highlightjs/styles/default.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/dist/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: {
     uglify: {
       build: {
       build: {
-        src: '<%= concat.dist.dest %>',
-        dest: '<%= dirs.jsDest %>/<%= pkg.name %>.min.js'
+        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: {
     jshint: {
       options: {
       options: {
         jshintrc: true
         jshintrc: true
       },
       },
-      all: ['Gruntfile.js', 'lib/**/*.js', 'models/**/*.js', 'routes/**/*.js', 'form/**/*.js', 'resource/js/**/*.js']
+      all: paths.scripts
     },
     },
     watch: {
     watch: {
       css: {
       css: {
@@ -109,6 +125,6 @@ module.exports = function(grunt) {
 
 
   // grunt watch dev
   // grunt watch dev
   grunt.registerTask('default', ['sass', 'concat', 'uglify']);
   grunt.registerTask('default', ['sass', 'concat', 'uglify']);
-  grunt.registerTask('dev', ['jshint', 'sass:dev', 'concat']);
+  grunt.registerTask('dev', ['sass:dev', 'concat', 'jshint']);
 
 
 };
 };

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Sotaro KARASAWA <sotaro.k@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 3 - 22
README.md

@@ -40,7 +40,7 @@ Start Up on Local
 Crowi is designed setting up to Heroku or some PaaS, but you can start up Crowi with ENV parameter on your local.
 Crowi is designed setting up to Heroku or some PaaS, but you can start up Crowi with ENV parameter on your local.
 
 
 ```
 ```
-$ PASSWORD_SEED=somesecretstring MONGOHQ_URL=mongodb://username:password@localhost/crowi node app.js
+$ PASSWORD_SEED=somesecretstring MONGO_URI=mongodb://username:password@localhost/crowi node app.js
 ```
 ```
 
 
 ### Environment
 ### Environment
@@ -57,24 +57,5 @@ $ PASSWORD_SEED=somesecretstring MONGOHQ_URL=mongodb://username:password@localho
 License
 License
 ---------
 ---------
 
 
-> The MIT License (MIT)
->
-> Copyright (c) 2013 Sotaro KARASAWA <sotaro.k@gmail.com>
->
-> Permission is hereby granted, free of charge, to any person obtaining a copy
-> of this software and associated documentation files (the "Software"), to deal
-> in the Software without restriction, including without limitation the rights
-> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-> copies of the Software, and to permit persons to whom the Software is
-> furnished to do so, subject to the following conditions:
->
-> The above copyright notice and this permission notice shall be included in
-> all copies or substantial portions of the Software.
->
-> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-> THE SOFTWARE.
+* The MIT License (MIT)
+* See LICENSE file.

+ 0 - 22
TODO

@@ -1,22 +0,0 @@
-TODO
-=====
-
-* ~~User create~~
-* ~~Page edit~~
-* ~~List view~~
-* ~~Page title as a separated link~~
-* ~~Page fromatter~~
-    * ~~Text (auto link, auto image expand)~~
-* ~~Timeline list view~~
-* Page move
-* Page copy
-* Page fromatter
-    * ~~Hatena~~
-    * ~~Markdown~~
-* Search
-* Pagination
-* Realtime preview on page edit
-* Page revert (from history)
-* History diff view
-* Ajax edit
-* Live edit

+ 19 - 14
app.js

@@ -19,6 +19,7 @@ var express  = require('express')
   , session  = require('express-session')
   , session  = require('express-session')
   , models
   , models
   , config
   , config
+  , configModel
   , server
   , server
   , sessionConfig
   , sessionConfig
   , RedisStore
   , RedisStore
@@ -31,10 +32,11 @@ var env = app.get('env');
 var days = (1000*3600*24*30);
 var days = (1000*3600*24*30);
 
 
 // mongoUri = mongodb://user:password@host/dbname
 // mongoUri = mongodb://user:password@host/dbname
-var mongoUri = process.env.MONGOLAB_URI
-  || process.env.MONGOHQ_URL
-  || process.env.MONGO_URI
-  || 'mongodb://localhost/crowi';
+var mongoUri = process.env.MONGOLAB_URI ||
+  process.env.MONGOHQ_URL ||
+  process.env.MONGO_URI ||
+  'mongodb://localhost/crowi'
+  ;
 
 
 mongo.connect(mongoUri);
 mongo.connect(mongoUri);
 
 
@@ -47,16 +49,16 @@ sessionConfig = {
     maxAge: days,
     maxAge: days,
   },
   },
 };
 };
-var redisUrl = process.env.REDISTOGO_URL
-  || process.env.REDIS_URL
-  || null;
+var redisUrl = process.env.REDISTOGO_URL ||
+  process.env.REDIS_URL ||
+  null;
 
 
 if (redisUrl) {
 if (redisUrl) {
-  var ru   = require("url").parse(redisUrl);
-  var redis = require("redis");
+  var ru   = require('url').parse(redisUrl);
+  var redis = require('redis');
   var redisClient = redis.createClient(ru.port, ru.hostname);
   var redisClient = redis.createClient(ru.port, ru.hostname);
   if (ru.auth) {
   if (ru.auth) {
-    redisClient.auth(ru.auth.split(":")[1]);
+    redisClient.auth(ru.auth.split(':')[1]);
   }
   }
 
 
   RedisStore = require('connect-redis')(session);
   RedisStore = require('connect-redis')(session);
@@ -89,7 +91,10 @@ async.series([
       return next();
       return next();
     });
     });
   }, function (next) {
   }, function (next) {
-    var config = app.set('config');
+    var config = app.set('config')
+      , tzoffset
+      ;
+
 
 
     app.set('mailer', require('./lib/mailer')(app));
     app.set('mailer', require('./lib/mailer')(app));
 
 
@@ -107,7 +112,7 @@ async.series([
 
 
       req.config = config;
       req.config = config;
 
 
-      config.crowi['app:url'] = req.baseUrl = (req.headers['x-forwarded-proto'] == 'https' ? 'https' : req.protocol) + "://" + req.get('host');
+      config.crowi['app:url'] = req.baseUrl = (req.headers['x-forwarded-proto'] == 'https' ? 'https' : req.protocol) + '://' + req.get('host');
       res.locals({
       res.locals({
         req: req,
         req: req,
         baseUrl: req.baseUrl,
         baseUrl: req.baseUrl,
@@ -164,7 +169,7 @@ async.series([
       app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
       app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
 
 
       server = http.createServer(app).listen(app.get('port'), function(){
       server = http.createServer(app).listen(app.get('port'), function(){
-        console.log("[" + app.get('env') + "] Express server listening on port " + app.get('port'));
+        console.log('[' + app.get('env') + '] Express server listening on port ' + app.get('port'));
       });
       });
     }
     }
 
 
@@ -176,7 +181,7 @@ async.series([
       });
       });
 
 
       server = http.createServer(app).listen(app.get('port'), function(){
       server = http.createServer(app).listen(app.get('port'), function(){
-        console.log("[" + app.get('env') + "] Express server listening on port " + app.get('port'));
+        console.log('[' + app.get('env') + '] Express server listening on port ' + app.get('port'));
       });
       });
     }
     }
 
 

+ 7 - 2
bower.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "crowi",
   "name": "crowi",
-  "version": "1.1.0",
+  "version": "1.1.1",
   "description": "Crocos' Wiki implementation in node.js",
   "description": "Crocos' Wiki implementation in node.js",
   "authors": [
   "authors": [
     "Sotaro KARASAWA <sotarok@crocos.co.jp>",
     "Sotaro KARASAWA <sotarok@crocos.co.jp>",
@@ -20,6 +20,11 @@
   ],
   ],
   "dependencies": {
   "dependencies": {
     "bootstrap-sass-official": "~3.3.1",
     "bootstrap-sass-official": "~3.3.1",
-    "fontawesome": "~4.2.0"
+    "fontawesome": "~4.2.0",
+    "jquery.cookie": "~1.4.1",
+    "marked": "~0.3.3",
+    "reveal.js": "~3.0.0",
+    "jquery": "~2.1.3",
+    "highlightjs": "~8.4.0"
   }
   }
 }
 }

+ 2 - 2
form/admin/fb.js

@@ -4,7 +4,7 @@ var form = require('express-form')
   , field = form.field;
   , field = form.field;
 
 
 module.exports = form(
 module.exports = form(
-  field('settingForm[fb:appId]').trim().is(/^\d+$/),
-  field('settingForm[fb:seret]').trim().is(/^[\da-z]+$/)
+  field('settingForm[facebook:appId]').trim().is(/^\d+$/),
+  field('settingForm[facebook:secret]').trim().is(/^[\da-z]+$/)
 );
 );
 
 

+ 3 - 7
lib/mailer.js

@@ -52,7 +52,7 @@ module.exports = function(app) {
     }
     }
 
 
     var ses = require('nodemailer-ses-transport');
     var ses = require('nodemailer-ses-transport');
-    var client = nodemailer.createTransport(ses(option));
+    client = nodemailer.createTransport(ses(option));
 
 
     debug('mailer setted up for SES', client);
     debug('mailer setted up for SES', client);
     return client;
     return client;
@@ -64,16 +64,12 @@ module.exports = function(app) {
       return;
       return;
     }
     }
 
 
-    if (config.crowi['mail:smtpUser']
-        && config.crowi['mail:smtpPassword']
-        && config.crowi['mail:smtpHost']
-        && config.crowi['mail:smtpPort']
+    if (config.crowi['mail:smtpUser'] && config.crowi['mail:smtpPassword'] && config.crowi['mail:smtpHost'] && config.crowi['mail:smtpPort']
       ) {
       ) {
       // SMTP 設定がある場合はそれを優先
       // SMTP 設定がある場合はそれを優先
       mailer = createSMTPClient();
       mailer = createSMTPClient();
 
 
-    } else if (config.crowi['aws:accessKeyId']
-      && config.crowi['aws:secretAccessKey']) {
+    } else if (config.crowi['aws:accessKeyId'] && config.crowi['aws:secretAccessKey']) {
       // AWS 設定がある場合はSESを設定
       // AWS 設定がある場合はSESを設定
       mailer = createSESClient();
       mailer = createSESClient();
     } else {
     } else {

+ 7 - 10
lib/middlewares.js

@@ -1,5 +1,4 @@
-var debug = require('debug')('crowi:lib:middlewares')
-  ;
+var debug = require('debug')('crowi:lib:middlewares');
 
 
 exports.loginChecker = function(app, models) {
 exports.loginChecker = function(app, models) {
   return function(req, res, next) {
   return function(req, res, next) {
@@ -7,7 +6,7 @@ exports.loginChecker = function(app, models) {
     if (req.session.user && '_id' in req.session.user) {
     if (req.session.user && '_id' in req.session.user) {
       models.User.findById(req.session.user._id, function(err, userData) {
       models.User.findById(req.session.user._id, function(err, userData) {
         if (err) {
         if (err) {
-          next()
+          next();
         } else {
         } else {
           req.user = req.session.user = userData;
           req.user = req.session.user = userData;
           res.locals({user: req.user});
           res.locals({user: req.user});
@@ -38,13 +37,15 @@ exports.swigFilters = function(app, swig) {
 
 
     swig.setFilter('datetz', function(input, format) {
     swig.setFilter('datetz', function(input, format) {
       // timezone
       // timezone
-      var swigFilters = require('swig/lib/filters')
+      var swigFilters = require('swig/lib/filters');
       return swigFilters.date(input, format, app.get('tzoffset'));
       return swigFilters.date(input, format, app.get('tzoffset'));
     });
     });
 
 
     swig.setFilter('presentation', function(string) {
     swig.setFilter('presentation', function(string) {
       // 手抜き
       // 手抜き
-      return string.replace(/[\n]+#/g, '\n\n\n#');
+      return string
+        .replace(/[\n]+#/g, '\n\n\n#')
+        .replace(/\s(https?.+(jpe?g|png|gif))\s/, '\n\n\n![]($1)\n\n\n');
     });
     });
 
 
     swig.setFilter('picture', function(user) {
     swig.setFilter('picture', function(user) {
@@ -130,11 +131,7 @@ exports.applicationInstalled = function() {
 exports.awsEnabled = function() {
 exports.awsEnabled = function() {
   return function (req, res, next) {
   return function (req, res, next) {
     var config = req.config;
     var config = req.config;
-    if (config.crowi['aws:region'] != ''
-        && config.crowi['aws:bucket'] != ''
-        && config.crowi['aws:accessKeyId'] != ''
-        && config.crowi['aws:secretAccessKey'] != ''
-       ) {
+    if (config.crowi['aws:region'] !== '' && config.crowi['aws:bucket'] !== '' && config.crowi['aws:accessKeyId'] !== '' && config.crowi['aws:secretAccessKey'] !== '') {
       req.flash('globalError', 'AWS settings required to use this function. Please ask the administrator.');
       req.flash('globalError', 'AWS settings required to use this function. Please ask the administrator.');
       return res.redirect('/');
       return res.redirect('/');
     }
     }

+ 1 - 0
models/bookmark.js

@@ -4,6 +4,7 @@ module.exports = function(app, models) {
     , ObjectId = mongoose.Schema.Types.ObjectId
     , ObjectId = mongoose.Schema.Types.ObjectId
     , bookmarkSchema;
     , bookmarkSchema;
 
 
+
   bookmarkSchema = new mongoose.Schema({
   bookmarkSchema = new mongoose.Schema({
     page: { type: ObjectId, ref: 'Page', index: true },
     page: { type: ObjectId, ref: 'Page', index: true },
     user: { type: ObjectId, ref: 'User', index: true },
     user: { type: ObjectId, ref: 'User', index: true },

+ 23 - 8
models/page.js

@@ -10,20 +10,21 @@ module.exports = function(app, models) {
     , pageSchema;
     , pageSchema;
 
 
   function populatePageData(pageData, revisionId, callback) {
   function populatePageData(pageData, revisionId, callback) {
-    debug('pageData', pageData.revision);
     if (revisionId) {
     if (revisionId) {
       pageData.revision = revisionId;
       pageData.revision = revisionId;
     }
     }
 
 
     pageData.latestRevision = pageData.revision;
     pageData.latestRevision = pageData.revision;
+    pageData.likerCount = pageData.liker.length || 0;
+    pageData.seenUsersCount = pageData.seenUsers.length || 0;
+
     pageData.populate([
     pageData.populate([
+      {path: 'creator', model: 'User'},
       {path: 'revision', model: 'Revision'},
       {path: 'revision', model: 'Revision'},
       {path: 'liker', options: { limit: 11 }},
       {path: 'liker', options: { limit: 11 }},
       {path: 'seenUsers', options: { limit: 11 }},
       {path: 'seenUsers', options: { limit: 11 }},
     ], function (err, pageData) {
     ], function (err, pageData) {
-      models.Page.populate(pageData, {path: 'revision.author', model: 'User'}, function(err, pageData) {
-        return callback(err, pageData);
-      });
+      models.Page.populate(pageData, {path: 'revision.author', model: 'User'}, callback);
     });
     });
   }
   }
 
 
@@ -33,6 +34,7 @@ module.exports = function(app, models) {
     redirectTo: { type: String, index: true },
     redirectTo: { type: String, index: true },
     grant: { type: Number, default: GRANT_PUBLIC, index: true },
     grant: { type: Number, default: GRANT_PUBLIC, index: true },
     grantedUsers: [{ type: ObjectId, ref: 'User' }],
     grantedUsers: [{ type: ObjectId, ref: 'User' }],
+    creator: { type: ObjectId, ref: 'User', index: true },
     liker: [{ type: ObjectId, ref: 'User', index: true }],
     liker: [{ type: ObjectId, ref: 'User', index: true }],
     seenUsers: [{ type: ObjectId, ref: 'User', index: true }],
     seenUsers: [{ type: ObjectId, ref: 'User', index: true }],
     createdAt: { type: Date, default: Date.now },
     createdAt: { type: Date, default: Date.now },
@@ -221,19 +223,31 @@ module.exports = function(app, models) {
       });
       });
   };
   };
 
 
-  pageSchema.statics.findPageById = function(id, userData, cb) {
+  pageSchema.statics.findPageById = function(id, cb) {
     var Page = this;
     var Page = this;
 
 
-    this.findOne({_id: id}, function(err, pageData) {
+    Page.findOne({_id: id}, function(err, pageData) {
       if (pageData === null) {
       if (pageData === null) {
         return cb(new Error('Page Not Found'), null);
         return cb(new Error('Page Not Found'), null);
       }
       }
 
 
-      if (!pageData.isGrantedFor(userData)) {
+      return populatePageData(pageData, null, cb);
+    });
+  };
+
+  pageSchema.statics.findPageByIdAndGrantedUser = function(id, userData, cb) {
+    var Page = this;
+
+    Page.findPageById(id, function(err, pageData) {
+      if (pageData === null) {
+        return cb(new Error('Page Not Found'), null);
+      }
+
+      if (userData && !pageData.isGrantedFor(userData)) {
         return cb(PAGE_GRANT_ERROR, null);
         return cb(PAGE_GRANT_ERROR, null);
       }
       }
 
 
-      return populatePageData(pageData, null, cb);
+      return cb(null,pageData);
     });
     });
   };
   };
 
 
@@ -353,6 +367,7 @@ module.exports = function(app, models) {
 
 
       var newPage = new Page();
       var newPage = new Page();
       newPage.path = path;
       newPage.path = path;
+      newPage.creator = user;
       newPage.createdAt = Date.now();
       newPage.createdAt = Date.now();
       newPage.updatedAt = Date.now();
       newPage.updatedAt = Date.now();
       newPage.redirectTo = redirectTo;
       newPage.redirectTo = redirectTo;

+ 12 - 12
package.json

@@ -1,9 +1,12 @@
 {
 {
   "name": "crowi",
   "name": "crowi",
-  "version": "1.1.0",
+  "version": "1.1.1",
   "description": "The simple & powerful Wiki",
   "description": "The simple & powerful Wiki",
   "tags": [
   "tags": [
-    "wiki", "communication", "documentation", "collaboration"
+    "wiki",
+    "communication",
+    "documentation",
+    "collaboration"
   ],
   ],
   "author": "Sotaro KARASAWA <sotaro.k@gmail.com>",
   "author": "Sotaro KARASAWA <sotaro.k@gmail.com>",
   "contributors": [
   "contributors": [
@@ -15,12 +18,12 @@
   },
   },
   "engines": {
   "engines": {
     "node": "0.10.x",
     "node": "0.10.x",
-    "npm": "1.3.x"
+    "npm": "2.4.x"
   },
   },
   "dependencies": {
   "dependencies": {
     "async": "~0.9.0",
     "async": "~0.9.0",
     "aws-sdk": "~2.0.0-rc.19",
     "aws-sdk": "~2.0.0-rc.19",
-    "bower": "~1.3.9",
+    "bower": "~1.3.12",
     "cli": "~0.6.4",
     "cli": "~0.6.4",
     "connect-flash": "~0.1.1",
     "connect-flash": "~0.1.1",
     "connect-redis": "^2.1.0",
     "connect-redis": "^2.1.0",
@@ -28,28 +31,25 @@
     "debug": "^1.0.3",
     "debug": "^1.0.3",
     "express": "=3.4.4",
     "express": "=3.4.4",
     "express-form": "~0.10.1",
     "express-form": "~0.10.1",
+    "express-session": "~1.9.3",
     "facebook-node-sdk": "=0.1.10",
     "facebook-node-sdk": "=0.1.10",
     "googleapis": "=0.4.7",
     "googleapis": "=0.4.7",
     "grunt": "~0.4.1",
     "grunt": "~0.4.1",
     "grunt-cli": "~0.1.13",
     "grunt-cli": "~0.1.13",
-    "grunt-contrib-concat": "~0.3.0",
+    "grunt-contrib-concat": "~0.5.0",
     "grunt-contrib-jshint": "^0.10.0",
     "grunt-contrib-jshint": "^0.10.0",
     "grunt-contrib-uglify": "~0.2.2",
     "grunt-contrib-uglify": "~0.2.2",
     "grunt-contrib-watch": "~0.5.3",
     "grunt-contrib-watch": "~0.5.3",
     "grunt-sass": "~0.14.1",
     "grunt-sass": "~0.14.1",
-    "jquery.cookie": "~1.4.1",
-    "marked": "=0.2.9",
     "mongoose": "=3.8.14",
     "mongoose": "=3.8.14",
     "mongoose-paginate": "~3.1.0",
     "mongoose-paginate": "~3.1.0",
     "nodemailer": "~1.2.2",
     "nodemailer": "~1.2.2",
     "nodemailer-ses-transport": "~1.1.0",
     "nodemailer-ses-transport": "~1.1.0",
-    "reveal.js": "~2.6.2",
+    "redis": "~0.12.1",
     "socket.io": "~0.9.16",
     "socket.io": "~0.9.16",
     "socket.io-client": "~0.9.16",
     "socket.io-client": "~0.9.16",
     "swig": "=1.3.2",
     "swig": "=1.3.2",
-    "time": "=0.10.0",
-    "redis": "~0.12.1",
-    "express-session": "~1.9.3"
+    "time": "=0.10.0"
   },
   },
   "devDependencies": {},
   "devDependencies": {},
   "license": [
   "license": [
@@ -60,7 +60,7 @@
   ],
   ],
   "scripts": {
   "scripts": {
     "start": "node app.js",
     "start": "node app.js",
-    "postinstall": "./node_modules/bower/bin/bower cache clean && ./node_modules/bower/bin/bower install && ./node_modules/grunt-cli/bin/grunt"
+    "postinstall": "./node_modules/.bin/bower cache clean && ./node_modules/.bin/bower install && ./node_modules/.bin/grunt"
   },
   },
   "env": {
   "env": {
     "NODE_ENV": "production"
     "NODE_ENV": "production"

+ 1 - 0
public/bower_components

@@ -0,0 +1 @@
+../bower_components

+ 0 - 3
public/hoge.css

@@ -1,3 +0,0 @@
-body {
-  font-family: Helvetica;
-}

+ 18 - 0
resource/css/_layout.scss

@@ -361,6 +361,24 @@
       margin-top: 30px;
       margin-top: 30px;
     }
     }
   }
   }
+
+  .content-main .timeline-body { // {{{ timeline
+     .revision-path {
+       margin-top: 1.6em;
+       margin-bottom: 0;
+       border: solid 2px #ddd;
+       border-bottom: none;
+       padding: 16px;
+       background: #ddd;
+     }
+     .revision-body {
+       font-size: 14px;
+       border: solid 2px #ddd;
+       padding: 16px;
+       background: #fdfdfd;
+     }
+  } // }}}
+
   // on-edit
   // on-edit
   .content-main.on-edit {
   .content-main.on-edit {
     position: fixed;
     position: fixed;

+ 1 - 0
resource/css/_wiki.scss

@@ -111,6 +111,7 @@ div.body {
     margin: 5px;
     margin: 5px;
     box-shadow: 0 0 12px 0px #999;
     box-shadow: 0 0 12px 0px #999;
     border: solid 1px #999;
     border: solid 1px #999;
+    max-width: 100%;
   }
   }
 
 
   ul, ol {
   ul, ol {

+ 26 - 18
resource/css/crowi-reveal.scss

@@ -1,4 +1,5 @@
-//@import "../../node_modules/reveal.js/css/theme/template/theme";
+@import 'reveal';
+@import 'theme/source/black';
 
 
 .reveal {
 .reveal {
   font-size: 32px;
   font-size: 32px;
@@ -6,38 +7,44 @@
     font-family: "Lucida Grande", "Hiragino Kaku Gothic Pro W3", Meiryo, san-serif;
     font-family: "Lucida Grande", "Hiragino Kaku Gothic Pro W3", Meiryo, san-serif;
   }
   }
 
 
-  section {
-    text-align: left;
+  .slides > section {
+    //text-align: left;
+    padding: 0;
 
 
     &.only.present {
     &.only.present {
-      top: -25%;
       h1, h2, h3, h4, h5, h6 {
       h1, h2, h3, h4, h5, h6 {
         font-size: 2.5em;
         font-size: 2.5em;
       }
       }
     }
     }
 
 
-    h1, h2, h3, h4, h5, h6 {
-      margin-bottom: 1em;
-      font-weight: bold;
-      line-height: 1.2em;
-      text-transform: none;
-      text-align: left;
-      text-shadow: none;
-    }
+    p {
+      line-height: 1.6;
 
 
-    p, ul li, ol li {
-      line-height: 1.3em;
+      &:first-child {
+        margin-top: 0;
+      }
     }
     }
 
 
-    p {
-      margin-top: .5em;
+    pre {
+      code {
+        padding: 20px 40px;
+      }
+    }
+    blockquote {
+      width: 80%;
+      padding: 20px 60px;
     }
     }
 
 
     ul {
     ul {
       margin-top: .2em;
       margin-top: .2em;
       margin-bottom: .1em;
       margin-bottom: .1em;
-      li {
-        margin-bottom: .2em;
+      > li {
+        line-height: 1.6;
+        margin-bottom: .5em;
+
+        > ul > li {
+          font-size: .85em;
+        }
       }
       }
     }
     }
 
 
@@ -116,6 +123,7 @@
         }
         }
       }
       }
     }
     }
+    // }}}
 
 
   }
   }
 }
 }

+ 2 - 0
resource/css/crowi.scss

@@ -6,6 +6,8 @@
 
 
 @import 'font-awesome';
 @import 'font-awesome';
 
 
+@import 'mixins';
+
 // crowi component
 // crowi component
 @import 'mixins';
 @import 'mixins';
 @import 'layout';
 @import 'layout';

+ 30 - 50
resource/js/crowi.js

@@ -40,7 +40,7 @@ Crowi.correctHeaders = function(contentId) {
   var $content = $(contentId || '#revision-body-content');
   var $content = $(contentId || '#revision-body-content');
   var i = 0;
   var i = 0;
   $('h1,h2,h3,h4,h5,h6', $content).each(function(idx, elm) {
   $('h1,h2,h3,h4,h5,h6', $content).each(function(idx, elm) {
-    var id = 'head' + i++ + '-' + $(this).text().replace(/\/|\(|\)|\s|\?|\!|\.|\+|\*|\-|\=|\#|\~|\&|\^/g, '');
+    var id = 'head' + i++;
     $(this).attr('id', id);
     $(this).attr('id', id);
     $(this).addClass('revision-head');
     $(this).addClass('revision-head');
     $(this).append('<span class="revision-head-link"><a href="#' + id +'"><i class="fa fa-link"></i></a></span>');
     $(this).append('<span class="revision-head-link"><a href="#' + id +'"><i class="fa fa-link"></i></a></span>');
@@ -95,60 +95,41 @@ Crowi.revisionToc = function(contentId, tocId) {
 
 
 
 
 Crowi.escape = function(s) {
 Crowi.escape = function(s) {
-  s = s.replace(/&/g, '&amp;');
-  s = s.replace(/</g, '&lt;');
-  s = s.replace(/>/g, '&gt;');
-  s = s.replace(/"/g, '&quot;');
+  s = s.replace(/&/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/"/g, '&quot;')
+    ;
   return s;
   return s;
 };
 };
 Crowi.unescape = function(s) {
 Crowi.unescape = function(s) {
-  s = s.replace(/&nbsp;/g, ' ');
-  s = s.replace(/&amp;/g, '&');
-  s = s.replace(/&lt;(?!\?)/g, '<');
-  s = s.replace(/([^\?])&gt;/g, '$1>');
-  s = s.replace(/&quot;/g, '"');
+  s = s.replace(/&nbsp;/g, ' ')
+    .replace(/&amp;/g, '&')
+    .replace(/&lt;/g, '<')
+    .replace(/&gt;/g, '>')
+    .replace(/&quot;/g, '"')
+    ;
   return s;
   return s;
 };
 };
 
 
-Crowi.getRendererType = function(format) {
-  if (!Crowi.rendererType[format]) {
-    throw new Error('no such renderer');
-  }
-
-  return new Crowi.rendererType[format]();
+Crowi.getRendererType = function() {
+  return new Crowi.rendererType.markdown();
 };
 };
 
 
 Crowi.rendererType = {};
 Crowi.rendererType = {};
-Crowi.rendererType.text = function(){};
 Crowi.rendererType.markdown = function(){};
 Crowi.rendererType.markdown = function(){};
-Crowi.rendererType.text.prototype = {
-  render: function($content) {
-    var $revisionHtml = this.$revisionBody.children('pre');
-    this.$content = $content;
-    $revisionHtml.html(this.$content.html());
-    this.expandImage();
-    this.link();
-  },
-  link: function () {
-    this.$revisionBody.html(this.$revisionBody.html().replace(/\s(https?:\/\/[\S]+)/g, ' <a href="$1">$1</a>'));
-  },
-  expandImage: function () {
-    this.$revisionBody.html(this.$revisionBody.html().replace(/\s(https?:\/\/[\S]+\.(jpg|jpeg|gif|png))/g, ' <img src="$1" class="auto-expanded-image" />'));
-  }
-};
 Crowi.rendererType.markdown.prototype = {
 Crowi.rendererType.markdown.prototype = {
-  render: function($content) {
+  render: function(contentText) {
     marked.setOptions({
     marked.setOptions({
       gfm: true,
       gfm: true,
       highlight: function (code, lang, callback) {
       highlight: function (code, lang, callback) {
-        callback(null, code);
-        // あとで
-        //highlight: function (code, lang, callback) {
-        //  pygmentize({ lang: lang, format: 'html' }, code, function (err, result) {
-        //    if (err) return callback(err);
-        //    callback(null, result.toString());
-        //  });
-        //},
+        var result;
+        if (lang) {
+          result = hljs.highlight(lang, code);
+        } else {
+          result = hljs.highlightAuto(code);
+        }
+        callback(null, result.value);
       },
       },
       tables: true,
       tables: true,
       breaks: true,
       breaks: true,
@@ -159,7 +140,7 @@ Crowi.rendererType.markdown.prototype = {
       langPrefix: 'lang-'
       langPrefix: 'lang-'
     });
     });
 
 
-    var contentHtml = Crowi.unescape(Crowi.escape($content.val()) || $content.html());
+    var contentHtml = Crowi.unescape(contentText);
     contentHtml = this.expandImage(contentHtml);
     contentHtml = this.expandImage(contentHtml);
     contentHtml = this.link(contentHtml);
     contentHtml = this.link(contentHtml);
 
 
@@ -170,7 +151,6 @@ Crowi.rendererType.markdown.prototype = {
         throw err;
         throw err;
       }
       }
       $body.html(content);
       $body.html(content);
-      //console.log(content);
     });
     });
   },
   },
   link: function (content) {
   link: function (content) {
@@ -184,18 +164,18 @@ Crowi.rendererType.markdown.prototype = {
   }
   }
 };
 };
 
 
-Crowi.renderer = function (contentId, format, revisionBody) {
-  var $revisionBody = revisionBody || '#revision-body-content';
+Crowi.renderer = function (contentText, revisionBody) {
+  var $revisionBody = revisionBody || $('#revision-body-content');
 
 
-  this.$content = $(contentId);
-  this.$revisionBody = $($revisionBody);
-  this.format = format;
-  this.renderer = Crowi.getRendererType(format);
+  this.contentText = contentText;
+  this.$revisionBody = $revisionBody;
+  this.format = 'markdown'; // とりあえず
+  this.renderer = Crowi.getRendererType();
   this.renderer.$revisionBody = this.$revisionBody;
   this.renderer.$revisionBody = this.$revisionBody;
 };
 };
 Crowi.renderer.prototype = {
 Crowi.renderer.prototype = {
   render: function() {
   render: function() {
-    this.renderer.render(this.$content);
+    this.renderer.render(this.contentText);
   }
   }
 };
 };
 
 

+ 2 - 2
routes/admin.js

@@ -83,7 +83,7 @@ module.exports = function(app) {
 
 
   actions.user = {};
   actions.user = {};
   actions.user.index = function(req, res) {
   actions.user.index = function(req, res) {
-    var page = parseInt(req.query.page) || 0;
+    var page = parseInt(req.query.page) || 1;
 
 
     User.findUsersWithPagination({page: page}, function(err, users, pageCount, itemCount) {
     User.findUsersWithPagination({page: page}, function(err, users, pageCount, itemCount) {
       var pager = createPager(page, pageCount, itemCount, MAX_PAGE_LIST);
       var pager = createPager(page, pageCount, itemCount, MAX_PAGE_LIST);
@@ -221,7 +221,7 @@ module.exports = function(app) {
   function saveSetting(req, res, form)
   function saveSetting(req, res, form)
   {
   {
     Config.updateNamespaceByArray('crowi', form, function(err, config) {
     Config.updateNamespaceByArray('crowi', form, function(err, config) {
-      Config.updateConfigCache('crowi', config)
+      Config.updateConfigCache('crowi', config);
       return res.json({status: true});
       return res.json({status: true});
     });
     });
   }
   }

+ 2 - 1
routes/index.js

@@ -56,7 +56,8 @@ module.exports = function(app) {
   app.post('/me/auth/google'         , middleware.loginRequired(app) , me.authGoogle);
   app.post('/me/auth/google'         , middleware.loginRequired(app) , me.authGoogle);
   app.get('/me/auth/google/callback' , middleware.loginRequired(app) , me.authGoogleCallback);
   app.get('/me/auth/google/callback' , middleware.loginRequired(app) , me.authGoogleCallback);
 
 
-  app.get('/_r/:id'                  , middleware.loginRequired(app) , page.api.redirector);
+  app.get('/:id([0-9a-z]{24})'       , middleware.loginRequired(app) , page.api.redirector);
+  app.get('/_r/:id([0-9a-z]{24})'    , middleware.loginRequired(app) , page.api.redirector); // alias
   app.get('/_api/check_username'     , user.api.checkUsername);
   app.get('/_api/check_username'     , user.api.checkUsername);
   app.post('/_api/me/picture/upload' , middleware.loginRequired(app) , me.api.uploadPicture);
   app.post('/_api/me/picture/upload' , middleware.loginRequired(app) , me.api.uploadPicture);
   app.get('/_api/user/bookmarks'     , middleware.loginRequired(app) , user.api.bookmarks);
   app.get('/_api/user/bookmarks'     , middleware.loginRequired(app) , user.api.bookmarks);

+ 4 - 4
routes/page.js

@@ -188,7 +188,7 @@ module.exports = function(app) {
       return res.redirect(d.path);
       return res.redirect(d.path);
     };
     };
 
 
-    Page.findPageById(id, req.user, function(err, pageData) {
+    Page.findPageById(id, function(err, pageData) {
       if (pageData) {
       if (pageData) {
         if (pageData.grant == Page.GRANT_RESTRICTED && !pageData.isGrantedFor(req.user)) {
         if (pageData.grant == Page.GRANT_RESTRICTED && !pageData.isGrantedFor(req.user)) {
           return Page.pushToGrantedUsers(pageData, req.user, cb);
           return Page.pushToGrantedUsers(pageData, req.user, cb);
@@ -219,7 +219,7 @@ module.exports = function(app) {
 
 
   api.bookmark = function(req, res){
   api.bookmark = function(req, res){
     var id = req.params.id;
     var id = req.params.id;
-    Page.findPageById(id, req.user, function(err, pageData) {
+    Page.findPageByIdAndGrantedUser(id, req.user, function(err, pageData) {
       if (pageData) {
       if (pageData) {
         Bookmark.add(pageData, req.user, function(err, data) {
         Bookmark.add(pageData, req.user, function(err, data) {
           return res.json({status: true});
           return res.json({status: true});
@@ -235,7 +235,7 @@ module.exports = function(app) {
    */
    */
   api.like = function(req, res){
   api.like = function(req, res){
     var id = req.params.id;
     var id = req.params.id;
-    Page.findPageById(id, req.user, function(err, pageData) {
+    Page.findPageByIdAndGrantedUser(id, req.user, function(err, pageData) {
       if (pageData) {
       if (pageData) {
         pageData.like(req.user, function(err, data) {
         pageData.like(req.user, function(err, data) {
           return res.json({status: true});
           return res.json({status: true});
@@ -252,7 +252,7 @@ module.exports = function(app) {
   api.unlike = function(req, res){
   api.unlike = function(req, res){
     var id = req.params.id;
     var id = req.params.id;
 
 
-    Page.findPageById(id, req.user, function(err, pageData) {
+    Page.findPageByIdAndGrantedUser(id, req.user, function(err, pageData) {
       if (pageData) {
       if (pageData) {
         pageData.unlike(req.user, function(err, data) {
         pageData.unlike(req.user, function(err, data) {
           return res.json({status: true});
           return res.json({status: true});

+ 2 - 2
views/_form.html

@@ -37,12 +37,12 @@
     var watchTimer = setInterval(function() {
     var watchTimer = setInterval(function() {
       var content = $('#form-body').val();
       var content = $('#form-body').val();
       if (prevContent != content) {
       if (prevContent != content) {
-        var renderer = new Crowi.renderer('#form-body', $('#form-format').val(), '#preview-body');
+        var renderer = new Crowi.renderer($('#form-body').val(), $('#preview-body'));
         renderer.render();
         renderer.render();
 
 
         prevContent = content;
         prevContent = content;
       }
       }
-    }, 1000);
+    }, 500);
 
 
     // tabs handle
     // tabs handle
     $('textarea#form-body').on('keydown', function(event){
     $('textarea#form-body').on('keydown', function(event){

+ 1 - 3
views/layout/2column.html

@@ -60,7 +60,7 @@
       #}
       #}
       <li id="login-user">
       <li id="login-user">
         <a href="/user/{{ user.username }}" id="link-mypage">
         <a href="/user/{{ user.username }}" id="link-mypage">
-          <img src="{{ user|picture }}" class="picture picture-rounded" width="25" /> マイページ
+          <img src="{{ user|picture }}" class="picture picture-rounded" width="25" /> {{ user.name }}
         </a>
         </a>
       </li>
       </li>
       <li class="dropdown">
       <li class="dropdown">
@@ -132,9 +132,7 @@
 
 
 <script>
 <script>
   $(function() {
   $(function() {
-    console.log($.cookie('aside-hidden'));
     if ($.cookie('aside-hidden') == 1) {
     if ($.cookie('aside-hidden') == 1) {
-      console.log("add aside-hidden");
       $('.main-container').addClass('aside-hidden');
       $('.main-container').addClass('aside-hidden');
     }
     }
   });
   });

+ 2 - 12
views/layout/layout.html

@@ -11,19 +11,9 @@
 
 
   <meta name="viewport" content="width=device-width,initial-scale=1">
   <meta name="viewport" content="width=device-width,initial-scale=1">
 
 
-  {% if env  == 'development' %}
-  <link rel="stylesheet" href="/css/crowi.css">
-  {% else %}
-  <link rel="stylesheet" href="/css/crowi.min.css">
-  {% endif %}
-
-  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
+  <link rel="stylesheet" href="/css/crowi{% if env  == 'production' %}.min{% endif %}.css">
+  <script src="/js/crowi{% if env  == 'production' %}.min{% endif %}.js"></script>
   <link href='//fonts.googleapis.com/css?family=Maven+Pro:400,700' rel='stylesheet' type='text/css'>
   <link href='//fonts.googleapis.com/css?family=Maven+Pro:400,700' rel='stylesheet' type='text/css'>
-  {% if env  == 'development' %}
-  <script src="/js/crowi.js"></script>
-  {% else %}
-  <script src="/js/crowi.min.js"></script>
-  {% endif %}
 </head>
 </head>
 {% endblock %}
 {% endblock %}
 
 

+ 6 - 9
views/page.html

@@ -42,7 +42,6 @@
       </a>
       </a>
     </li>
     </li>
 
 
-    <li><a href="#raw-text" data-toggle="tab"><i class="fa fa-font"></i> テキスト表示</a></li>
     <li {% if req.body.pageForm %}class="active"{% endif %}><a href="#edit-form" data-toggle="tab"><i class="fa fa-pencil-square-o"></i> 編集</a></li>
     <li {% if req.body.pageForm %}class="active"{% endif %}><a href="#edit-form" data-toggle="tab"><i class="fa fa-pencil-square-o"></i> 編集</a></li>
 
 
     <li class="dropdown pull-right">
     <li class="dropdown pull-right">
@@ -79,6 +78,7 @@
     </div>
     </div>
   </div>
   </div>
 #}
 #}
+    <script type="text/template" id="raw-text-original">{{ revision.body }}</script>
 
 
     {# formatted text #}
     {# formatted text #}
     <div class="tab-pane {% if not req.body.pageForm %}active{% endif %}" id="revision-body">
     <div class="tab-pane {% if not req.body.pageForm %}active{% endif %}" id="revision-body">
@@ -86,16 +86,12 @@
         <a data-toggle="collapse" data-parent="#revision-toc" href="#revision-toc-content" class="revision-toc-head collapsed">目次</a>
         <a data-toggle="collapse" data-parent="#revision-toc" href="#revision-toc-content" class="revision-toc-head collapsed">目次</a>
 
 
       </div>
       </div>
-    {% if revision.format == 'text' %}
-      <div class="wiki {{ revision.format }}" id="revision-body-content"><pre class="" id=""></pre></div>
-    {% else  %}
       <div class="wiki {{ revision.format }}" id="revision-body-content"></div>
       <div class="wiki {{ revision.format }}" id="revision-body-content"></div>
-    {% endif  %}
     </div>
     </div>
 
 
     {# raw text #}
     {# raw text #}
     <div class="tab-pane" id="raw-text">
     <div class="tab-pane" id="raw-text">
-      <pre id="raw-text-original">{{ revision.body }}</pre>
+      <pre id="">{{ revision.body }}</pre>
     </div>
     </div>
 
 
     {# edit form #}
     {# edit form #}
@@ -105,7 +101,7 @@
   </div>
   </div>
   <script type="text/javascript">
   <script type="text/javascript">
     $(function(){
     $(function(){
-        var renderer = new Crowi.renderer('#raw-text-original', '{{ revision.format }}');
+        var renderer = new Crowi.renderer($('#raw-text-original').html());
         renderer.render();
         renderer.render();
         Crowi.correctHeaders('#revision-body-content');
         Crowi.correctHeaders('#revision-body-content');
         Crowi.revisionToc('#revision-body-content', '#revision-toc');
         Crowi.revisionToc('#revision-body-content', '#revision-toc');
@@ -169,12 +165,13 @@
 {% if page %} {# {{{ if page #}
 {% if page %} {# {{{ if page #}
 <div class="page-meta">
 <div class="page-meta">
   <div class="row">
   <div class="row">
+    {# default(author) としているのは、v1.1.1 以前に page.creator データが入ってないから。暫定として最新更新ユーザーを表示しちゃう。 #}
     <div class="col-md-3 creator-picture">
     <div class="col-md-3 creator-picture">
-      <img src="{{ author|picture }}" class="picture picture-lg picture-rounded"><br>
+      <img src="{{ page.creator|default(author)|picture }}" class="picture picture-lg picture-rounded"><br>
     </div>
     </div>
     <div class="col-md-9">
     <div class="col-md-9">
       <p class="creator">
       <p class="creator">
-        {{ author.name }}
+        {{ page.creator.name|default(author.name) }}
       </p>
       </p>
       <p class="created-at">
       <p class="created-at">
         作成日: {{ page.createdAt|datetz('Y/m/d H:i:s') }}<br>
         作成日: {{ page.createdAt|datetz('Y/m/d H:i:s') }}<br>

+ 5 - 6
views/page_list.html

@@ -43,9 +43,10 @@
       {% for page in pages %}
       {% for page in pages %}
       <div class="timeline-body" id="id-{{ page.id }}">
       <div class="timeline-body" id="id-{{ page.id }}">
         <h3 class="revision-path"><a href="{{ page.path }}">{{ page.path }}</a></h3>
         <h3 class="revision-path"><a href="{{ page.path }}">{{ page.path }}</a></h3>
-        <div class="revision-body" data-format="{{ page.revision.format }}"><pre></pre></div>
-        <pre class="hide raw-text-original">{{ page.revision.body }}</pre>
+        <div class="revision-body wiki"></div>
+        <script type="text/template">{{ page.revision.body }}</script>
       </div>
       </div>
+      <hr>
       {% endfor %}
       {% endfor %}
     </div>
     </div>
   </div>
   </div>
@@ -55,12 +56,10 @@
         $('#view-timeline .timeline-body').each(function()
         $('#view-timeline .timeline-body').each(function()
         {
         {
           var id = $(this).attr('id');
           var id = $(this).attr('id');
-          //var format = $(this).children('.body').data('format');
-          var format = 'text';
-          var contentId = '#' + id + ' .raw-text-original';
+          var contentId = '#' + id + ' > script';
           var revisionBody = '#' + id + ' .revision-body';
           var revisionBody = '#' + id + ' .revision-body';
           var revisionPath = '#' + id + ' .revision-path';
           var revisionPath = '#' + id + ' .revision-path';
-          var renderer = new Crowi.renderer(contentId, format, revisionBody);
+          var renderer = new Crowi.renderer($(contentId).html(), $(revisionBody));
           renderer.render();
           renderer.render();
         });
         });
         //$('.tooltip .tabs').tabs();
         //$('.tooltip .tabs').tabs();

+ 13 - 25
views/page_presentation.html

@@ -6,10 +6,10 @@
     <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="//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/css/reveal.min.css">
-    <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/css/theme/solarized.css">
+
     <link rel="stylesheet" type="text/css" href="/css/crowi-reveal.css">
     <link rel="stylesheet" type="text/css" href="/css/crowi-reveal.css">
-    <link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/lib/css/zenburn.css">
+    <link rel="stylesheet" type="text/css" href="/bower_components/reveal.js/lib/css/zenburn.css">
+
     <title>{{ path|path2name }} | {{ path }}</title>
     <title>{{ path|path2name }} | {{ path }}</title>
   </head>
   </head>
   <body>
   <body>
@@ -17,7 +17,7 @@
       <div class="slides">
       <div class="slides">
         <section data-markdown data-separator="^\n\n\n">
         <section data-markdown data-separator="^\n\n\n">
           <script type="text/template">
           <script type="text/template">
-{{ revision.body|presentation }}
+{{ revision.body|presentation|safe }}
 
 
 
 
 
 
@@ -27,38 +27,26 @@
       </div>
       </div>
     </div>
     </div>
 
 
-    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
-    <script src="//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/lib/js/head.min.js"></script>
-    <script src="//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/js/reveal.min.js"></script>
+    <script src="/js/crowi-reveal.js"></script>
     <script>
     <script>
-
-      // Full list of configuration options available here:
-      // https://github.com/hakimel/reveal.js#configuration
       Reveal.initialize({
       Reveal.initialize({
         controls: true,
         controls: true,
         progress: true,
         progress: true,
         history: true,
         history: true,
-        center: false,
-
-        theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
-        transition: Reveal.getQueryHash().transition || 'default', // default/cube/page/concave/zoom/linear/fade/none
-
-        // Parallax scrolling
-        // parallaxBackgroundImage: 'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg',
-        // parallaxBackgroundSize: '2100px 900px',
+        center: true,
+        transition: 'slide',
 
 
         // Optional libraries used to extend on reveal.js
         // Optional libraries used to extend on reveal.js
         dependencies: [
         dependencies: [
-          { src: '//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/lib/js/classList.js', condition: function() { return !document.body.classList; } },
-          { src: '//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
-          { src: '//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
-          { src: '//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
-          { src: '//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
-          { src: '//cdnjs.cloudflare.com/ajax/libs/reveal.js/2.5/plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
+          { src: '/bower_components/reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } },
+          { src: '/bower_components/reveal.js/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
+          { src: '/bower_components/reveal.js/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
+          { src: '/bower_components/reveal.js/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
+          { src: '/bower_components/reveal.js/plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
+          { src: '/bower_components/reveal.js/plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
         ]
         ]
       });
       });
 
 
-      //
       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) {