summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWu Cheng-Han2016-01-12 08:01:42 -0600
committerWu Cheng-Han2016-01-12 08:01:42 -0600
commit2ecec3b59aabe2fd6156338cd4cbab7672d4f9b1 (patch)
treea27846db2e2e8d0ef1480893a8ad2b69dac36ad0
parent1672df3dceebe885ded02530799a78d5a07be1d7 (diff)
Support show last change user with profile and support YAML config inside the note with robots, lang, dir, breaks options
Diffstat (limited to '')
-rw-r--r--bower.json3
-rw-r--r--lib/note.js21
-rw-r--r--lib/realtime.js168
-rw-r--r--lib/response.js182
-rw-r--r--lib/user.js34
-rw-r--r--package.json1
-rw-r--r--public/css/extra.css63
-rw-r--r--public/css/html.min.css2
-rw-r--r--public/css/index.css37
-rw-r--r--public/css/markdown.css13
-rw-r--r--public/js/extra.js122
-rw-r--r--public/js/index.js23
-rw-r--r--public/js/pretty.js8
-rw-r--r--public/views/body.ejs7
-rw-r--r--public/views/foot.ejs2
-rw-r--r--public/views/head.ejs3
-rw-r--r--public/views/html.hbs3
-rw-r--r--public/views/pretty.ejs21
18 files changed, 546 insertions, 167 deletions
diff --git a/bower.json b/bower.json
index da93a2a5..a90aec00 100644
--- a/bower.json
+++ b/bower.json
@@ -29,6 +29,7 @@
"handlebars": "~4.0.5",
"js-url": "~2.0.2",
"socket.io-client": "~1.3.7",
- "viz.js": "~1.3.0"
+ "viz.js": "~1.3.0",
+ "js-yaml": "~3.4.6"
}
}
diff --git a/lib/note.js b/lib/note.js
index dc384b7f..671e5383 100644
--- a/lib/note.js
+++ b/lib/note.js
@@ -26,6 +26,10 @@ var model = mongoose.model('note', {
type: String,
enum: permissionTypes
},
+ lastchangeuser: {
+ type: Schema.Types.ObjectId,
+ ref: 'user'
+ },
viewcount: {
type: Number,
default: 0
@@ -45,7 +49,8 @@ var note = {
getNoteTitle: getNoteTitle,
generateWebTitle: generateWebTitle,
increaseViewCount: increaseViewCount,
- updatePermission: updatePermission
+ updatePermission: updatePermission,
+ updateLastChangeUser: updateLastChangeUser
};
function checkNoteIdValid(noteId) {
@@ -198,4 +203,18 @@ function updatePermission(note, permission, callback) {
});
}
+function updateLastChangeUser(note, lastchangeuser, callback) {
+ note.lastchangeuser = lastchangeuser;
+ note.updated = Date.now();
+ note.save(function (err) {
+ if (err) {
+ logger.error('update note lastchangeuser failed: ' + err);
+ callback(err, null);
+ } else {
+ logger.info("update note lastchangeuser success: " + note.id);
+ callback(null, note);
+ };
+ });
+}
+
module.exports = note; \ No newline at end of file
diff --git a/lib/realtime.js b/lib/realtime.js
index a9c541cf..484ef12e 100644
--- a/lib/realtime.js
+++ b/lib/realtime.js
@@ -9,7 +9,6 @@ var shortId = require('shortid');
var randomcolor = require("randomcolor");
var Chance = require('chance'),
chance = new Chance();
-var md5 = require("blueimp-md5").md5;
var moment = require('moment');
//core
@@ -68,7 +67,9 @@ function secure(socket, next) {
function emitCheck(note) {
var out = {
- updatetime: note.updatetime
+ updatetime: note.updatetime,
+ lastchangeuser: note.lastchangeuser,
+ lastchangeuserprofile: note.lastchangeuserprofile
};
realtime.io.to(note.id).emit('check', out);
/*
@@ -89,18 +90,52 @@ var updater = setInterval(function () {
if (note.server.isDirty) {
if (config.debug)
logger.info("updater found dirty note: " + key);
- var body = note.server.document;
- var title = Note.getNoteTitle(body);
- title = LZString.compressToBase64(title);
- body = LZString.compressToBase64(body);
- db.saveToDB(key, title, body, function (err, result) {
- if (err) return;
- note.server.isDirty = false;
- note.updatetime = Date.now();
- emitCheck(note);
+ Note.findNote(note.id, function (err, _note) {
+ if (err || !_note) return callback(err, null);
+ //mongo update
+ if (note.lastchangeuser && _note.lastchangeuser != note.lastchangeuser) {
+ var lastchangeuser = note.lastchangeuser;
+ var lastchangeuserprofile = null;
+ User.findUser(lastchangeuser, function (err, user) {
+ if (err) return callback(err, null);
+ if (user && user.profile) {
+ var profile = JSON.parse(user.profile);
+ if (profile) {
+ lastchangeuserprofile = {
+ name: profile.displayName || profile.username,
+ photo: User.parsePhotoByProfile(profile)
+ }
+ note.lastchangeuser = lastchangeuser;
+ note.lastchangeuserprofile = lastchangeuserprofile;
+ Note.updateLastChangeUser(_note, lastchangeuser, function (err, result) {
+ if (err) return callback(err, null);
+ });
+ }
+ }
+ });
+ } else {
+ note.lastchangeuser = null;
+ note.lastchangeuserprofile = null;
+ Note.updateLastChangeUser(_note, null, function (err, result) {
+ if (err) return callback(err, null);
+ });
+ }
+ //postgres update
+ var body = note.server.document;
+ var title = Note.getNoteTitle(body);
+ title = LZString.compressToBase64(title);
+ body = LZString.compressToBase64(body);
+ db.saveToDB(key, title, body, function (err, result) {
+ if (err) return callback(err, null);
+ note.server.isDirty = false;
+ note.updatetime = Date.now();
+ emitCheck(note);
+ callback(null, null);
+ });
});
+ } else {
+ callback(null, null);
}
- callback();
}, function (err) {
if (err) return logger.error('updater error', err);
});
@@ -121,7 +156,7 @@ var cleaner = setInterval(function () {
disconnectSocketQueue.push(socket);
disconnect(socket);
}
- callback();
+ callback(null, null);
}, function (err) {
if (err) return logger.error('cleaner error', err);
});
@@ -250,7 +285,11 @@ function emitRefresh(socket) {
socket.emit('refresh', {
docmaxlength: config.documentmaxlength,
owner: note.owner,
+ ownerprofile: note.ownerprofile,
+ lastchangeuser: note.lastchangeuser,
+ lastchangeuserprofile: note.lastchangeuserprofile,
permission: note.permission,
+ createtime: note.createtime,
updatetime: note.updatetime
});
}
@@ -321,11 +360,15 @@ function startConnection(socket) {
isConnectionBusy = false;
return logger.error(err);
}
+
var owner = data.rows[0].owner;
+ var ownerprofile = null;
var permission = "freely";
if (owner && owner != "null") {
permission = "editable";
}
+
+ //find or new note
Note.findOrNewNote(notename, permission, function (err, note) {
if (err) {
responseError(res, "404", "Not Found", "oops.");
@@ -333,20 +376,64 @@ function startConnection(socket) {
isConnectionBusy = false;
return;
}
+
var body = LZString.decompressFromBase64(data.rows[0].content);
//body = LZString.compressToUTF16(body);
+ var createtime = data.rows[0].create_time;
var updatetime = data.rows[0].update_time;
var server = new ot.EditorSocketIOServer(body, [], notename, ifMayEdit);
+
+ var lastchangeuser = note.lastchangeuser || null;
+ var lastchangeuserprofile = null;
+
notes[notename] = {
id: notename,
owner: owner,
+ ownerprofile: ownerprofile,
permission: note.permission,
+ lastchangeuser: lastchangeuser,
+ lastchangeuserprofile: lastchangeuserprofile,
socks: [],
users: {},
+ createtime: moment(createtime).valueOf(),
updatetime: moment(updatetime).valueOf(),
server: server
};
- finishConnection(socket, notes[notename], users[socket.id]);
+
+ if (lastchangeuser) {
+ //find last change user profile if lastchangeuser exists
+ User.findUser(lastchangeuser, function (err, user) {
+ if (!err && user && user.profile) {
+ var profile = JSON.parse(user.profile);
+ if (profile) {
+ lastchangeuserprofile = {
+ name: profile.displayName || profile.username,
+ photo: User.parsePhotoByProfile(profile)
+ }
+ notes[notename].lastchangeuserprofile = lastchangeuserprofile;
+ }
+ }
+ });
+ }
+
+ if (owner && owner != "null") {
+ //find owner profile if owner exists
+ User.findUser(owner, function (err, user) {
+ if (!err && user && user.profile) {
+ var profile = JSON.parse(user.profile);
+ if (profile) {
+ ownerprofile = {
+ name: profile.displayName || profile.username,
+ photo: User.parsePhotoByProfile(profile)
+ }
+ notes[notename].ownerprofile = ownerprofile;
+ }
+ }
+ finishConnection(socket, notes[notename], users[socket.id]);
+ });
+ } else {
+ finishConnection(socket, notes[notename], users[socket.id]);
+ }
});
});
} else {
@@ -433,23 +520,7 @@ function updateUserData(socket, user) {
//retrieve user data from passport
if (socket.request.user && socket.request.user.logged_in) {
var profile = JSON.parse(socket.request.user.profile);
- var photo = null;
- switch (profile.provider) {
- case "facebook":
- photo = 'https://graph.facebook.com/' + profile.id + '/picture';
- break;
- case "twitter":
- photo = profile.photos[0].value;
- break;
- case "github":
- photo = 'https://avatars.githubusercontent.com/u/' + profile.id + '?s=48';
- break;
- case "dropbox":
- //no image api provided, use gravatar
- photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0].value);
- break;
- }
- user.photo = photo;
+ user.photo = User.parsePhotoByProfile(profile);
user.name = profile.displayName || profile.username;
user.userid = socket.request.user._id;
user.login = true;
@@ -466,19 +537,28 @@ function ifMayEdit(socket, callback) {
var note = notes[notename];
var mayEdit = true;
switch (note.permission) {
- case "freely":
- //not blocking anyone
- break;
- case "editable":
- //only login user can change
- if (!socket.request.user || !socket.request.user.logged_in)
- mayEdit = false;
- break;
- case "locked":
- //only owner can change
- if (note.owner != socket.request.user._id)
- mayEdit = false;
- break;
+ case "freely":
+ //not blocking anyone
+ break;
+ case "editable":
+ //only login user can change
+ if (!socket.request.user || !socket.request.user.logged_in)
+ mayEdit = false;
+ break;
+ case "locked":
+ //only owner can change
+ if (note.owner != socket.request.user._id)
+ mayEdit = false;
+ break;
+ }
+ //if user may edit and this note have owner (not anonymous usage)
+ if (mayEdit && note.owner && note.owner != "null") {
+ //save for the last change user id
+ if (socket.request.user && socket.request.user.logged_in) {
+ note.lastchangeuser = socket.request.user._id;
+ } else {
+ note.lastchangeuser = null;
+ }
}
callback(mayEdit);
}
diff --git a/lib/response.js b/lib/response.js
index 6a180f2b..a30df470 100644
--- a/lib/response.js
+++ b/lib/response.js
@@ -8,6 +8,7 @@ var markdownpdf = require("markdown-pdf");
var LZString = require('lz-string');
var S = require('string');
var shortId = require('shortid');
+var metaMarked = require('meta-marked');
//core
var config = require("../config.js");
@@ -15,6 +16,7 @@ var config = require("../config.js");
//others
var db = require("./db.js");
var Note = require("./note.js");
+var User = require("./user.js");
//slides
var md = require('reveal.js/plugin/markdown/markdown');
@@ -104,6 +106,13 @@ function responseHackMD(res, noteId) {
responseError(res, "404", "Not Found", "oops.");
return;
}
+ var body = LZString.decompressFromBase64(data.rows[0].content);
+ var meta = null;
+ try {
+ meta = metaMarked(body).meta;
+ } catch(err) {
+ //na
+ }
var title = data.rows[0].title;
var decodedTitle = LZString.decompressFromBase64(title);
if (decodedTitle) title = decodedTitle;
@@ -116,7 +125,8 @@ function responseHackMD(res, noteId) {
var compiled = ejs.compile(fs.readFileSync(template, 'utf8'), options);
var html = compiled({
title: title,
- useCDN: config.usecdn
+ useCDN: config.usecdn,
+ robots: (meta && meta.robots) || false //default allow robots
});
var buf = html;
res.writeHead(200, {
@@ -192,34 +202,47 @@ function showPublishNote(req, res, next) {
return;
}
var body = LZString.decompressFromBase64(data.rows[0].content);
+ var meta = null;
+ try {
+ meta = metaMarked(body).meta;
+ } catch(err) {
+ //na
+ }
var updatetime = data.rows[0].update_time;
var text = S(body).escapeHTML().s;
var title = data.rows[0].title;
var decodedTitle = LZString.decompressFromBase64(title);
if (decodedTitle) title = decodedTitle;
title = Note.generateWebTitle(title);
- var template = config.prettypath;
- var options = {
- cache: !config.debug,
- filename: template
- };
- var compiled = ejs.compile(fs.readFileSync(template, 'utf8'), options);
var origin = config.getserverurl();
- var html = compiled({
+ var data = {
title: title,
viewcount: note.viewcount,
updatetime: updatetime,
url: origin,
body: text,
- useCDN: config.usecdn
- });
- var buf = html;
- res.writeHead(200, {
- 'Content-Type': 'text/html; charset=UTF-8',
- 'Cache-Control': 'private',
- 'Content-Length': buf.length
- });
- res.end(buf);
+ useCDN: config.usecdn,
+ lastchangeuserprofile: null,
+ robots: (meta && meta.robots) || false //default allow robots
+ };
+ if (note.lastchangeuser) {
+ //find last change user profile if lastchangeuser exists
+ User.findUser(note.lastchangeuser, function (err, user) {
+ if (!err && user && user.profile) {
+ var profile = JSON.parse(user.profile);
+ if (profile) {
+ data.lastchangeuserprofile = {
+ name: profile.displayName || profile.username,
+ photo: User.parsePhotoByProfile(profile)
+ }
+ renderPublish(data, res);
+ }
+ }
+ });
+ } else {
+ renderPublish(data, res);
+ }
+
});
});
});
@@ -228,6 +251,23 @@ function showPublishNote(req, res, next) {
}
}
+function renderPublish(data, res) {
+ var template = config.prettypath;
+ var options = {
+ cache: !config.debug,
+ filename: template
+ };
+ var compiled = ejs.compile(fs.readFileSync(template, 'utf8'), options);
+ var html = compiled(data);
+ var buf = html;
+ res.writeHead(200, {
+ 'Content-Type': 'text/html; charset=UTF-8',
+ 'Cache-Control': 'private',
+ 'Content-Length': buf.length
+ });
+ res.end(buf);
+}
+
function actionPublish(req, res, noteId) {
db.readFromDB(noteId, function (err, data) {
if (err) {
@@ -269,36 +309,6 @@ function actionSlide(req, res, noteId) {
});
});
}
-//pretty api is deprecated
-function actionPretty(req, res, noteId) {
- db.readFromDB(noteId, function (err, data) {
- if (err) {
- responseError(res, "404", "Not Found", "oops.");
- return;
- }
- var body = LZString.decompressFromBase64(data.rows[0].content);
- var text = S(body).escapeHTML().s;
- var title = data.rows[0].title;
- var decodedTitle = LZString.decompressFromBase64(title);
- if (decodedTitle) title = decodedTitle;
- title = Note.generateWebTitle(title);
- var template = config.prettypath;
- var compiled = ejs.compile(fs.readFileSync(template, 'utf8'));
- var origin = config.getserverurl();
- var html = compiled({
- title: title,
- url: origin,
- body: text
- });
- var buf = html;
- res.writeHead(200, {
- 'Content-Type': 'text/html; charset=UTF-8',
- 'Cache-Control': 'private',
- 'Content-Length': buf.length
- });
- res.end(buf);
- });
-}
function actionDownload(req, res, noteId) {
db.readFromDB(noteId, function (err, data) {
@@ -325,6 +335,11 @@ function actionPDF(req, res, noteId) {
return;
}
var body = LZString.decompressFromBase64(data.rows[0].content);
+ try {
+ body = metaMarked(body).markdown;
+ } catch(err) {
+ //na
+ }
var title = Note.getNoteTitle(body);
if (!fs.existsSync(config.tmppath)) {
@@ -361,46 +376,46 @@ function noteActions(req, res, next) {
}
var action = req.params.action;
switch (action) {
- case "publish":
- case "pretty": //pretty deprecated
- actionPublish(req, res, noteId);
- break;
- case "slide":
- actionSlide(req, res, noteId);
- break;
- case "download":
- actionDownload(req, res, noteId);
- break;
- case "pdf":
- actionPDF(req, res, noteId);
- break;
- default:
- if (noteId != config.featuresnotename)
- res.redirect('/' + LZString.compressToBase64(noteId));
- else
- res.redirect('/' + noteId);
- break;
+ case "publish":
+ case "pretty": //pretty deprecated
+ actionPublish(req, res, noteId);
+ break;
+ case "slide":
+ actionSlide(req, res, noteId);
+ break;
+ case "download":
+ actionDownload(req, res, noteId);
+ break;
+ case "pdf":
+ actionPDF(req, res, noteId);
+ break;
+ default:
+ if (noteId != config.featuresnotename)
+ res.redirect('/' + LZString.compressToBase64(noteId));
+ else
+ res.redirect('/' + noteId);
+ break;
}
}
function publishNoteActions(req, res, next) {
var action = req.params.action;
switch (action) {
- case "edit":
- var shortid = req.params.shortid;
- if (shortId.isValid(shortid)) {
- Note.findNote(shortid, function (err, note) {
- if (err || !note) {
- responseError(res, "404", "Not Found", "oops.");
- return;
- }
- if (note.id != config.featuresnotename)
- res.redirect('/' + LZString.compressToBase64(note.id));
- else
- res.redirect('/' + note.id);
- });
- }
- break;
+ case "edit":
+ var shortid = req.params.shortid;
+ if (shortId.isValid(shortid)) {
+ Note.findNote(shortid, function (err, note) {
+ if (err || !note) {
+ responseError(res, "404", "Not Found", "oops.");
+ return;
+ }
+ if (note.id != config.featuresnotename)
+ res.redirect('/' + LZString.compressToBase64(note.id));
+ else
+ res.redirect('/' + note.id);
+ });
+ }
+ break;
}
}
@@ -424,6 +439,11 @@ function showPublishSlide(req, res, next) {
return;
}
var body = LZString.decompressFromBase64(data.rows[0].content);
+ try {
+ body = metaMarked(body).markdown;
+ } catch(err) {
+ //na
+ }
var title = data.rows[0].title;
var decodedTitle = LZString.decompressFromBase64(title);
if (decodedTitle) title = decodedTitle;
diff --git a/lib/user.js b/lib/user.js
index f89f7def..b3fae39c 100644
--- a/lib/user.js
+++ b/lib/user.js
@@ -1,6 +1,7 @@
//user
//external modules
var mongoose = require('mongoose');
+var md5 = require("blueimp-md5").md5;
//core
var config = require("../config.js");
@@ -20,9 +21,30 @@ var user = {
findUser: findUser,
newUser: newUser,
findOrNewUser: findOrNewUser,
- getUserCount: getUserCount
+ getUserCount: getUserCount,
+ parsePhotoByProfile: parsePhotoByProfile
};
+function parsePhotoByProfile(profile) {
+ var photo = null;
+ switch (profile.provider) {
+ case "facebook":
+ photo = 'https://graph.facebook.com/' + profile.id + '/picture';
+ break;
+ case "twitter":
+ photo = profile.photos[0].value;
+ break;
+ case "github":
+ photo = 'https://avatars.githubusercontent.com/u/' + profile.id + '?s=48';
+ break;
+ case "dropbox":
+ //no image api provided, use gravatar
+ photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0].value);
+ break;
+ }
+ return photo;
+}
+
function getUserCount(callback) {
model.count(function(err, count){
if(err) callback(err, null);
@@ -31,9 +53,13 @@ function getUserCount(callback) {
}
function findUser(id, callback) {
- model.findOne({
- id: id
- }, function (err, user) {
+ var rule = {};
+ var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");
+ if (checkForHexRegExp.test(id))
+ rule._id = id;
+ else
+ rule.id = id;
+ model.findOne(rule, function (err, user) {
if (err) {
logger.error('find user failed: ' + err);
callback(err, null);
diff --git a/package.json b/package.json
index 664673dc..1238ff35 100644
--- a/package.json
+++ b/package.json
@@ -28,6 +28,7 @@
"lz-string": "1.4.4",
"markdown-pdf": "^6.0.0",
"marked": "^0.3.5",
+ "meta-marked": "^0.4.0",
"method-override": "^2.3.5",
"moment": "^2.10.6",
"mongoose": "^4.3.1",
diff --git a/public/css/extra.css b/public/css/extra.css
index 1e0356c7..8d91f529 100644
--- a/public/css/extra.css
+++ b/public/css/extra.css
@@ -56,6 +56,7 @@ h6:hover .header-link {
.header-link {
position: relative;
left: 0.5em;
+ right: 0.5em;
opacity: 0;
font-size: 0.8em;
-webkit-transition: opacity 0.2s ease-in-out 0.1s;
@@ -114,6 +115,12 @@ h6:hover .header-link {
width: 25vw;
max-height: 65vh;
overflow: auto;
+ text-align: inherit;
+}
+
+.ui-toc-dropdown[dir='rtl'] .nav {
+ padding-right: 0;
+ letter-spacing: 0.0029em;
}
.ui-toc-dropdown a {
@@ -138,6 +145,12 @@ h6:hover .header-link {
border-left: 1px solid black;
}
+.ui-toc-dropdown[dir='rtl'] .nav>li>a:focus,.ui-toc-dropdown[dir='rtl'] .nav>li>a:hover {
+ padding-right: 19px;
+ border-left: none;
+ border-right: 1px solid black;
+}
+
.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a {
padding-left: 18px;
font-weight: 700;
@@ -146,6 +159,12 @@ h6:hover .header-link {
border-left: 2px solid black;
}
+.ui-toc-dropdown[dir='rtl'] .nav>.active:focus>a,.ui-toc-dropdown[dir='rtl'] .nav>.active:hover>a,.ui-toc-dropdown[dir='rtl'] .nav>.active>a {
+ padding-right: 18px;
+ border-left: none;
+ border-right: 2px solid black;
+}
+
.ui-toc-dropdown .nav .nav {
display: none;
padding-bottom: 10px;
@@ -163,6 +182,10 @@ h6:hover .header-link {
font-weight: 400;
}
+.ui-toc-dropdown[dir='rtl'] .nav .nav>li>a {
+ padding-right: 30px;
+}
+
.ui-toc-dropdown .nav .nav>li>ul>li>a {
padding-top: 1px;
padding-bottom: 1px;
@@ -171,24 +194,44 @@ h6:hover .header-link {
font-weight: 400;
}
+.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>a {
+ padding-right: 40px;
+}
+
.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover {
padding-left: 29px;
}
+.ui-toc-dropdown[dir='rtl'] .nav .nav>li>a:focus,.ui-toc-dropdown[dir='rtl'] .nav .nav>li>a:hover {
+ padding-right: 29px;
+}
+
.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover {
padding-left: 39px;
}
+.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir='rtl'] .nav .nav>li>ul>li>a:hover {
+ padding-right: 39px;
+}
+
.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a {
padding-left: 28px;
font-weight: 500;
}
+.ui-toc-dropdown[dir='rtl'] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir='rtl'] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>a {
+ padding-right: 28px;
+}
+
.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a {
padding-left: 38px;
font-weight: 500;
}
+.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir='rtl'] .nav .nav>.active>.nav>.active>a {
+ padding-right: 38px;
+}
+
.ui-affix-toc {
position: fixed;
top: 0;
@@ -216,6 +259,26 @@ h6:hover .header-link {
margin-top: 0;
}
+.ui-user-icon {
+ width: 20px;
+ height: 20px;
+ display: block;
+ border-radius: 3px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ margin-right: 5px;
+ background-position: center center;
+ background-repeat: no-repeat;
+ background-size: contain;
+}
+.ui-user-icon.small {
+ width: 18px;
+ height: 18px;
+ display: inline-block;
+ vertical-align: middle;
+ margin: 0 0 0.2em 0;
+}
+
small span {
line-height: 22px;
}
diff --git a/public/css/html.min.css b/public/css/html.min.css
index 679c0142..50de453e 100644
--- a/public/css/html.min.css
+++ b/public/css/html.min.css
@@ -1 +1 @@
-.markdown-body h1,.markdown-body h2{padding-bottom:.3em;border-bottom:1px solid #eee}.markdown-body{overflow:hidden;font-size:1pc;line-height:1.6;word-wrap:break-word}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body .absent{color:#c00}.markdown-body .anchor{position:absolute;top:0;bottom:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}.markdown-body .anchor:focus{outline:0}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{position:relative;margin-top:1em;margin-bottom:1pc;font-weight:700;line-height:1.4}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{display:none;color:#000;vertical-align:middle}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{padding-left:8px;margin-left:-30px;line-height:1;text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{display:inline-block}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2.25em;line-height:1.2}.markdown-body h2{font-size:1.75em;line-height:1.225}.markdown-body h3{font-size:1.5em;line-height:1.43}.markdown-body h4{font-size:1.25em}.markdown-body h5{font-size:1em}.markdown-body h6{font-size:1em;color:#777}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:1pc}.markdown-body hr{height:4px;padding:0;margin:1pc 0;background-color:#e7e7e7;border:0}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{padding:0;list-style-type:none}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:1pc}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:1pc;font-size:1em;font-style:italic;font-weight:700}.markdown-body dl dd{padding:0 1pc;margin-bottom:1pc}.markdown-body blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body table{display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #ddd}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{max-width:100%;-moz-box-sizing:border-box;box-sizing:border-box}.markdown-body .emoji{width:20px;height:20px;max-width:none;margin-bottom:0}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown-body span.align-center{display:block;overflow:hidden;clear:both}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{display:block;overflow:hidden;clear:both}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{padding:.2em 0;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown-body .highlight{margin-bottom:1pc}.markdown-body .highlight pre,.markdown-body pre{padding:1pc;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body pre code,.markdown-body pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{padding:5px;overflow:hidden;font-size:9pt;line-height:1;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.news .alert .markdown-body blockquote{padding:0 0 0 40px;border:0}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle;cursor:default!important}.markdown-body{font-family:"Helvetica Neue",Helvetica,Arial,"Microsoft JhengHei",Meiryo,"MS ゴシック","MS Gothic",sans-serif;padding-top:40px;padding-bottom:40px;max-width:758px}.markdown-body pre{word-wrap:normal;border:inherit!important}.markdown-body code{color:inherit!important}.markdown-body pre code .wrapper{display:-webkit-inline-flex;display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{text-align:right;position:relative;display:inline-block;float:right;cursor:default;z-index:4;padding:0 8px 0 0;min-width:20px;box-sizing:content-box;color:#afafaf!important;border-right:3px solid #6ce26c!important}.markdown-body .flow-chart,.markdown-body .sequence-diagram,.vimeo,.youtube{text-align:center}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 1pc}.markdown-body .gist .line-numbers{border-left:none;border-top:none;border-bottom:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-spacing:0;border-collapse:inherit!important}.markdown-body code[data-gist-id]{background:0 0;padding:0}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:''}.markdown-body .flow-chart{margin-bottom:40px}svg{width:100%;max-height:70vh}.vimeo,.youtube{position:relative;cursor:pointer;display:table;max-width:540px;background-position:center center;background-repeat:no-repeat;background-size:contain;background-color:#000}.vimeo img,.youtube img{position:absolute;margin:auto;top:0;left:0;right:0;bottom:0}.vimeo .icon,.youtube .icon{position:absolute;height:auto;width:auto;top:50%;left:50%;margin-top:-40px;margin-left:-40px;color:#fff;opacity:.3;-webkit-transition:opacity .2s;transition:opacity .2s}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;-webkit-transition:opacity .2s;transition:opacity .2s}h1:hover .header-link,h2:hover .header-link,h3:hover .header-link,h4:hover .header-link,h5:hover .header-link,h6:hover .header-link{opacity:1;-webkit-transition:opacity .2s ease-in-out .1s;-moz-transition:opacity .2s ease-in-out .1s;-o-transition:opacity .2s ease-in-out .1s;transition:opacity .2s ease-in-out .1s}.header-link{position:relative;left:.5em;opacity:0;font-size:.8em;-webkit-transition:opacity .2s ease-in-out .1s;-moz-transition:opacity .2s ease-in-out .1s;-o-transition:opacity .2s ease-in-out .1s;transition:opacity .2s ease-in-out .1s}.ui-infobar{max-width:758px;margin-top:25px;margin-bottom:-25px;color:#777}.ui-toc{position:fixed;bottom:20px;z-index:10000}.ui-toc-label{opacity:.3;background-color:#ccc;border:none;-webkit-transition:opacity .2s;transition:opacity .2s}.ui-toc .open .ui-toc-label{opacity:1;color:#fff;-webkit-transition:opacity .2s;transition:opacity .2s}.ui-toc-label:focus{opacity:.3;background-color:#ccc;color:#000}.ui-toc-label:hover{opacity:1;background-color:#ccc;-webkit-transition:opacity .2s;transition:opacity .2s}.ui-toc-dropdown{margin-top:23px;margin-bottom:20px;padding-left:10px;padding-right:10px;max-width:45vw;width:25vw;max-height:65vh;overflow:auto}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{padding-left:19px;color:#000;text-decoration:none;background-color:transparent;border-left:1px solid #000}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{padding-left:18px;font-weight:700;color:#000;background-color:transparent;border-left:2px solid #000}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul{display:block}.ui-toc-dropdown .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:9pt;font-weight:400}.ui-toc-dropdown .nav .nav>li>ul>li>a{padding-top:1px;padding-bottom:1px;padding-left:40px;font-size:9pt;font-weight:400}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{padding-left:28px;font-weight:500}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{padding-left:38px;font-weight:500}.ui-affix-toc{position:fixed;top:0;max-width:15vw;max-height:70vh;overflow:auto}.back-to-top,.go-to-bottom{display:block;padding:4px 10px;margin-top:10px;margin-left:10px;font-size:9pt;font-weight:500;color:#999}.back-to-top:focus,.back-to-top:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:#563d7c;text-decoration:none}.go-to-bottom{margin-top:0}small span{line-height:22px}small .dropdown{display:inline-block}small .dropdown a:focus,small .dropdown a:hover{text-decoration:none}.unselectable{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:9pt!important}}@font-face{font-family:'Source Code Pro';font-style:normal;font-weight:300;src:local('Source Code Pro Light'),local('SourceCodePro-Light'),url(https://fonts.gstatic.com/s/sourcecodepro/v6/leqv3v-yTsJNC7nFznSMqUBls_1aQwi4AfipSOlE3SU.ttf) format('truetype')}@font-face{font-family:'Source Code Pro';font-style:normal;font-weight:400;src:local('Source Code Pro'),local('SourceCodePro-Regular'),url(https://fonts.gstatic.com/s/sourcecodepro/v6/mrl8jkM18OlOQN8JLgasD1zCdIATDt8zXO3QNtzVeJ8.ttf) format('truetype')}@font-face{font-family:'Source Code Pro';font-style:normal;font-weight:500;src:local('Source Code Pro Medium'),local('SourceCodePro-Medium'),url(https://fonts.gstatic.com/s/sourcecodepro/v6/leqv3v-yTsJNC7nFznSMqdgxThF69EFTxeh70dQtJtE.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:normal;font-weight:300;src:local('Source Sans Pro Light'),local('SourceSansPro-Light'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/toadOcfmlt9b38dHJxOBGEBls_1aQwi4AfipSOlE3SU.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:normal;font-weight:400;src:local('Source Sans Pro'),local('SourceSansPro-Regular'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/ODelI1aHBYDBqgeIAH2zlFzCdIATDt8zXO3QNtzVeJ8.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:normal;font-weight:600;src:local('Source Sans Pro Semibold'),local('SourceSansPro-Semibold'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/toadOcfmlt9b38dHJxOBGGvd-IutAbwf5FQ8ZpuI2w4.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:italic;font-weight:300;src:local('Source Sans Pro Light Italic'),local('SourceSansPro-LightIt'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/fpTVHK8qsXbIeTHTrnQH6I48KljrVa8Zcyi9xGGohEU.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:italic;font-weight:400;src:local('Source Sans Pro Italic'),local('SourceSansPro-It'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/M2Jd71oPJhLKp0zdtTvoM6xot8ENfkYez2Lz7rcrw70.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:italic;font-weight:600;src:local('Source Sans Pro Semibold Italic'),local('SourceSansPro-SemiboldIt'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/fpTVHK8qsXbIeTHTrnQH6KjMMkbXdLGS8FpAnMJn5J0.ttf) format('truetype')}@font-face{font-family:'Source Serif Pro';font-style:normal;font-weight:400;src:local('Source Serif Pro'),local('SourceSerifPro-Regular'),url(https://fonts.gstatic.com/s/sourceserifpro/v4/CeUM4np2c42DV49nanp55WdjwOOpWxWrsXXkZJyNRnI.ttf) format('truetype')}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;text-shadow:1px 1px 1px rgba(0,0,0,.004);-webkit-overflow-scrolling:touch;font-family:"Source Sans Pro",Helvetica,Arial,"Microsoft JhengHei UI","Meiryo UI","MS Pゴシック","MS PGothic",sans-serif;letter-spacing:.025em}:focus{outline:0!important}::-moz-focus-inner{border:0!important}body.modal-open{overflow-y:auto;padding-right:0!important} \ No newline at end of file
+.markdown-body h1,.markdown-body h2{padding-bottom:.3em;border-bottom:1px solid #eee}.markdown-body{font-size:1pc;line-height:1.6;word-wrap:break-word}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body .absent{color:#c00}.markdown-body .anchor{position:absolute;top:0;bottom:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}.markdown-body .anchor:focus{outline:0}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{position:relative;margin-top:1em;margin-bottom:1pc;font-weight:700;line-height:1.4}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{display:none;color:#000;vertical-align:middle}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{padding-left:8px;margin-left:-30px;line-height:1;text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{display:inline-block}.markdown-body h1 code,.markdown-body h1 tt,.markdown-body h2 code,.markdown-body h2 tt,.markdown-body h3 code,.markdown-body h3 tt,.markdown-body h4 code,.markdown-body h4 tt,.markdown-body h5 code,.markdown-body h5 tt,.markdown-body h6 code,.markdown-body h6 tt{font-size:inherit}.markdown-body h1{font-size:2.25em;line-height:1.2}.markdown-body h2{font-size:1.75em;line-height:1.225}.markdown-body h3{font-size:1.5em;line-height:1.43}.markdown-body h4{font-size:1.25em}.markdown-body h5{font-size:1em}.markdown-body h6{font-size:1em;color:#777}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:1pc}.markdown-body hr{height:4px;padding:0;margin:1pc 0;background-color:#e7e7e7;border:0}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol.no-list,.markdown-body ul.no-list{padding:0;list-style-type:none}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:1pc}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:1pc;font-size:1em;font-style:italic;font-weight:700}.markdown-body dl dd{padding:0 1pc;margin-bottom:1pc}.markdown-body blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body table{display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #ddd}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{max-width:100%;-moz-box-sizing:border-box;box-sizing:border-box}.markdown-body .emoji{width:20px;height:20px;max-width:none;margin-bottom:0}.markdown-body span.frame{display:block;overflow:hidden}.markdown-body span.frame>span{display:block;float:left;width:auto;padding:7px;margin:13px 0 0;overflow:hidden;border:1px solid #ddd}.markdown-body span.frame span img{display:block;float:left}.markdown-body span.frame span span{display:block;padding:5px 0 0;clear:both;color:#333}.markdown-body span.align-center{display:block;overflow:hidden;clear:both}.markdown-body span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown-body span.align-center span img{margin:0 auto;text-align:center}.markdown-body span.align-right{display:block;overflow:hidden;clear:both}.markdown-body span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown-body span.align-right span img{margin:0;text-align:right}.markdown-body span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown-body span.float-left span{margin:13px 0 0}.markdown-body span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown-body span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown-body code,.markdown-body tt{padding:.2em 0;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown-body code:after,.markdown-body code:before,.markdown-body tt:after,.markdown-body tt:before{letter-spacing:-.2em;content:"\00a0"}.markdown-body code br,.markdown-body tt br{display:none}.markdown-body del code{text-decoration:inherit}.markdown-body pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:0 0;border:0}.markdown-body .highlight{margin-bottom:1pc}.markdown-body .highlight pre,.markdown-body pre{padding:1pc;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body pre code,.markdown-body pre tt{display:inline;max-width:initial;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body pre code:after,.markdown-body pre code:before,.markdown-body pre tt:after,.markdown-body pre tt:before{content:normal}.markdown-body .csv-data td,.markdown-body .csv-data th{padding:5px;overflow:hidden;font-size:9pt;line-height:1;text-align:left;white-space:nowrap}.markdown-body .csv-data .blob-line-num{padding:10px 8px 9px;text-align:right;background:#fff;border:0}.markdown-body .csv-data tr{border-top:0}.markdown-body .csv-data th{font-weight:700;background:#f8f8f8;border-top:0}.news .alert .markdown-body blockquote{padding:0 0 0 40px;border:0}.activity-tab .news .alert .commits,.activity-tab .news .markdown-body blockquote{padding-left:0}.task-list-item{list-style-type:none}.task-list-item label{font-weight:400}.task-list-item.enabled label{cursor:pointer}.task-list-item+.task-list-item{margin-top:3px}.task-list-item-checkbox{float:left;margin:.31em 0 .2em -1.3em!important;vertical-align:middle;cursor:default!important}.markdown-body{font-family:"Helvetica Neue",Helvetica,Arial,"Microsoft JhengHei",Meiryo,"MS ゴシック","MS Gothic",sans-serif;padding-top:40px;padding-bottom:40px;max-width:758px;overflow:visible!important}.markdown-body pre{word-wrap:normal;border:inherit!important}.markdown-body code{color:inherit!important}.markdown-body pre code .wrapper{display:-webkit-inline-flex;display:-moz-inline-flex;display:-ms-inline-flex;display:-o-inline-flex;display:inline-flex}.markdown-body pre code .gutter{float:left;overflow:hidden;-webkit-user-select:none;user-select:none}.markdown-body pre code .gutter.linenumber{text-align:right;position:relative;display:inline-block;cursor:default;z-index:4;padding:0 8px 0 0;min-width:20px;box-sizing:content-box;color:#afafaf!important;border-right:3px solid #6ce26c!important}.markdown-body .flow-chart,.markdown-body .sequence-diagram,.vimeo,.youtube{text-align:center}.markdown-body pre code .gutter.linenumber>span:before{content:attr(data-linenumber)}.markdown-body pre code .code{float:left;margin:0 0 0 1pc}.markdown-body .gist .line-numbers{border-left:none;border-top:none;border-bottom:none}.markdown-body .gist .line-data{border:none}.markdown-body .gist table{border-spacing:0;border-collapse:inherit!important}.markdown-body code[data-gist-id]{background:0 0;padding:0}.ui-user-icon,.vimeo,.youtube{background-position:center center;background-repeat:no-repeat;background-size:contain}.markdown-body code[data-gist-id]:after,.markdown-body code[data-gist-id]:before{content:''}.markdown-body .flow-chart{margin-bottom:40px}.markdown-body[dir=rtl] pre{direction:ltr}.markdown-body[dir=rtl] code{direction:ltr;unicode-bidi:embed}svg{width:100%;max-height:70vh}.vimeo,.youtube{position:relative;cursor:pointer;display:table;max-width:540px;background-color:#000}.vimeo img,.youtube img{position:absolute;margin:auto;top:0;left:0;right:0;bottom:0}.vimeo .icon,.youtube .icon{position:absolute;height:auto;width:auto;top:50%;left:50%;margin-top:-40px;margin-left:-40px;color:#fff;opacity:.3;-webkit-transition:opacity .2s;transition:opacity .2s}.vimeo:hover .icon,.youtube:hover .icon{opacity:.6;-webkit-transition:opacity .2s;transition:opacity .2s}h1:hover .header-link,h2:hover .header-link,h3:hover .header-link,h4:hover .header-link,h5:hover .header-link,h6:hover .header-link{opacity:1;-webkit-transition:opacity .2s ease-in-out .1s;-moz-transition:opacity .2s ease-in-out .1s;-o-transition:opacity .2s ease-in-out .1s;transition:opacity .2s ease-in-out .1s}.header-link{position:relative;left:.5em;right:.5em;opacity:0;font-size:.8em;-webkit-transition:opacity .2s ease-in-out .1s;-moz-transition:opacity .2s ease-in-out .1s;-o-transition:opacity .2s ease-in-out .1s;transition:opacity .2s ease-in-out .1s}.ui-infobar{max-width:758px;margin-top:25px;margin-bottom:-25px;color:#777}.ui-toc{position:fixed;bottom:20px;z-index:10000}.ui-toc-label{opacity:.3;background-color:#ccc;border:none;-webkit-transition:opacity .2s;transition:opacity .2s}.ui-toc .open .ui-toc-label{opacity:1;color:#fff;-webkit-transition:opacity .2s;transition:opacity .2s}.ui-toc-label:focus{opacity:.3;background-color:#ccc;color:#000}.ui-toc-label:hover{opacity:1;background-color:#ccc;-webkit-transition:opacity .2s;transition:opacity .2s}.ui-toc-dropdown{margin-top:23px;margin-bottom:20px;padding-left:10px;padding-right:10px;max-width:45vw;width:25vw;max-height:65vh;overflow:auto;text-align:inherit}.ui-toc-dropdown[dir=rtl] .nav{padding-right:0;letter-spacing:.0029em}.ui-toc-dropdown a{overflow:hidden;text-overflow:ellipsis;white-space:pre}.ui-toc-dropdown .nav>li>a{display:block;padding:4px 20px;font-size:13px;font-weight:500;color:#767676}.ui-toc-dropdown .nav>li>a:focus,.ui-toc-dropdown .nav>li>a:hover{padding-left:19px;color:#000;text-decoration:none;background-color:transparent;border-left:1px solid #000}.ui-toc-dropdown[dir=rtl] .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav>li>a:hover{padding-right:19px;border-left:none;border-right:1px solid #000}.ui-toc-dropdown .nav>.active:focus>a,.ui-toc-dropdown .nav>.active:hover>a,.ui-toc-dropdown .nav>.active>a{padding-left:18px;font-weight:700;color:#000;background-color:transparent;border-left:2px solid #000}.ui-toc-dropdown[dir=rtl] .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav>.active>a{padding-right:18px;border-left:none;border-right:2px solid #000}.ui-toc-dropdown .nav .nav{display:none;padding-bottom:10px}.ui-toc-dropdown .nav>.active>ul,.ui-user-icon{display:block}.ui-toc-dropdown .nav .nav>li>a{padding-top:1px;padding-bottom:1px;padding-left:30px;font-size:9pt;font-weight:400}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a{padding-right:30px}.ui-toc-dropdown .nav .nav>li>ul>li>a{padding-top:1px;padding-bottom:1px;padding-left:40px;font-size:9pt;font-weight:400}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a{padding-right:40px}.ui-toc-dropdown .nav .nav>li>a:focus,.ui-toc-dropdown .nav .nav>li>a:hover{padding-left:29px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>a:hover{padding-right:29px}.ui-toc-dropdown .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown .nav .nav>li>ul>li>a:hover{padding-left:39px}.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:focus,.ui-toc-dropdown[dir=rtl] .nav .nav>li>ul>li>a:hover{padding-right:39px}.ui-toc-dropdown .nav .nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>a{padding-left:28px;font-weight:500}.ui-toc-dropdown[dir=rtl] .nav .nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>a{padding-right:28px}.ui-toc-dropdown .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown .nav .nav>.active>.nav>.active>a{padding-left:38px;font-weight:500}.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:focus>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active:hover>a,.ui-toc-dropdown[dir=rtl] .nav .nav>.active>.nav>.active>a{padding-right:38px}.ui-affix-toc{position:fixed;top:0;max-width:15vw;max-height:70vh;overflow:auto}.back-to-top,.go-to-bottom{display:block;padding:4px 10px;margin-top:10px;margin-left:10px;font-size:9pt;font-weight:500;color:#999}.back-to-top:focus,.back-to-top:hover,.go-to-bottom:focus,.go-to-bottom:hover{color:#563d7c;text-decoration:none}.go-to-bottom{margin-top:0}.ui-user-icon{width:20px;height:20px;border-radius:3px;margin-top:2px;margin-bottom:2px;margin-right:5px}.ui-user-icon.small,small .dropdown{display:inline-block}.ui-user-icon.small{width:18px;height:18px;vertical-align:middle;margin:0 0 .2em}small span{line-height:22px}small .dropdown a:focus,small .dropdown a:hover{text-decoration:none}.unselectable{-moz-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-o-user-select:none;user-select:none}@media print{blockquote,div,img,pre,table{page-break-inside:avoid!important}a[href]:after{font-size:9pt!important}}@font-face{font-family:'Source Code Pro';font-style:normal;font-weight:300;src:local('Source Code Pro Light'),local('SourceCodePro-Light'),url(https://fonts.gstatic.com/s/sourcecodepro/v6/leqv3v-yTsJNC7nFznSMqUBls_1aQwi4AfipSOlE3SU.ttf) format('truetype')}@font-face{font-family:'Source Code Pro';font-style:normal;font-weight:400;src:local('Source Code Pro'),local('SourceCodePro-Regular'),url(https://fonts.gstatic.com/s/sourcecodepro/v6/mrl8jkM18OlOQN8JLgasD1zCdIATDt8zXO3QNtzVeJ8.ttf) format('truetype')}@font-face{font-family:'Source Code Pro';font-style:normal;font-weight:500;src:local('Source Code Pro Medium'),local('SourceCodePro-Medium'),url(https://fonts.gstatic.com/s/sourcecodepro/v6/leqv3v-yTsJNC7nFznSMqdgxThF69EFTxeh70dQtJtE.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:normal;font-weight:300;src:local('Source Sans Pro Light'),local('SourceSansPro-Light'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/toadOcfmlt9b38dHJxOBGEBls_1aQwi4AfipSOlE3SU.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:normal;font-weight:400;src:local('Source Sans Pro'),local('SourceSansPro-Regular'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/ODelI1aHBYDBqgeIAH2zlFzCdIATDt8zXO3QNtzVeJ8.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:normal;font-weight:600;src:local('Source Sans Pro Semibold'),local('SourceSansPro-Semibold'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/toadOcfmlt9b38dHJxOBGGvd-IutAbwf5FQ8ZpuI2w4.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:italic;font-weight:300;src:local('Source Sans Pro Light Italic'),local('SourceSansPro-LightIt'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/fpTVHK8qsXbIeTHTrnQH6I48KljrVa8Zcyi9xGGohEU.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:italic;font-weight:400;src:local('Source Sans Pro Italic'),local('SourceSansPro-It'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/M2Jd71oPJhLKp0zdtTvoM6xot8ENfkYez2Lz7rcrw70.ttf) format('truetype')}@font-face{font-family:'Source Sans Pro';font-style:italic;font-weight:600;src:local('Source Sans Pro Semibold Italic'),local('SourceSansPro-SemiboldIt'),url(https://fonts.gstatic.com/s/sourcesanspro/v9/fpTVHK8qsXbIeTHTrnQH6KjMMkbXdLGS8FpAnMJn5J0.ttf) format('truetype')}@font-face{font-family:'Source Serif Pro';font-style:normal;font-weight:400;src:local('Source Serif Pro'),local('SourceSerifPro-Regular'),url(https://fonts.gstatic.com/s/sourceserifpro/v4/CeUM4np2c42DV49nanp55WdjwOOpWxWrsXXkZJyNRnI.ttf) format('truetype')}body{font-smoothing:subpixel-antialiased!important;-webkit-font-smoothing:subpixel-antialiased!important;-moz-osx-font-smoothing:auto!important;text-shadow:1px 1px 1px rgba(0,0,0,.004);-webkit-overflow-scrolling:touch;font-family:"Source Sans Pro",Helvetica,Arial,"Microsoft JhengHei UI","Meiryo UI","MS Pゴシック","MS PGothic",sans-serif;letter-spacing:.025em}:focus{outline:0!important}::-moz-focus-inner{border:0!important}body.modal-open{overflow-y:auto;padding-right:0!important} \ No newline at end of file
diff --git a/public/css/index.css b/public/css/index.css
index 1f20e926..3be56065 100644
--- a/public/css/index.css
+++ b/public/css/index.css
@@ -156,18 +156,7 @@ body {
.ui-user-name {
margin-top: 2px;
}
-.ui-user-icon {
- width: 20px;
- height: 20px;
- display: block;
- border-radius: 3px;
- margin-top: 2px;
- margin-bottom: 2px;
- margin-right: 5px;
- background-position: center center;
- background-repeat: no-repeat;
- background-size: contain;
-}
+
.ui-user-status {
margin-top: 5px;
}
@@ -213,7 +202,6 @@ body {
width: 0px;
position: absolute;
border-right: none;
- transition: left 0.1s, top 0.1s;
}
.dropdown-menu.other-cursor {
transition: none;
@@ -243,6 +231,10 @@ div[contenteditable]:empty:not(:focus):before{
max-height: 80vh;
overflow: auto;
}
+.dropdown-menu.list.small {
+ max-height: 40vh;
+ overflow: auto;
+}
.dropdown-menu.list::-webkit-scrollbar {
display: none;
}
@@ -279,6 +271,25 @@ div[contenteditable]:empty:not(:focus):before{
display: block;
}
+.info-label {
+ width: 36%;
+ text-align: right;
+ position: relative;
+ display: inline-block;
+ margin-right: 6px;
+}
+.popover {
+ width: 100%;
+ font-family: inherit !important;
+ line-height: 25px;
+}
+
+.text-ellipsis {
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+}
+
.cm-trailing-space-a:before,
.cm-trailing-space-b:before,
.cm-trailing-space-new-line:before {
diff --git a/public/css/markdown.css b/public/css/markdown.css
index 6a98212a..f9009d58 100644
--- a/public/css/markdown.css
+++ b/public/css/markdown.css
@@ -36,7 +36,6 @@
text-align: right;
position: relative;
display: inline-block;
- float: right;
cursor: default;
z-index: 4;
padding: 0 8px 0 0;
@@ -89,6 +88,18 @@
.markdown-body .flow-chart {
margin-bottom: 40px;
}
+
+/*fixed style for rtl in pre and code*/
+
+.markdown-body[dir='rtl'] pre {
+ direction: ltr;
+}
+
+.markdown-body[dir='rtl'] code {
+ direction: ltr;
+ unicode-bidi: embed;
+}
+
svg {
width: 100%;
max-height: 70vh;
diff --git a/public/js/extra.js b/public/js/extra.js
index 07e85acc..e624bfaf 100644
--- a/public/js/extra.js
+++ b/public/js/extra.js
@@ -1,15 +1,32 @@
//auto update last change
var lastchangetime = null;
-var lastchangeui = null;
+var lastchangeui = {
+ time: $(".ui-lastchange"),
+ user: $(".ui-lastchangeuser"),
+ nouser: $(".ui-no-lastchangeuser")
+}
function updateLastChange() {
if (lastchangetime && lastchangeui) {
- lastchangeui.html('&nbsp;<i class="fa fa-clock-o"></i> change ' + moment(lastchangetime).fromNow());
- lastchangeui.attr('title', moment(lastchangetime).format('llll'));
+ lastchangeui.time.html(moment(lastchangetime).fromNow());
+ lastchangeui.time.attr('title', moment(lastchangetime).format('llll'));
}
}
setInterval(updateLastChange, 60000);
+function updateLastChangeUser(data) {
+ if (data.lastchangeuserprofile) {
+ var icon = lastchangeui.user.children('i');
+ icon.attr('title', data.lastchangeuserprofile.name).tooltip('fixTitle');
+ icon.attr('style', 'background-image:url(' + data.lastchangeuserprofile.photo + ')');
+ lastchangeui.user.show();
+ lastchangeui.nouser.hide();
+ } else {
+ lastchangeui.user.hide();
+ lastchangeui.nouser.show();
+ }
+}
+
//get title
function getTitle(view) {
var h1s = view.find("h1");
@@ -48,6 +65,57 @@ function slugifyWithUTF8(text) {
return newText;
}
+//parse meta
+function parseMeta(md, view, toc, tocAffix) {
+ var robots = null;
+ var lang = null;
+ var dir = null;
+ var breaks = true;
+ if (md && md.meta) {
+ var meta = md.meta;
+ robots = meta.robots;
+ lang = meta.lang;
+ dir = meta.dir;
+ breaks = meta.breaks;
+ }
+ //robots meta
+ var robotsMeta = $('meta[name=robots]');
+ if (robots) {
+ if (robotsMeta.length > 0)
+ robotsMeta.attr('content', robots);
+ else
+ $('head').prepend('<meta name="robots" content="' + robots + '">')
+ }
+ else
+ robotsMeta.remove();
+ //text language
+ if (lang) {
+ view.attr('lang', lang);
+ toc.attr('lang', lang);
+ tocAffix.attr('lang', lang);
+ } else {
+ view.removeAttr('lang');
+ toc.removeAttr('lang');
+ tocAffix.removeAttr('lang');
+ }
+ //text direction
+ if (dir) {
+ view.attr('dir', dir);
+ toc.attr('dir', dir);
+ tocAffix.attr('dir', dir);
+ } else {
+ view.removeAttr('dir');
+ toc.removeAttr('dir');
+ tocAffix.removeAttr('dir');
+ }
+ //breaks
+ if (typeof breaks === 'boolean' && !breaks) {
+ md.options.breaks = false;
+ } else {
+ md.options.breaks = true;
+ }
+}
+
var viewAjaxCallback = null;
//regex for extra tags
@@ -329,7 +397,10 @@ function exportToHTML(view) {
css: css,
html: src[0].outerHTML,
toc: toc.html(),
- 'toc-affix': tocAffix.html()
+ 'toc-affix': tocAffix.html(),
+ robots: (md && md.meta && md.meta.robots) ? '<meta name="robots" content="' + md.meta.robots + '">' : null,
+ lang: (md && md.meta && md.meta.lang) ? 'lang="' + md.meta.lang + '"' : null,
+ dir: (md && md.meta && md.meta.dir) ? 'dir="' + md.meta.dir + '"' : null
};
var html = template(context);
// console.log(html);
@@ -737,6 +808,49 @@ var speakerdeckPlugin = new Plugin(
return div[0].outerHTML;
}
);
+
+//yaml meta, from https://github.com/eugeneware/remarkable-meta
+function get(state, line) {
+ var pos = state.bMarks[line];
+ var max = state.eMarks[line];
+ return state.src.substr(pos, max - pos);
+}
+
+function meta(state, start, end, silent) {
+ if (start !== 0 || state.blkIndent !== 0) return false;
+ if (state.tShift[start] < 0) return false;
+ if (!get(state, start).match(/^---$/)) return false;
+
+ var data = [];
+ for (var line = start + 1; line < end; line++) {
+ var str = get(state, line);
+ if (str.match(/^(\.{3}|-{3})$/)) break;
+ if (state.tShift[line] < 0) break;
+ data.push(str);
+ }
+
+ if (line >= end) return false;
+
+ try {
+ md.meta = jsyaml.safeLoad(data.join('\n')) || {};
+ } catch(err) {
+ console.error(err);
+ return false;
+ }
+
+ state.line = line + 1;
+
+ return true;
+}
+
+function metaPlugin(md) {
+ md.meta = md.meta || {};
+ md.block.ruler.before('code', 'meta', meta, {
+ alt: []
+ });
+}
+
+md.use(metaPlugin);
md.use(youtubePlugin);
md.use(vimeoPlugin);
md.use(gistPlugin);
diff --git a/public/js/index.js b/public/js/index.js
index e9be3de0..34cca1f8 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -320,6 +320,8 @@ var ui = {
},
infobar: {
lastchange: $(".ui-lastchange"),
+ lastchangeuser: $(".ui-lastchangeuser"),
+ nolastchangeuser: $(".ui-no-lastchangeuser"),
permission: {
permission: $(".ui-permission"),
label: $(".ui-permission-label"),
@@ -387,9 +389,9 @@ function setHaveUnreadChanges(bool) {
function updateTitleReminder() {
if (!loaded) return;
if (haveUnreadChanges) {
- document.title = '• ' + renderTitle(ui.area.view);
+ document.title = '• ' + renderTitle(ui.area.markdown);
} else {
- document.title = renderTitle(ui.area.view);
+ document.title = renderTitle(ui.area.markdown);
}
}
@@ -465,6 +467,8 @@ $(document).ready(function () {
upClass: 'navbar-hide',
downClass: 'navbar-show'
});
+ //tooltip
+ $('[data-toggle="tooltip"]').tooltip();
});
//when page resize
$(window).resize(function () {
@@ -1165,8 +1169,8 @@ socket.on('version', function (data) {
});
socket.on('check', function (data) {
lastchangetime = data.updatetime;
- lastchangeui = ui.infobar.lastchange;
updateLastChange();
+ updateLastChangeUser(data);
});
socket.on('permission', function (data) {
updatePermission(data.permission);
@@ -1182,8 +1186,8 @@ socket.on('refresh', function (data) {
owner = data.owner;
updatePermission(data.permission);
lastchangetime = data.updatetime;
- lastchangeui = ui.infobar.lastchange;
updateLastChange();
+ updateLastChangeUser(data);
if (!loaded) {
changeMode(currentMode);
loaded = true;
@@ -1884,15 +1888,18 @@ var lastResult = null;
function updateViewInner() {
if (currentMode == modeType.edit || !isDirty) return;
var value = editor.getValue();
+ md.meta = {};
+ md.render(value); //only for get meta
+ parseMeta(md, ui.area.markdown, $('#toc'), $('#toc-affix'));
var result = postProcess(md.render(value)).children().toArray();
partialUpdate(result, lastResult, ui.area.markdown.children().toArray());
if (result && lastResult && result.length != lastResult.length)
updateDataAttrs(result, ui.area.markdown.children().toArray());
lastResult = $(result).clone();
- finishView(ui.area.view);
- autoLinkify(ui.area.view);
- deduplicatedHeaderId(ui.area.view);
- renderTOC(ui.area.view);
+ finishView(ui.area.markdown);
+ autoLinkify(ui.area.markdown);
+ deduplicatedHeaderId(ui.area.markdown);
+ renderTOC(ui.area.markdown);
generateToc('toc');
generateToc('toc-affix');
generateScrollspy();
diff --git a/public/js/pretty.js b/public/js/pretty.js
index ff393cac..43e833c2 100644
--- a/public/js/pretty.js
+++ b/public/js/pretty.js
@@ -1,5 +1,8 @@
var markdown = $(".markdown-body");
var text = $('<textarea/>').html(markdown.html()).text();
+md.meta = {};
+md.render(text); //only for get meta
+parseMeta(md, markdown, $('#toc'), $('#toc-affix'));
var result = postProcess(md.render(text));
markdown.html(result.html());
$(document.body).show();
@@ -10,8 +13,7 @@ renderTOC(markdown);
generateToc('toc');
generateToc('toc-affix');
smoothHashScroll();
-lastchangetime = $('.ui-lastchange').text();
-lastchangeui = $('.ui-lastchange');
+lastchangetime = lastchangeui.time.text();
updateLastChange();
var url = window.location.pathname;
$('.ui-edit').attr('href', url + '/edit');
@@ -68,6 +70,8 @@ $(window).resize(function () {
$(document).ready(function () {
windowResize();
generateScrollspy();
+ //tooltip
+ $('[data-toggle="tooltip"]').tooltip();
});
function scrollToTop() {
diff --git a/public/views/body.ejs b/public/views/body.ejs
index f47cf175..b3a49db8 100644
--- a/public/views/body.ejs
+++ b/public/views/body.ejs
@@ -5,7 +5,12 @@
<div class="ui-view-area">
<div class="ui-infobar container-fluid unselectable hidden-print">
<small>
- <span class="ui-lastchange text-uppercase"></span>
+ <span>
+ <span class="ui-lastchangeuser">&thinsp;<i class="ui-user-icon small" data-toggle="tooltip" data-placement="right"></i></span>
+ <span class="ui-no-lastchangeuser">&thinsp;<i class="fa fa-clock-o"></i></span>
+ &nbsp;<span class="text-uppercase">changed</span>
+ <span class="ui-lastchange text-uppercase"></span>
+ </span>
<span class="ui-permission dropdown pull-right">
<a id="permissionLabel" class="ui-permission-label text-uppercase" data-target="#" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
</a>
diff --git a/public/views/foot.ejs b/public/views/foot.ejs
index ee04d440..c042438d 100644
--- a/public/views/foot.ejs
+++ b/public/views/foot.ejs
@@ -6,6 +6,7 @@
<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/TweenMax.min.js" defer></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.18.0/jquery.gsap.min.js" defer></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.7/socket.io.min.js" defer></script>
+<script src="//cdnjs.cloudflare.com/ajax/libs/js-yaml/3.4.6/js-yaml.min.js" defer></script>
<% } else { %>
<script src="/vendor/spin.js/spin.min.js" defer></script>
<script src="/vendor/jquery/dist/jquery.min.js"></script>
@@ -14,6 +15,7 @@
<script src="/vendor/gsap/src/minified/TweenMax.min.js" defer></script>
<script src="/vendor/gsap/src/minified/jquery.gsap.min.js" defer></script>
<script src="/vendor/socket.io-client/socket.io.js" defer></script>
+<script src="/vendor/js-yaml/dist/js-yaml.min.js" defer></script>
<% } %>
<script src="/vendor/jquery-ui/jquery-ui.min.js" defer></script>
<!--codemirror-->
diff --git a/public/views/head.ejs b/public/views/head.ejs
index fa690108..795665b4 100644
--- a/public/views/head.ejs
+++ b/public/views/head.ejs
@@ -4,6 +4,9 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="mobile-web-app-capable" content="yes">
+<% if(typeof robots !== 'undefined' && robots) { %>
+<meta name="robots" content="<%- robots %>">
+<% } %>
<title><%- title %></title>
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
diff --git a/public/views/html.hbs b/public/views/html.hbs
index e3aa1331..5c7e6bea 100644
--- a/public/views/html.hbs
+++ b/public/views/html.hbs
@@ -9,6 +9,7 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="mobile-web-app-capable" content="yes">
+ {{{robots}}}
<title>
{{title}}
</title>
@@ -42,7 +43,7 @@
</ul>
</div>
</div>
- <div id="toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;">
+ <div id="toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;" {{{lang}}} {{{dir}}}>
{{{toc-affix}}}
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
diff --git a/public/views/pretty.ejs b/public/views/pretty.ejs
index 46c559f9..6fe02827 100644
--- a/public/views/pretty.ejs
+++ b/public/views/pretty.ejs
@@ -8,6 +8,9 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="mobile-web-app-capable" content="yes">
+ <% if(typeof robots !== 'undefined' && robots) { %>
+ <meta name="robots" content="<%- robots %>">
+ <% } %>
<title><%- title %></title>
<link rel="icon" type="image/png" href="<%- url %>/favicon.png">
<link rel="apple-touch-icon" href="<%- url %>/apple-touch-icon.png">
@@ -37,13 +40,19 @@
<body style="display:none;">
<div class="ui-infobar container-fluid unselectable hidden-print">
<small>
- <span class="ui-lastchange text-uppercase"><%- updatetime %></span>
- <span class="pull-right"><%- viewcount %> views <a href="#" class="ui-edit" title="Edit this note"><i class="fa fa-pencil"></i></a></span>
+ <span>
+ <% if(lastchangeuserprofile) { %>
+ <span class="ui-lastchangeuser">&thinsp;<i class="ui-user-icon small" style="background-image: url(<%- lastchangeuserprofile.photo %>);" data-toggle="tooltip" data-placement="right" title="<%- lastchangeuserprofile.name %>"></i></span>
+ <% } else { %>
+ <span class="ui-no-lastchangeuser">&thinsp;<i class="fa fa-clock-o"></i></span>
+ <% } %>
+ &nbsp;<span class="text-uppercase">changed</span>
+ <span class="ui-lastchange text-uppercase"><%- updatetime %></span>
+ </span>
+ <span class="pull-right"><%- viewcount %> views <a href="#" class="ui-edit" title="Edit this note"><i class="fa fa-fw fa-pencil"></i></a></span>
</small>
</div>
- <div id="doc" class="container markdown-body">
-<%- body %>
- </div>
+ <div id="doc" class="container markdown-body"><%- body %></div>
<div class="ui-toc dropup unselectable hidden-print" style="display:none;">
<div class="pull-right dropdown">
<a id="tocLabel" class="ui-toc-label btn btn-default" data-target="#" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" title="Table of content">
@@ -60,9 +69,11 @@
<% if(useCDN) { %>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" defer></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.4.6/js-yaml.min.js" defer></script>
<% } else { %>
<script src="<%- url %>/vendor/jquery/dist/jquery.min.js"></script>
<script src="<%- url %>/vendor/bootstrap/dist/js/bootstrap.min.js" defer></script>
+<script src="<%- url %>/vendor/js-yaml/dist/js-yaml.min.js" defer></script>
<% } %>
<script src="<%- url %>/vendor/lz-string.min.js" defer></script>
<script src="<%- url %>/vendor/remarkable.min.js" defer></script>