From a013c9d3bc0eb98c935e80bdb694c1a1cf7bd4c4 Mon Sep 17 00:00:00 2001 From: Wu Cheng-Han Date: Mon, 15 Aug 2016 11:25:27 +0800 Subject: Update slide mode to show extra info and support url actions and support disqus via yaml-metadata --- app.js | 2 ++ lib/models/note.js | 2 ++ lib/response.js | 39 +++++++++++++++++++++++++++++---- public/css/slide.css | 26 ++++++++++++++++++++++ public/docs/yaml-metadata.md | 11 ++++++++++ public/js/slide.js | 11 ++++++++++ public/vendor/bootstrap/tooltip.min.css | 14 ++++++++++++ public/vendor/bootstrap/tooltip.min.js | 11 ++++++++++ public/views/disqus.ejs | 14 ++++++++++++ public/views/pretty.ejs | 5 +++++ public/views/slide.ejs | 24 ++++++++++++++++++++ 11 files changed, 155 insertions(+), 4 deletions(-) mode change 100644 => 100755 lib/response.js create mode 100755 public/vendor/bootstrap/tooltip.min.css create mode 100755 public/vendor/bootstrap/tooltip.min.js create mode 100644 public/views/disqus.ejs diff --git a/app.js b/app.js index 98b2b983..54a6baac 100644 --- a/app.js +++ b/app.js @@ -464,6 +464,8 @@ app.get("/s/:shortid", response.showPublishNote); app.get("/s/:shortid/:action", response.publishNoteActions); //get publish slide app.get("/p/:shortid", response.showPublishSlide); +//publish slide actions +app.get("/p/:shortid/:action", response.publishSlideActions); //get note by id app.get("/:noteId", response.showNote); //note actions diff --git a/lib/models/note.js b/lib/models/note.js index 81013047..d1c073e9 100644 --- a/lib/models/note.js +++ b/lib/models/note.js @@ -241,6 +241,8 @@ module.exports = function (sequelize, DataTypes) { _meta.robots = meta.robots; if (meta.GA && (typeof meta.GA == "string" || typeof meta.GA == "number")) _meta.GA = meta.GA; + if (meta.disqus && (typeof meta.disqus == "string" || typeof meta.disqus == "number")) + _meta.disqus = meta.disqus; if (meta.slideOptions && (typeof meta.slideOptions == "object")) _meta.slideOptions = meta.slideOptions; } diff --git a/lib/response.js b/lib/response.js old mode 100644 new mode 100755 index 23818da8..39d83ca2 --- a/lib/response.js +++ b/lib/response.js @@ -47,6 +47,7 @@ var response = { showIndex: showIndex, noteActions: noteActions, publishNoteActions: publishNoteActions, + publishSlideActions: publishSlideActions, githubActions: githubActions, gitlabActions: gitlabActions }; @@ -241,7 +242,8 @@ function showPublishNote(req, res, next) { useCDN: config.usecdn, lastchangeuserprofile: note.lastchangeuser ? models.User.parseProfile(note.lastchangeuser.profile) : null, robots: meta.robots || false, //default allow robots - GA: meta.GA + GA: meta.GA, + disqus: meta.disqus }; return renderPublish(data, res); }).catch(function (err) { @@ -410,6 +412,20 @@ function publishNoteActions(req, res, next) { }); } +function publishSlideActions(req, res, next) { + findNote(req, res, function (note) { + var action = req.params.action; + switch (action) { + case "edit": + res.redirect(config.serverurl + '/' + (note.alias ? note.alias : LZString.compressToBase64(note.id))); + break; + default: + res.redirect(config.serverurl + '/p/' + note.shortid); + break; + } + }); +} + function githubActions(req, res, next) { var noteId = req.params.noteId; findNote(req, res, function (note) { @@ -530,6 +546,13 @@ function gitlabActionProjects(req, res, note) { } function showPublishSlide(req, res, next) { + var include = [{ + model: models.User, + as: "owner" + }, { + model: models.User, + as: "lastchangeuser" + }]; findNote(req, res, function (note) { // force to use short id var shortid = req.params.shortid; @@ -549,26 +572,34 @@ function showPublishSlide(req, res, next) { //na } if (!meta) meta = {}; + var createtime = note.createdAt; + var updatetime = note.lastchangeAt; var text = S(body).escapeHTML().s; var title = models.Note.decodeTitle(note.title); title = models.Note.generateWebTitle(meta.title || title); var slides = md.slidify(text, slideOptions); var origin = config.serverurl; var data = { - url: origin, title: title, description: meta.description, + viewcount: note.viewcount, + createtime: createtime, + updatetime: updatetime, + url: origin, slides: slides, meta: JSON.stringify(obj.meta || {}), + useCDN: config.usecdn, + lastchangeuserprofile: note.lastchangeuser ? models.User.parseProfile(note.lastchangeuser.profile) : null, + robots: meta.robots || false, //default allow robots GA: meta.GA, - useCDN: config.usecdn + disqus: meta.disqus }; return renderPublishSlide(data, res); }).catch(function (err) { logger.error(err); return response.errorInternalError(res); }); - }); + }, include); } function renderPublishSlide(data, res) { diff --git a/public/css/slide.css b/public/css/slide.css index df04fae1..bccb7e42 100644 --- a/public/css/slide.css +++ b/public/css/slide.css @@ -264,3 +264,29 @@ pre.mermaid > svg { direction: rtl; font-family: inherit; } + +.text-uppercase { + text-transform: uppercase; +} + +.footer { + background-color: white; + padding: 25px 15px; +} + +.footer > * { + margin-left: auto; + margin-right: auto; + max-width: 758px; +} + +.reveal { + height: 100vh; +} + +.reveal .progress, +.reveal .slide-number, +.reveal .playback, +.reveal .controls { + position: absolute; +} diff --git a/public/docs/yaml-metadata.md b/public/docs/yaml-metadata.md index d22fccda..7158104b 100644 --- a/public/docs/yaml-metadata.md +++ b/public/docs/yaml-metadata.md @@ -117,6 +117,17 @@ This option allow you to enable Google Analytics with your ID. GA: UA-12345667-8 ``` +disqus +--- +This option allow you to enable Disqus with your shortname. + +> default: not set (which won't enable) + +**Example** +```xml +disqus: hackmd +``` + slideOptions --- This option allow you provide custom options to slide mode. diff --git a/public/js/slide.js b/public/js/slide.js index fe3cb1e8..e45f78a6 100644 --- a/public/js/slide.js +++ b/public/js/slide.js @@ -1,6 +1,17 @@ var body = $(".slides").html(); $(".slides").html(S(body).unescapeHTML().s); +createtime = lastchangeui.time.attr('data-createtime'); +lastchangetime = lastchangeui.time.attr('data-updatetime'); +updateLastChange(); +var url = window.location.pathname; +$('.ui-edit').attr('href', url + '/edit'); + +$(document).ready(function () { + //tooltip + $('[data-toggle="tooltip"]').tooltip(); +}); + function extend() { var target = {}; for (var i = 0; i < arguments.length; i++) { diff --git a/public/vendor/bootstrap/tooltip.min.css b/public/vendor/bootstrap/tooltip.min.css new file mode 100755 index 00000000..4c1c1caa --- /dev/null +++ b/public/vendor/bootstrap/tooltip.min.css @@ -0,0 +1,14 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! + * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=f461126998f11cadc491b2b443db2a1b) + * Config saved to config.json and https://gist.github.com/f461126998f11cadc491b2b443db2a1b + *//*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height, visibility;-o-transition-property:height, visibility;transition-property:height, visibility;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:12px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.clearfix:before,.clearfix:after{content:" ";display:table}.clearfix:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed} \ No newline at end of file diff --git a/public/vendor/bootstrap/tooltip.min.js b/public/vendor/bootstrap/tooltip.min.js new file mode 100755 index 00000000..6968d747 --- /dev/null +++ b/public/vendor/bootstrap/tooltip.min.js @@ -0,0 +1,11 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! + * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=9ca9e711ecf93a5859df188c8b394683) + * Config saved to config.json and https://gist.github.com/9ca9e711ecf93a5859df188c8b394683 + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(t){"use strict";var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1==e[0]&&9==e[1]&&e[2]<1||e[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(t){"use strict";function e(e){return this.each(function(){var o=t(this),n=o.data("bs.tooltip"),s="object"==typeof e&&e;!n&&/destroy|hide/.test(e)||(n||o.data("bs.tooltip",n=new i(this,s)),"string"==typeof e&&n[e]())})}var i=function(t,e){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",t,e)};i.VERSION="3.3.7",i.TRANSITION_DURATION=150,i.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},i.prototype.init=function(e,i,o){if(this.enabled=!0,this.type=e,this.$element=t(i),this.options=this.getOptions(o),this.$viewport=this.options.viewport&&t(t.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var n=this.options.trigger.split(" "),s=n.length;s--;){var r=n[s];if("click"==r)this.$element.on("click."+this.type,this.options.selector,t.proxy(this.toggle,this));else if("manual"!=r){var a="hover"==r?"mouseenter":"focusin",p="hover"==r?"mouseleave":"focusout";this.$element.on(a+"."+this.type,this.options.selector,t.proxy(this.enter,this)),this.$element.on(p+"."+this.type,this.options.selector,t.proxy(this.leave,this))}}this.options.selector?this._options=t.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},i.prototype.getDefaults=function(){return i.DEFAULTS},i.prototype.getOptions=function(e){return e=t.extend({},this.getDefaults(),this.$element.data(),e),e.delay&&"number"==typeof e.delay&&(e.delay={show:e.delay,hide:e.delay}),e},i.prototype.getDelegateOptions=function(){var e={},i=this.getDefaults();return this._options&&t.each(this._options,function(t,o){i[t]!=o&&(e[t]=o)}),e},i.prototype.enter=function(e){var i=e instanceof this.constructor?e:t(e.currentTarget).data("bs."+this.type);return i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i)),e instanceof t.Event&&(i.inState["focusin"==e.type?"focus":"hover"]=!0),i.tip().hasClass("in")||"in"==i.hoverState?void(i.hoverState="in"):(clearTimeout(i.timeout),i.hoverState="in",i.options.delay&&i.options.delay.show?void(i.timeout=setTimeout(function(){"in"==i.hoverState&&i.show()},i.options.delay.show)):i.show())},i.prototype.isInStateTrue=function(){for(var t in this.inState)if(this.inState[t])return!0;return!1},i.prototype.leave=function(e){var i=e instanceof this.constructor?e:t(e.currentTarget).data("bs."+this.type);return i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i)),e instanceof t.Event&&(i.inState["focusout"==e.type?"focus":"hover"]=!1),i.isInStateTrue()?void 0:(clearTimeout(i.timeout),i.hoverState="out",i.options.delay&&i.options.delay.hide?void(i.timeout=setTimeout(function(){"out"==i.hoverState&&i.hide()},i.options.delay.hide)):i.hide())},i.prototype.show=function(){var e=t.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(e);var o=t.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(e.isDefaultPrevented()||!o)return;var n=this,s=this.tip(),r=this.getUID(this.type);this.setContent(),s.attr("id",r),this.$element.attr("aria-describedby",r),this.options.animation&&s.addClass("fade");var a="function"==typeof this.options.placement?this.options.placement.call(this,s[0],this.$element[0]):this.options.placement,p=/\s?auto?\s?/i,l=p.test(a);l&&(a=a.replace(p,"")||"top"),s.detach().css({top:0,left:0,display:"block"}).addClass(a).data("bs."+this.type,this),this.options.container?s.appendTo(this.options.container):s.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var h=this.getPosition(),u=s[0].offsetWidth,f=s[0].offsetHeight;if(l){var c=a,d=this.getPosition(this.$viewport);a="bottom"==a&&h.bottom+f>d.bottom?"top":"top"==a&&h.top-fd.width?"left":"left"==a&&h.left-ur.top+r.height&&(n.top=r.top+r.height-p)}else{var l=e.left-s,h=e.left+s+i;lr.right&&(n.left=r.left+r.width-h)}return n},i.prototype.getTitle=function(){var t,e=this.$element,i=this.options;return t=e.attr("data-original-title")||("function"==typeof i.title?i.title.call(e[0]):i.title)},i.prototype.getUID=function(t){do t+=~~(1e6*Math.random());while(document.getElementById(t));return t},i.prototype.tip=function(){if(!this.$tip&&(this.$tip=t(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},i.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},i.prototype.enable=function(){this.enabled=!0},i.prototype.disable=function(){this.enabled=!1},i.prototype.toggleEnabled=function(){this.enabled=!this.enabled},i.prototype.toggle=function(e){var i=this;e&&(i=t(e.currentTarget).data("bs."+this.type),i||(i=new this.constructor(e.currentTarget,this.getDelegateOptions()),t(e.currentTarget).data("bs."+this.type,i))),e?(i.inState.click=!i.inState.click,i.isInStateTrue()?i.enter(i):i.leave(i)):i.tip().hasClass("in")?i.leave(i):i.enter(i)},i.prototype.destroy=function(){var t=this;clearTimeout(this.timeout),this.hide(function(){t.$element.off("."+t.type).removeData("bs."+t.type),t.$tip&&t.$tip.detach(),t.$tip=null,t.$arrow=null,t.$viewport=null,t.$element=null})};var o=t.fn.tooltip;t.fn.tooltip=e,t.fn.tooltip.Constructor=i,t.fn.tooltip.noConflict=function(){return t.fn.tooltip=o,this}}(jQuery),+function(t){"use strict";function e(){var t=document.createElement("bootstrap"),e={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var i in e)if(void 0!==t.style[i])return{end:e[i]};return!1}t.fn.emulateTransitionEnd=function(e){var i=!1,o=this;t(this).one("bsTransitionEnd",function(){i=!0});var n=function(){i||t(o).trigger(t.support.transition.end)};return setTimeout(n,e),this},t(function(){t.support.transition=e(),t.support.transition&&(t.event.special.bsTransitionEnd={bindType:t.support.transition.end,delegateType:t.support.transition.end,handle:function(e){return t(e.target).is(this)?e.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery); \ No newline at end of file diff --git a/public/views/disqus.ejs b/public/views/disqus.ejs new file mode 100644 index 00000000..ed991a41 --- /dev/null +++ b/public/views/disqus.ejs @@ -0,0 +1,14 @@ +
+ + + \ No newline at end of file diff --git a/public/views/pretty.ejs b/public/views/pretty.ejs index 779e7da1..3afb2a1a 100644 --- a/public/views/pretty.ejs +++ b/public/views/pretty.ejs @@ -72,6 +72,11 @@ + <% if(typeof disqus !== 'undefined' && disqus) { %> +
+ <%- include disqus %> +
+ <% } %> diff --git a/public/views/slide.ejs b/public/views/slide.ejs index 8a8fbae0..5b728b21 100644 --- a/public/views/slide.ejs +++ b/public/views/slide.ejs @@ -23,6 +23,7 @@ <% } %> + @@ -52,6 +53,28 @@ + + @@ -70,6 +93,7 @@ <% } %> + -- cgit v1.2.3