feat: anchor - copy link to clipboard

This commit is contained in:
NGPixel 2017-05-22 13:32:52 -04:00
parent 45d94e7e94
commit 13bdb2edb7
10 changed files with 117 additions and 14 deletions

View File

@ -6,6 +6,7 @@
import $ from 'jquery' import $ from 'jquery'
import Vue from 'vue' import Vue from 'vue'
import VueResource from 'vue-resource' import VueResource from 'vue-resource'
import VueClipboards from 'vue-clipboards'
import store from './store' import store from './store'
import io from 'socket.io-client' import io from 'socket.io-client'
import i18next from 'i18next' import i18next from 'i18next'
@ -36,6 +37,7 @@ import sourceComponent from './pages/source.component.js'
// ==================================== // ====================================
Vue.use(VueResource) Vue.use(VueResource)
Vue.use(VueClipboards)
Vue.use(VueI18Next) Vue.use(VueI18Next)
i18next i18next
@ -91,7 +93,7 @@ $(() => {
i18n, i18n,
el: '#root', el: '#root',
mounted() { mounted() {
$('a').smoothScroll({ speed: 500, offset: -50 }) $('a:not(.toc-anchor)').smoothScroll({ speed: 500, offset: -50 })
$('#header').sticky({ topSpacing: 0 }) $('#header').sticky({ topSpacing: 0 })
$('.sidebar-pagecontents').sticky({ topSpacing: 15, bottomSpacing: 75 }) $('.sidebar-pagecontents').sticky({ topSpacing: 15, bottomSpacing: 75 })
} }

View File

@ -1,16 +1,53 @@
<template> <template lang="pug">
<div> .modal(v-bind:class='{ "is-active": isShown }')
<p>{{ msg }}</p> .modal-background
<input type="text" v-model="msg" /> .modal-container
</div> .modal-content
header.is-blue
span Copy link to this section
section
p.control.is-fullwidth
input.input(type='text', ref='anchorURLinput', v-model='anchorURL')
footer
a.button.is-grey.is-outlined(v-on:click='cancel') Discard
a.button.is-blue(v-clipboard='anchorURL', @success="clipboardSuccess", @error="clipboardError") Copy to Clipboard
</template> </template>
<script> <script>
import * as _ from 'lodash'
export default { export default {
name: 'anchor', name: 'anchor',
data () { data () {
return { return {}
msg: 'Welcome to Your Vue.js App' },
computed: {
anchorURL () {
return window.location.href.split('#')[0] + '#' + this.$store.state.anchor.hash
},
isShown () {
return this.$store.state.anchor.shown
}
},
methods: {
cancel () {
this.$store.dispatch('anchorClose')
},
clipboardSuccess () {
this.$store.dispatch('alert', {
style: 'blue',
icon: 'clipboard',
msg: 'The URL has been copied to your clipboard.'
})
this.$store.dispatch('anchorClose')
},
clipboardError () {
this.$store.dispatch('alert', {
style: 'red',
icon: 'clipboard',
msg: 'Clipboard copy failed. Copy the URL manually.'
})
this.$refs.anchorURLinput.select()
} }
} }
} }

View File

@ -2,6 +2,7 @@ import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import alert from './modules/alert' import alert from './modules/alert'
import anchor from './modules/anchor'
import adminUsersCreate from './modules/admin-users-create' import adminUsersCreate from './modules/admin-users-create'
Vue.use(Vuex) Vue.use(Vuex)
@ -20,6 +21,7 @@ export default new Vuex.Store({
getters: {}, getters: {},
modules: { modules: {
alert, alert,
anchor,
adminUsersCreate adminUsersCreate
} }
}) })

View File

@ -0,0 +1,23 @@
'use strict'
export default {
state: {
shown: false,
hash: ''
},
getters: {},
mutations: {
anchorChange: (state, opts) => {
state.shown = (opts.shown === true)
state.hash = opts.hash || ''
}
},
actions: {
anchorOpen({ commit, dispatch }, hash) {
commit('anchorChange', { shown: true, hash })
},
anchorClose({ commit, dispatch }) {
commit('anchorChange', { shown: false })
}
}
}

View File

@ -157,6 +157,7 @@
"uglify-js": "latest", "uglify-js": "latest",
"vee-validate": "^2.0.0-rc.3", "vee-validate": "^2.0.0-rc.3",
"vue": "^2.3.3", "vue": "^2.3.3",
"vue-clipboards": "^1.0.0",
"vue-resource": "^1.3.1", "vue-resource": "^1.3.1",
"vue-template-compiler": "^2.3.3", "vue-template-compiler": "^2.3.3",
"vue-template-es2015-compiler": "^1.5.2", "vue-template-es2015-compiler": "^1.5.2",

View File

@ -20,7 +20,7 @@ var mkdown = md({
html: true, html: true,
linkify: true, linkify: true,
typography: true, typography: true,
highlight (str, lang) { highlight(str, lang) {
if (lang && hljs.getLanguage(lang)) { if (lang && hljs.getLanguage(lang)) {
try { try {
return '<pre class="hljs"><code>' + hljs.highlight(lang, str, true).value + '</code></pre>' return '<pre class="hljs"><code>' + hljs.highlight(lang, str, true).value + '</code></pre>'
@ -206,6 +206,13 @@ const parseContent = (content) => {
cr(elm).replaceWith(txtLink) cr(elm).replaceWith(txtLink)
}) })
// -> Add anchor handler
cr('a.toc-anchor').each((i, elm) => {
let hashText = cr(elm).attr('href').slice(1)
cr(elm).attr('v-on:click.stop.prevent', "$store.dispatch('anchorOpen', '" + hashText + "')")
})
// -> Re-attach blockquote styling classes to their parents // -> Re-attach blockquote styling classes to their parents
cr.root().children('blockquote').each((i, elm) => { cr.root().children('blockquote').each((i, elm) => {
@ -313,7 +320,7 @@ module.exports = {
* @param {String} content Markdown-formatted content * @param {String} content Markdown-formatted content
* @return {Object} Object containing meta, html and tree data * @return {Object} Object containing meta, html and tree data
*/ */
parse (content) { parse(content) {
return { return {
meta: parseMeta(content), meta: parseMeta(content),
html: parseContent(content), html: parseContent(content),

View File

@ -1,7 +1,7 @@
extends ./_layout.pug extends ./_layout.pug
block rootNavRight block rootNavRight
i.nav-item#notifload loading-spinner
.nav-item .nav-item
a.button(v-on:click='$store.dispatch("adminUsersCreateOpen")') a.button(v-on:click='$store.dispatch("adminUsersCreateOpen")')
i.icon-plus i.icon-plus

View File

@ -9,7 +9,7 @@ mixin tocMenu(ti)
+tocMenu(node.nodes) +tocMenu(node.nodes)
block rootNavRight block rootNavRight
i.nav-item#notifload loading-spinner
.nav-item .nav-item
if rights.write if rights.write
a.button.is-outlined.btn-move-prompt.is-hidden a.button.is-outlined.btn-move-prompt.is-hidden
@ -83,3 +83,4 @@ block content
include ../modals/create.pug include ../modals/create.pug
include ../modals/move.pug include ../modals/move.pug
anchor

View File

@ -2,8 +2,6 @@ extends ../layout.pug
block rootNavCenter block rootNavCenter
block rootNavRight
i.nav-item#notifload
block content block content

View File

@ -1223,6 +1223,14 @@ cli-width@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a"
clipboard@^1.5.15:
version "1.6.1"
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-1.6.1.tgz#65c5b654812466b0faab82dc6ba0f1d2f8e4be53"
dependencies:
good-listener "^1.2.0"
select "^1.1.2"
tiny-emitter "^1.0.0"
clite@^0.3.0: clite@^0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/clite/-/clite-0.3.0.tgz#e7fcbc8cc5bd3e7f8b84ed48db12e9474cc73441" resolved "https://registry.yarnpkg.com/clite/-/clite-0.3.0.tgz#e7fcbc8cc5bd3e7f8b84ed48db12e9474cc73441"
@ -1659,6 +1667,10 @@ delayed-stream@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
delegate@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.1.2.tgz#1e1bc6f5cadda6cb6cbf7e6d05d0bcdd5712aebe"
delegates@^1.0.0: delegates@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@ -2749,6 +2761,12 @@ globule@^1.0.0:
lodash "~4.16.4" lodash "~4.16.4"
minimatch "~3.0.2" minimatch "~3.0.2"
good-listener@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
dependencies:
delegate "^3.1.2"
got@^3.2.0: got@^3.2.0:
version "3.3.1" version "3.3.1"
resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca" resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca"
@ -5978,6 +5996,10 @@ scss-tokenizer@^0.2.3:
lodash.union "^4.6.0" lodash.union "^4.6.0"
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
select@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
semver-diff@^2.0.0: semver-diff@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
@ -6641,6 +6663,10 @@ timed-out@^4.0.0:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
tiny-emitter@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.2.0.tgz#6dc845052cb08ebefc1874723b58f24a648c3b6f"
tinycolor2@^1.1.2: tinycolor2@^1.1.2:
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
@ -6992,6 +7018,12 @@ void-elements@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
vue-clipboards@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/vue-clipboards/-/vue-clipboards-1.0.0.tgz#60e356dcfd627af9de499ea5c102ac021f8d9adc"
dependencies:
clipboard "^1.5.15"
vue-resource@^1.3.1: vue-resource@^1.3.1:
version "1.3.1" version "1.3.1"
resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-1.3.1.tgz#bf2f7b70bfe21b397c9d7607878f776a3acea2cf" resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-1.3.1.tgz#bf2f7b70bfe21b397c9d7607878f776a3acea2cf"