You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
7.1 KiB

  1. <template lang='pug'>
  2. v-card.editor-modal-conflict.animated.fadeIn(flat, tile)
  3. .pa-4
  4. v-toolbar.radius-7(flat, color='indigo', style='border-bottom-left-radius: 0; border-bottom-right-radius: 0;', dark)
  5. v-icon.mr-3 mdi-merge
  6. .subtitle-1 {{$t('editor:conflict.title')}}
  7. v-spacer
  8. v-btn(outlined, color='white', @click='useLocal', :title='$t(`editor:conflict.useLocalHint`)')
  9. v-icon(left) mdi-alpha-l-box
  10. span {{$t('editor:conflict.useLocal')}}
  11. v-dialog(
  12. v-model='isRemoteConfirmDiagShown'
  13. width='500'
  14. )
  15. template(v-slot:activator='{ on }')
  16. v-btn.ml-3(outlined, color='white', v-on='on', :title='$t(`editor:conflict.useRemoteHint`)')
  17. v-icon(left) mdi-alpha-r-box
  18. span {{$t('editor:conflict.useRemote')}}
  19. v-card
  20. .dialog-header.is-short.is-indigo
  21. v-icon.mr-3(color='white') mdi-alpha-r-box
  22. span {{$t('editor:conflict.overwrite.title')}}
  23. v-card-text.pa-4
  24. i18next.body-2(tag='div', path='editor:conflict.overwrite.description')
  25. strong(place='refEditsLost') {{$t('editor:conflict.overwrite.editsLost')}}
  26. v-card-chin
  27. v-spacer
  28. v-btn(outlined, color='indigo', @click='isRemoteConfirmDiagShown = false')
  29. v-icon(left) mdi-close
  30. span {{$t('common:actions.cancel')}}
  31. v-btn(@click='useRemote', color='indigo', dark)
  32. v-icon(left) mdi-check
  33. span {{$t('common:actions.confirm')}}
  34. v-divider.mx-3(vertical)
  35. v-btn(outlined, color='indigo lighten-4', @click='close')
  36. v-icon(left) mdi-close
  37. span {{$t('common:actions.cancel')}}
  38. v-row.indigo.darken-1.body-2(no-gutters)
  39. v-col.pa-4
  40. v-icon.mr-3(color='white') mdi-alpha-l-box
  41. i18next.white--text(tag='span', path='editor:conflict.localVersion')
  42. em.indigo--text.text--lighten-4(place='refEditable') {{$t('editor:conflict.editable')}}
  43. v-divider(vertical)
  44. v-col.pa-4
  45. v-icon.mr-3(color='white') mdi-alpha-r-box
  46. i18next.white--text(tag='span', path='editor:conflict.remoteVersion')
  47. em.indigo--text.text--lighten-4(place='refReadOnly') {{$t('editor:conflict.readonly')}}
  48. v-row.grey.lighten-2.body-2(no-gutters)
  49. v-col.px-4.py-2
  50. i18next.grey--text.text--darken-2(tag='em', path='editor:conflict.leftPanelInfo')
  51. span(place='date', :title='$options.filters.moment(checkoutDateActive, `LLL`)') {{ checkoutDateActive | moment('from') }}
  52. v-divider(vertical)
  53. v-col.px-4.py-2
  54. i18next.grey--text.text--darken-2(tag='em', path='editor:conflict.rightPanelInfo')
  55. strong(place='authorName') {{latest.authorName}}
  56. span(place='date', :title='$options.filters.moment(latest.updatedAt, `LLL`)') {{ latest.updatedAt | moment('from') }}
  57. v-row.grey.lighten-3.grey--text.text--darken-3(no-gutters)
  58. v-col.pa-4
  59. .body-2
  60. strong.indigo--text {{$t('editor:conflict.pageTitle')}}
  61. strong.pl-2 {{title}}
  62. .caption
  63. strong.indigo--text {{$t('editor:conflict.pageDescription')}}
  64. span.pl-2 {{description}}
  65. v-divider(vertical, light)
  66. v-col.pa-4
  67. .body-2
  68. strong.indigo--text {{$t('editor:conflict.pageTitle')}}
  69. strong.pl-2 {{latest.title}}
  70. .caption
  71. strong.indigo--text {{$t('editor:conflict.pageDescription')}}
  72. span.pl-2 {{latest.description}}
  73. v-card.radius-7(:light='!$vuetify.theme.dark', :dark='$vuetify.theme.dark')
  74. div(ref='cm')
  75. </template>
  76. <script>
  77. import _ from 'lodash'
  78. import gql from 'graphql-tag'
  79. import { sync, get } from 'vuex-pathify'
  80. /* global siteConfig */
  81. // ========================================
  82. // IMPORTS
  83. // ========================================
  84. import '../../libs/codemirror-merge/diff-match-patch.js'
  85. // Code Mirror
  86. import CodeMirror from 'codemirror'
  87. import 'codemirror/lib/codemirror.css'
  88. // Language
  89. import 'codemirror/mode/markdown/markdown.js'
  90. import 'codemirror/mode/htmlmixed/htmlmixed.js'
  91. // Addons
  92. import 'codemirror/addon/selection/active-line.js'
  93. import 'codemirror/addon/merge/merge.js'
  94. import 'codemirror/addon/merge/merge.css'
  95. export default {
  96. data() {
  97. return {
  98. cm: null,
  99. latest: {
  100. title: '',
  101. description: '',
  102. updatedAt: '',
  103. authorName: ''
  104. },
  105. isRemoteConfirmDiagShown: false
  106. }
  107. },
  108. computed: {
  109. editorKey: get('editor/editorKey'),
  110. activeModal: sync('editor/activeModal'),
  111. pageId: get('page/id'),
  112. title: get('page/title'),
  113. description: get('page/description'),
  114. updatedAt: get('page/updatedAt'),
  115. checkoutDateActive: sync('editor/checkoutDateActive')
  116. },
  117. methods: {
  118. close () {
  119. this.isRemoteConfirmDiagShown = false
  120. this.activeModal = ''
  121. },
  122. overwriteAndClose() {
  123. this.checkoutDateActive = this.latest.updatedAt
  124. this.$root.$emit('overwriteEditorContent')
  125. this.$root.$emit('resetEditorConflict')
  126. this.close()
  127. },
  128. useLocal () {
  129. this.$store.set('editor/content', this.cm.edit.getValue())
  130. this.overwriteAndClose()
  131. },
  132. useRemote () {
  133. this.$store.set('editor/content', this.latest.content)
  134. this.overwriteAndClose()
  135. }
  136. },
  137. async mounted () {
  138. let textMode = 'text/html'
  139. switch (this.editorKey) {
  140. case 'markdown':
  141. textMode = 'text/markdown'
  142. break
  143. }
  144. let resp = await this.$apollo.query({
  145. query: gql`
  146. query ($id: Int!) {
  147. pages {
  148. conflictLatest(id: $id) {
  149. id
  150. authorId
  151. authorName
  152. content
  153. createdAt
  154. description
  155. isPublished
  156. locale
  157. path
  158. tags
  159. title
  160. updatedAt
  161. }
  162. }
  163. }
  164. `,
  165. fetchPolicy: 'network-only',
  166. variables: {
  167. id: this.$store.get('page/id')
  168. }
  169. })
  170. resp = _.get(resp, 'data.pages.conflictLatest', false)
  171. if (!resp) {
  172. return this.$store.commit('showNotification', {
  173. message: 'Failed to fetch latest version.',
  174. style: 'warning',
  175. icon: 'warning'
  176. })
  177. }
  178. this.latest = resp
  179. this.cm = CodeMirror.MergeView(this.$refs.cm, {
  180. value: this.$store.get('editor/content'),
  181. orig: resp.content,
  182. tabSize: 2,
  183. mode: textMode,
  184. lineNumbers: true,
  185. lineWrapping: true,
  186. connect: null,
  187. highlightDifferences: true,
  188. styleActiveLine: true,
  189. collapseIdentical: true,
  190. direction: siteConfig.rtl ? 'rtl' : 'ltr'
  191. })
  192. this.cm.rightOriginal().setSize(null, 'calc(100vh - 265px)')
  193. this.cm.editor().setSize(null, 'calc(100vh - 265px)')
  194. this.cm.wrap.style.height = 'calc(100vh - 265px)'
  195. }
  196. }
  197. </script>
  198. <style lang='scss'>
  199. .editor-modal-conflict {
  200. position: fixed !important;
  201. top: 0;
  202. left: 0;
  203. z-index: 10;
  204. width: 100%;
  205. height: 100vh;
  206. background-color: rgba(0, 0, 0, .9) !important;
  207. overflow: auto;
  208. }
  209. </style>