|
|
@@ -3,187 +3,84 @@
|
|
|
<template v-for="page in pages">
|
|
|
<editing-page-vue :key="page.id" :page="page"></editing-page-vue>
|
|
|
</template>
|
|
|
+ <div>{{ focus }}</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import { mapState } from 'vuex'
|
|
|
import EditingPageVue from './EditingPage.vue'
|
|
|
+import { USE_FOCUS } from '../../store/types/editor-types'
|
|
|
export default {
|
|
|
name: 'editor',
|
|
|
components: {
|
|
|
EditingPageVue
|
|
|
},
|
|
|
- created() {},
|
|
|
- mounted() {},
|
|
|
computed: {
|
|
|
...mapState({
|
|
|
pages: state => state.editor.pages
|
|
|
- })
|
|
|
- }
|
|
|
-}
|
|
|
-</script>
|
|
|
-<style lang="scss" scoped>
|
|
|
-@import './reset.scss';
|
|
|
-.slide {
|
|
|
- box-sizing: border-box;
|
|
|
- text-align: justify;
|
|
|
- margin: 0 auto;
|
|
|
- outline: none;
|
|
|
-
|
|
|
- line-height: 1.6;
|
|
|
- word-break: break-word;
|
|
|
- word-wrap: break-word;
|
|
|
-
|
|
|
- font-size: 22px;
|
|
|
-
|
|
|
- h1,
|
|
|
- h2,
|
|
|
- h3,
|
|
|
- h4,
|
|
|
- h5,
|
|
|
- h6 {
|
|
|
- font-weight: 600;
|
|
|
- text-align: left;
|
|
|
- }
|
|
|
-
|
|
|
- h1 {
|
|
|
- font-size: 1.88em;
|
|
|
- margin: 1.25em 0 0.5em 0;
|
|
|
- }
|
|
|
-
|
|
|
- h2 {
|
|
|
- font-size: 1.56em;
|
|
|
- margin: 2.5em 0 0.3em 0;
|
|
|
- }
|
|
|
-
|
|
|
- h3 {
|
|
|
- font-size: 1.38em;
|
|
|
- margin: 2.19em 0 0.15em 0;
|
|
|
- }
|
|
|
-
|
|
|
- h4 {
|
|
|
- font-size: 1.25em;
|
|
|
- margin: 1.56em 0 0.1em 0;
|
|
|
- }
|
|
|
-
|
|
|
- h5 {
|
|
|
- font-size: 1em;
|
|
|
- margin: 1.25em 0 0.1em 0;
|
|
|
- }
|
|
|
-
|
|
|
- h6 {
|
|
|
- font-size: 1em;
|
|
|
- margin: 1.25em 0 0.1em 0;
|
|
|
- }
|
|
|
-
|
|
|
- p {
|
|
|
- margin: 0.44em 0;
|
|
|
- }
|
|
|
-
|
|
|
- li {
|
|
|
- margin: 0.19em;
|
|
|
- }
|
|
|
-
|
|
|
- ul,
|
|
|
- ol {
|
|
|
- list-style: none;
|
|
|
- padding-left: 1em;
|
|
|
- margin-top: 0.3em;
|
|
|
- margin-bottom: 0.8em;
|
|
|
- }
|
|
|
-
|
|
|
- ul > li::before {
|
|
|
- content: '\02022';
|
|
|
- display: inline-block;
|
|
|
- color: #1976d2;
|
|
|
- width: 1em;
|
|
|
- margin-left: -1em;
|
|
|
- }
|
|
|
-
|
|
|
- ol {
|
|
|
- counter-reset: li;
|
|
|
- margin: 0 0 0 0.5em;
|
|
|
-
|
|
|
- li {
|
|
|
- text-align: left;
|
|
|
+ }),
|
|
|
+ focus() {
|
|
|
+ const res = this.$store.state.editor.focus
|
|
|
+ res !== null &&
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.checkFocus()
|
|
|
+ })
|
|
|
+ return this.$store.state.editor.focus
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- ol > li::before {
|
|
|
- font-family: 'Courier', 'Courier New', monospace !important;
|
|
|
- overflow: hidden;
|
|
|
- font-size: 1em;
|
|
|
- line-height: 0;
|
|
|
- content: counter(li) '.';
|
|
|
- color: #1976d2;
|
|
|
- display: inline;
|
|
|
- margin-left: -1.6em;
|
|
|
- margin-right: 0.4em;
|
|
|
- text-align: right;
|
|
|
- counter-increment: li;
|
|
|
- }
|
|
|
-
|
|
|
- blockquote {
|
|
|
- margin: 0.63em 0;
|
|
|
- padding: 0.31em 0.94em;
|
|
|
- border-left: #fbc02d 0.25em solid;
|
|
|
- background: #fffad3;
|
|
|
- position: relative;
|
|
|
-
|
|
|
- &::before {
|
|
|
- content: '!';
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
- font-size: 0.75em;
|
|
|
- font-family: monospace;
|
|
|
- color: white;
|
|
|
- position: absolute;
|
|
|
- left: -0.69em;
|
|
|
- top: 1em;
|
|
|
- width: 0.88em;
|
|
|
- height: 0.88em;
|
|
|
- background: #fbc02d;
|
|
|
- border: 0.13em #fbc02d solid;
|
|
|
- border-radius: 50%;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- a {
|
|
|
- text-decoration: underline solid transparent;
|
|
|
- transition: 0.2s all ease-out;
|
|
|
-
|
|
|
- &:hover {
|
|
|
- text-decoration: underline solid #ccc;
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ checkFocus() {
|
|
|
+ if (this.focus !== null) {
|
|
|
+ if (this.focus.focusItemId) {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ const item = document.getElementById(this.focus.focusItemId)
|
|
|
+ item.focus()
|
|
|
+ const offset = this.focus.focusItemOffset
|
|
|
+ const computeResult = this.computeContainerAndOffset(item, offset)
|
|
|
+
|
|
|
+ const range = document.getSelection().getRangeAt(0)
|
|
|
+ range.setStart(computeResult.container, computeResult.offset)
|
|
|
+ range.collapse()
|
|
|
+
|
|
|
+ this.$store.commit(USE_FOCUS)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computeContainerAndOffset(item, offset) {
|
|
|
+ // todo test
|
|
|
+ if (offset === 0) {
|
|
|
+ return { container: item, offset: 0 }
|
|
|
+ }
|
|
|
+
|
|
|
+ let restOffset = offset
|
|
|
+ if (item.hasChildNodes()) {
|
|
|
+ for (const node of item.childNodes) {
|
|
|
+ if (node.length > restOffset) {
|
|
|
+ return {
|
|
|
+ container: node,
|
|
|
+ offset: restOffset
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ restOffset -= node.length
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return { container: item, offset: 0 }
|
|
|
+ }
|
|
|
+
|
|
|
+ // default return value is the end of this element
|
|
|
+ // notice that when the element is not Text, offset 1 means the end of element
|
|
|
+ return {
|
|
|
+ container: item,
|
|
|
+ offset: 1
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- li > a,
|
|
|
- p > a {
|
|
|
- color: #1976d2;
|
|
|
- }
|
|
|
-
|
|
|
- img {
|
|
|
- max-width: 100%;
|
|
|
- max-height: 100vh;
|
|
|
- margin: 0.94em auto 1.88em auto;
|
|
|
- display: block;
|
|
|
- box-shadow: 0 0.13em 0.63em 0 #e5e5e5;
|
|
|
- }
|
|
|
-
|
|
|
- pre {
|
|
|
- padding: 0.63em 0.94em;
|
|
|
- border: gray 0.06em solid;
|
|
|
- }
|
|
|
-
|
|
|
- code {
|
|
|
- overflow: auto;
|
|
|
- word-break: normal;
|
|
|
- padding: 0 0.19em;
|
|
|
- font-family: 'Menlo', 'Courier New', monospace;
|
|
|
- color: #1899ba;
|
|
|
- font-size: 0.88em;
|
|
|
- }
|
|
|
}
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+@import '@/common/reset.scss';
|
|
|
+@import '@/common/show-mode.scss';
|
|
|
</style>
|