diff --git a/deployments/Dockerfile b/deployments/Dockerfile index 1e8e3dbb..532a099c 100644 --- a/deployments/Dockerfile +++ b/deployments/Dockerfile @@ -1,8 +1,10 @@ ARG RUNTIME +ARG BUILDPACK -FROM hackmdio/buildpack:node-10-0baafb79 as BUILD +FROM $BUILDPACK as BUILD COPY --chown=hackmd:hackmd . . +ENV QT_QPA_PLATFORM=offscreen RUN set -xe && \ git reset --hard && \ @@ -18,6 +20,7 @@ RUN set -xe && \ FROM $RUNTIME USER hackmd +ENV QT_QPA_PLATFORM=offscreen WORKDIR /home/hackmd/app COPY --chown=1500:1500 --from=BUILD /home/hackmd/app . RUN npm install --production && npm cache clean --force && rm -rf /tmp/{core-js-banners,phantomjs} diff --git a/deployments/build.sh b/deployments/build.sh index bc30747c..bf49aef6 100755 --- a/deployments/build.sh +++ b/deployments/build.sh @@ -1,8 +1,13 @@ #!/usr/bin/env bash -set -euo pipefail +set -eo pipefail set -x +if [[ -z $1 || -z $2 ]];then + echo "build.sh [runtime image] [buildpack image]" + exit 1 +fi + CURRENT_DIR=$(dirname "$BASH_SOURCE") GIT_SHA1="$(git rev-parse HEAD)" @@ -11,6 +16,6 @@ GIT_TAG=$(git describe --exact-match --tags $(git log -n1 --pretty='%h') 2>/dev/ DOCKER_TAG="${GIT_TAG:-$GIT_SHORT_ID}" -docker build --build-arg RUNTIME=hackmdio/runtime:node-10-d27854ef -t "hackmdio/hackmd:$DOCKER_TAG" -f "$CURRENT_DIR/Dockerfile" "$CURRENT_DIR/.." +docker build --build-arg RUNTIME=$1 --build-arg BUILDPACK=$2 -t "hackmdio/hackmd:$DOCKER_TAG" -f "$CURRENT_DIR/Dockerfile" "$CURRENT_DIR/.." -docker build --build-arg RUNTIME=hackmdio/runtime:node-10-cjk-d27854ef -t "hackmdio/hackmd:$DOCKER_TAG-cjk" -f "$CURRENT_DIR/Dockerfile" "$CURRENT_DIR/.." +docker build --build-arg RUNTIME=$1 --build-arg BUILDPACK=$2 -t "hackmdio/hackmd:$DOCKER_TAG-cjk" -f "$CURRENT_DIR/Dockerfile" "$CURRENT_DIR/.." diff --git a/public/js/extra.js b/public/js/extra.js index 2fcb1b6a..cbc98758 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -27,6 +27,8 @@ import { renderFretBoard } from './lib/renderer/fretboard/fretboard' import './lib/renderer/lightbox' import { renderCSVPreview } from './lib/renderer/csvpreview' +import { escapeAttrValue } from './render' + import markdownit from 'markdown-it' import markdownitContainer from 'markdown-it-container' @@ -202,18 +204,15 @@ export function parseMeta (md, edit, view, toc, tocAffix) { dir = meta.dir breaks = meta.breaks } - // text language - if (lang && typeof lang === 'string') { - view.attr('lang', lang) - toc.attr('lang', lang) - tocAffix.attr('lang', lang) - if (edit) { edit.attr('lang', lang) } - } else { - view.removeAttr('lang') - toc.removeAttr('lang') - tocAffix.removeAttr('lang') - if (edit) { edit.removeAttr('lang', lang) } + if (!lang || typeof lang !== 'string') { + lang = 'en' } + // text language + view.attr('lang', lang) + toc.attr('lang', lang) + tocAffix.attr('lang', lang) + if (edit) { edit.attr('lang', lang) } + // text direction if (dir && typeof dir === 'string') { view.attr('dir', dir) @@ -817,8 +816,8 @@ export function exportToHTML (view) { html: src[0].outerHTML, 'ui-toc': toc.html(), 'ui-toc-affix': tocAffix.html(), - lang: (md && md.meta && md.meta.lang) ? `lang="${md.meta.lang}"` : null, - dir: (md && md.meta && md.meta.dir) ? `dir="${md.meta.dir}"` : null + lang: (md && md.meta && md.meta.lang) ? `lang="${escapeAttrValue(md.meta.lang)}"` : null, + dir: (md && md.meta && md.meta.dir) ? `dir="${escapeAttrValue(md.meta.dir)}"` : null } const html = template(context) // console.log(html); @@ -875,13 +874,16 @@ let tocExpand = false function checkExpandToggle () { const toc = $('.ui-toc-dropdown .toc') - const toggle = $('.expand-toggle') + const expand = $('.expand-toggle.expand-all') + const collapse = $('.expand-toggle.collapse-all') if (!tocExpand) { toc.removeClass('expand') - toggle.text('Expand all') + expand.show() + collapse.hide() } else { toc.addClass('expand') - toggle.text('Collapse all') + expand.hide() + collapse.show() } } @@ -904,11 +906,12 @@ export function generateToc (id) { }) /* eslint-enable no-unused-vars */ if (target.text() === 'undefined') { target.html('') } - const tocMenu = $('
Expand all') - const backtotop = $('Back to top') - const gotobottom = $('Go to bottom') checkExpandToggle() + const tocMenu = $('body').children('.toc-menu') + target.append(tocMenu.clone().show()) + const toggle = $('.expand-toggle', target) + const backtotop = $('.back-to-top', target) + const gotobottom = $('.go-to-bottom', target) toggle.click(e => { e.preventDefault() e.stopPropagation() @@ -927,8 +930,6 @@ export function generateToc (id) { if (window.scrollToBottom) { window.scrollToBottom() } removeHash() }) - tocMenu.append(toggle).append(backtotop).append(gotobottom) - target.append(tocMenu) } // smooth all hash trigger scrolling diff --git a/public/js/index.js b/public/js/index.js index 36c483df..c1ba91f5 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -239,21 +239,9 @@ const supportExtraTags = [ } ] const statusType = { - connected: { - msg: 'CONNECTED', - label: 'label-warning', - fa: 'fa-wifi' - }, - online: { - msg: 'ONLINE', - label: 'label-primary', - fa: 'fa-users' - }, - offline: { - msg: 'OFFLINE', - label: 'label-danger', - fa: 'fa-plug' - } + connected: 1, + online: 2, + offline: 3 } // global vars @@ -725,43 +713,23 @@ function checkTocStyle () { function showStatus (type, num) { currentStatus = type - var shortStatus = ui.toolbar.shortStatus - var status = ui.toolbar.status - var label = $('') - var fa = $('') - var msg = '' - var shortMsg = '' - shortStatus.html('') - status.html('') + ui.toolbar.statusConnected.hide() + ui.toolbar.statusOnline.hide() + ui.toolbar.statusOffline.hide() switch (currentStatus) { case statusType.connected: - label.addClass(statusType.connected.label) - fa.addClass(statusType.connected.fa) - msg = statusType.connected.msg + ui.toolbar.statusConnected.show() break case statusType.online: - label.addClass(statusType.online.label) - fa.addClass(statusType.online.fa) - shortMsg = num - msg = num + ' ' + statusType.online.msg + ui.toolbar.statusShortMsg.text(num) + ui.toolbar.statusOnline.show() break case statusType.offline: - label.addClass(statusType.offline.label) - fa.addClass(statusType.offline.fa) - msg = statusType.offline.msg + ui.toolbar.statusOffline.show() break } - - label.append(fa) - var shortLabel = label.clone() - - shortLabel.append(' ' + shortMsg) - shortStatus.append(shortLabel) - - label.append(' ' + msg) - status.append(label) } function toggleMode () { @@ -1707,41 +1675,34 @@ function updatePermission (newPermission) { permission = newPermission if (window.loaded) refreshView() } - var label = null - var title = null + ui.infobar.permission.label.hide() switch (permission) { case 'freely': - label = ' Freely' - title = 'Anyone can edit' + $('#permissionLabelFreely').show() break case 'editable': - label = ' Editable' - title = 'Signed people can edit' + $('#permissionLabelEditable').show() break case 'limited': - label = ' Limited' - title = 'Signed people can edit (forbid guest)' + $('#permissionLabelLimited').show() break case 'locked': - label = ' Locked' - title = 'Only owner can edit' + $('#permissionLabelLocked').show() break case 'protected': - label = ' Protected' - title = 'Only owner can edit (forbid guest)' + $('#permissionLabelProtected').show() break case 'private': - label = ' Private' - title = 'Only owner can view & edit' + $('#permissionLabelPrivate').show() break } if (personalInfo.userid && window.owner && personalInfo.userid === window.owner) { - label += ' ' + ui.infobar.permission.labelCaretDown.show() ui.infobar.permission.label.removeClass('disabled') } else { + ui.infobar.permission.labelCaretDown.hide() ui.infobar.permission.label.addClass('disabled') } - ui.infobar.permission.label.html(label).attr('title', title) } function havePermission () { @@ -3204,7 +3165,7 @@ function checkInContainerSyntax () { function matchInContainer (text) { var match - match = text.match(/:{3,}/g) + match = text.match(/^:::/gm) if (match && match.length % 2) { return true } else { diff --git a/public/js/lib/editor/ui-elements.js b/public/js/lib/editor/ui-elements.js index f4c65a5a..3b6fa943 100644 --- a/public/js/lib/editor/ui-elements.js +++ b/public/js/lib/editor/ui-elements.js @@ -9,6 +9,10 @@ export const getUIElements = () => ({ toolbar: { shortStatus: $('.ui-short-status'), status: $('.ui-status'), + statusShortMsg: $('.ui-status-short-msg'), + statusConnected: $('.ui-status-connected'), + statusOnline: $('.ui-status-online'), + statusOffline: $('.ui-status-offline'), new: $('.ui-new'), publish: $('.ui-publish'), extra: { @@ -46,6 +50,7 @@ export const getUIElements = () => ({ permission: { permission: $('.ui-permission'), label: $('.ui-permission-label'), + labelCaretDown: $('.ui-permission-caret-down'), freely: $('.ui-permission-freely'), editable: $('.ui-permission-editable'), locked: $('.ui-permission-locked'), diff --git a/public/views/codimd.ejs b/public/views/codimd.ejs index 7818346c..c6c5be0a 100644 --- a/public/views/codimd.ejs +++ b/public/views/codimd.ejs @@ -1,15 +1,15 @@ - + - <%- include codimd/head %> + <%- include('codimd/head') %> - <%- include codimd/header %> - <%- include codimd/body %> - <%- include codimd/footer %> - <%- include codimd/foot %> + <%- include('codimd/header') %> + <%- include('codimd/body') %> + <%- include('codimd/footer') %> + <%- include('codimd/foot') %> diff --git a/public/views/codimd/body.ejs b/public/views/codimd/body.ejs index 07184f2d..965cbdc8 100644 --- a/public/views/codimd/body.ejs +++ b/public/views/codimd/body.ejs @@ -12,23 +12,27 @@