mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge branch 'extract-styleguide' into add-styleguide-dev-mode
This commit is contained in:
commit
25c759c48c
1
.gitignore
vendored
1
.gitignore
vendored
@ -80,3 +80,4 @@ static/uploads
|
||||
|
||||
cypress/videos
|
||||
cypress/screenshots/
|
||||
cypress.env.json
|
||||
|
||||
@ -18,22 +18,23 @@ before_install:
|
||||
- curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
|
||||
- chmod +x docker-compose
|
||||
- sudo mv docker-compose /usr/local/bin
|
||||
- cp cypress.env.template.json cypress.env.json
|
||||
|
||||
install:
|
||||
- docker build --build-arg BUILD_COMMIT=$TRAVIS_COMMIT --target production -t humanconnection/nitro-web .
|
||||
- docker-compose -f docker-compose.yml -f docker-compose.travis.yml up -d
|
||||
- git clone https://github.com/Human-Connection/Nitro-Backend.git ../Nitro-Backend
|
||||
- git -C "../Nitro-Backend" checkout $BACKEND_BRANCH || git -C "../Nitro-Backend" checkout master
|
||||
- docker-compose -f ../Nitro-Backend/docker-compose.yml -f ../Nitro-Backend/docker-compose.travis.yml up -d
|
||||
- cd ../Nitro-Backend && yarn install && cd -
|
||||
- docker-compose -f ../Nitro-Backend/docker-compose.yml -f ../Nitro-Backend/docker-compose.cypress.yml up -d
|
||||
- yarn global add cypress wait-on
|
||||
- yarn add cypress-cucumber-preprocessor
|
||||
|
||||
script:
|
||||
- docker-compose exec -e NODE_ENV=test webapp yarn run lint
|
||||
- docker-compose exec -e NODE_ENV=test webapp yarn run test
|
||||
- docker-compose -f ../Nitro-Backend/docker-compose.yml exec backend yarn run db:seed
|
||||
- wait-on http://localhost:3000
|
||||
- cypress run --record --key $CYPRESS_TOKEN
|
||||
- wait-on http://localhost:7474 && docker-compose -f ../Nitro-Backend/docker-compose.yml exec neo4j migrate
|
||||
- wait-on http://localhost:3000 && cypress run --record --key $CYPRESS_TOKEN
|
||||
|
||||
after_success:
|
||||
- wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh
|
||||
|
||||
@ -23,8 +23,9 @@ $ yarn install
|
||||
Copy:
|
||||
```
|
||||
cp .env.template .env
|
||||
cp cypress.env.template.json cypress.env.json
|
||||
```
|
||||
Configure the file `.env` according to your needs and your local setup.
|
||||
Configure the files according to your needs and your local setup.
|
||||
|
||||
### Development
|
||||
``` bash
|
||||
|
||||
@ -78,45 +78,6 @@ blockquote {
|
||||
}
|
||||
}
|
||||
|
||||
.hc-editor-content {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
&:not(:first-child) {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
p {
|
||||
&:not(:last-child) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
dl,
|
||||
ol,
|
||||
ul,
|
||||
blockquote,
|
||||
pre,
|
||||
table {
|
||||
&:not(:first-child) {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
*:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
*:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
// avoid double breaks
|
||||
br + p {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
|
||||
@ -8,14 +8,19 @@
|
||||
slot="default"
|
||||
slot-scope="{toggleMenu}"
|
||||
>
|
||||
<ds-button
|
||||
class="content-menu-trigger"
|
||||
size="small"
|
||||
ghost
|
||||
@click.prevent="toggleMenu"
|
||||
<slot
|
||||
name="button"
|
||||
:toggleMenu="toggleMenu"
|
||||
>
|
||||
<ds-icon name="ellipsis-v" />
|
||||
</ds-button>
|
||||
<ds-button
|
||||
class="content-menu-trigger"
|
||||
size="small"
|
||||
ghost
|
||||
@click.prevent="toggleMenu"
|
||||
>
|
||||
<ds-icon name="ellipsis-v" />
|
||||
</ds-button>
|
||||
</slot>
|
||||
</template>
|
||||
<div
|
||||
slot="popover"
|
||||
@ -49,6 +54,7 @@ export default {
|
||||
placement: { type: String, default: 'top-end' },
|
||||
itemId: { type: String, required: true },
|
||||
name: { type: String, required: true },
|
||||
isOwner: { type: Boolean, default: false },
|
||||
context: {
|
||||
type: String,
|
||||
required: true,
|
||||
@ -59,20 +65,54 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
routes() {
|
||||
let routes = [
|
||||
{
|
||||
let routes = []
|
||||
|
||||
if (this.isOwner && this.context === 'contribution') {
|
||||
routes.push({
|
||||
name: this.$t(`contribution.edit`),
|
||||
path: this.$router.resolve({
|
||||
name: 'post-edit-id',
|
||||
params: {
|
||||
id: this.itemId
|
||||
}
|
||||
}).href,
|
||||
icon: 'edit'
|
||||
})
|
||||
}
|
||||
if (this.isOwner && this.context === 'comment') {
|
||||
routes.push({
|
||||
name: this.$t(`comment.edit`),
|
||||
callback: () => {
|
||||
console.log('EDIT COMMENT')
|
||||
},
|
||||
icon: 'edit'
|
||||
})
|
||||
}
|
||||
|
||||
if (!this.isOwner) {
|
||||
routes.push({
|
||||
name: this.$t(`report.${this.context}.title`),
|
||||
callback: this.openReportDialog,
|
||||
icon: 'flag'
|
||||
}
|
||||
]
|
||||
if (this.isModerator) {
|
||||
})
|
||||
}
|
||||
|
||||
if (!this.isOwner && this.isModerator) {
|
||||
routes.push({
|
||||
name: this.$t(`disable.${this.context}.title`),
|
||||
callback: this.openDisableDialog,
|
||||
callback: () => {},
|
||||
icon: 'eye-slash'
|
||||
})
|
||||
}
|
||||
|
||||
if (this.isOwner && this.context === 'user') {
|
||||
routes.push({
|
||||
name: this.$t(`settings.data.name`),
|
||||
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
|
||||
callback: () => this.$router.push('/settings'),
|
||||
icon: 'edit'
|
||||
})
|
||||
}
|
||||
return routes
|
||||
},
|
||||
isModerator() {
|
||||
|
||||
145
components/ContributionForm.vue
Normal file
145
components/ContributionForm.vue
Normal file
@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<ds-form
|
||||
ref="contributionForm"
|
||||
v-model="form"
|
||||
:schema="formSchema"
|
||||
@submit="submit"
|
||||
>
|
||||
<template slot-scope="{ errors }">
|
||||
<ds-card>
|
||||
<ds-input
|
||||
model="title"
|
||||
class="post-title"
|
||||
placeholder="Title"
|
||||
name="title"
|
||||
autofocus
|
||||
/>
|
||||
<no-ssr>
|
||||
<hc-editor
|
||||
:value="form.content"
|
||||
@input="updateEditorContent"
|
||||
/>
|
||||
</no-ssr>
|
||||
<div
|
||||
slot="footer"
|
||||
style="text-align: right"
|
||||
>
|
||||
<ds-button
|
||||
:disabled="loading || disabled"
|
||||
ghost
|
||||
@click.prevent="$router.back()"
|
||||
>
|
||||
{{ $t('actions.cancel') }}
|
||||
</ds-button>
|
||||
<ds-button
|
||||
icon="check"
|
||||
type="submit"
|
||||
:loading="loading"
|
||||
:disabled="disabled || errors"
|
||||
primary
|
||||
>
|
||||
{{ $t('actions.save') }}
|
||||
</ds-button>
|
||||
</div>
|
||||
</ds-card>
|
||||
</template>
|
||||
</ds-form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import HcEditor from '~/components/Editor/Editor.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcEditor
|
||||
},
|
||||
props: {
|
||||
contribution: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
title: '',
|
||||
content: ''
|
||||
},
|
||||
formSchema: {
|
||||
title: { required: true, min: 3, max: 64 },
|
||||
content: { required: true, min: 3 }
|
||||
},
|
||||
id: null,
|
||||
loading: false,
|
||||
disabled: false,
|
||||
slug: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
contribution: {
|
||||
immediate: true,
|
||||
handler: function(contribution) {
|
||||
if (!contribution || !contribution.id) {
|
||||
return
|
||||
}
|
||||
this.id = contribution.id
|
||||
this.slug = contribution.slug
|
||||
this.form.content = contribution.content
|
||||
this.form.title = contribution.title
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
const postMutations = require('~/graphql/PostMutations.js').default(this)
|
||||
this.loading = true
|
||||
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: this.id
|
||||
? postMutations.UpdatePost
|
||||
: postMutations.CreatePost,
|
||||
variables: {
|
||||
id: this.id,
|
||||
title: this.form.title,
|
||||
content: this.form.content
|
||||
}
|
||||
})
|
||||
.then(res => {
|
||||
this.loading = false
|
||||
this.$toast.success('Saved!')
|
||||
this.disabled = true
|
||||
|
||||
const result = res.data[this.id ? 'UpdatePost' : 'CreatePost']
|
||||
|
||||
this.$router.push({
|
||||
name: 'post-slug',
|
||||
params: { slug: result.slug }
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
this.$toast.error(err.message)
|
||||
this.loading = false
|
||||
this.disabled = false
|
||||
})
|
||||
},
|
||||
updateEditorContent(value) {
|
||||
// this.form.content = value
|
||||
this.$refs.contributionForm.update('content', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.post-title {
|
||||
margin-top: $space-x-small;
|
||||
margin-bottom: $space-xx-small;
|
||||
|
||||
input {
|
||||
border: 0;
|
||||
font-size: $font-size-x-large;
|
||||
font-weight: bold;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
366
components/Editor/Editor.vue
Normal file
366
components/Editor/Editor.vue
Normal file
@ -0,0 +1,366 @@
|
||||
<template>
|
||||
<div class="editor">
|
||||
<editor-menu-bubble :editor="editor">
|
||||
<div
|
||||
ref="menu"
|
||||
slot-scope="{ commands, getMarkAttrs, isActive, menu }"
|
||||
class="menububble tooltip"
|
||||
x-placement="top"
|
||||
:class="{ 'is-active': menu.isActive || linkMenuIsActive }"
|
||||
:style="`left: ${menu.left}px; bottom: ${menu.bottom}px;`"
|
||||
>
|
||||
<div class="tooltip-wrapper">
|
||||
<template v-if="linkMenuIsActive">
|
||||
<ds-input
|
||||
ref="linkInput"
|
||||
v-model="linkUrl"
|
||||
class="editor-menu-link-input"
|
||||
placeholder="http://"
|
||||
@blur.native.capture="hideMenu(menu.isActive)"
|
||||
@keydown.native.esc.prevent="hideMenu(menu.isActive)"
|
||||
@keydown.native.enter.prevent="setLinkUrl(commands.link, linkUrl)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<ds-button
|
||||
class="menububble__button"
|
||||
size="small"
|
||||
:hover="isActive.bold()"
|
||||
ghost
|
||||
@click.prevent="() => {}"
|
||||
@mousedown.native.prevent="commands.bold"
|
||||
>
|
||||
<ds-icon name="bold" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menububble__button"
|
||||
size="small"
|
||||
:hover="isActive.italic()"
|
||||
ghost
|
||||
@click.prevent="() => {}"
|
||||
@mousedown.native.prevent="commands.italic"
|
||||
>
|
||||
<ds-icon name="italic" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menububble__button"
|
||||
size="small"
|
||||
:hover="isActive.link()"
|
||||
ghost
|
||||
@click.prevent="() => {}"
|
||||
@mousedown.native.prevent="showLinkMenu(getMarkAttrs('link'))"
|
||||
>
|
||||
<ds-icon name="link" />
|
||||
</ds-button>
|
||||
</template>
|
||||
</div>
|
||||
<div class="tooltip-arrow" />
|
||||
</div>
|
||||
</editor-menu-bubble>
|
||||
<editor-floating-menu :editor="editor">
|
||||
<div
|
||||
slot-scope="{ commands, isActive, menu }"
|
||||
class="editor__floating-menu"
|
||||
:class="{ 'is-active': menu.isActive }"
|
||||
:style="`top: ${menu.top}px`"
|
||||
>
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.paragraph()"
|
||||
@click.prevent="commands.paragraph()"
|
||||
>
|
||||
<ds-icon name="paragraph" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.heading({ level: 3 })"
|
||||
@click.prevent="commands.heading({ level: 3 })"
|
||||
>
|
||||
H3
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.heading({ level: 4 })"
|
||||
@click.prevent="commands.heading({ level: 4 })"
|
||||
>
|
||||
H4
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.bullet_list()"
|
||||
@click.prevent="commands.bullet_list()"
|
||||
>
|
||||
<ds-icon name="list-ul" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.ordered_list()"
|
||||
@click.prevent="commands.ordered_list()"
|
||||
>
|
||||
<ds-icon name="list-ol" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.blockquote()"
|
||||
@click.prevent="commands.blockquote"
|
||||
>
|
||||
<ds-icon name="quote-right" />
|
||||
</ds-button>
|
||||
|
||||
<ds-button
|
||||
class="menubar__button"
|
||||
size="small"
|
||||
:ghost="!isActive.horizontal_rule()"
|
||||
@click.prevent="commands.horizontal_rule"
|
||||
>
|
||||
<ds-icon name="minus" />
|
||||
</ds-button>
|
||||
</div>
|
||||
</editor-floating-menu>
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import linkify from 'linkify-it'
|
||||
import stringHash from 'string-hash'
|
||||
import {
|
||||
Editor,
|
||||
EditorContent,
|
||||
EditorFloatingMenu,
|
||||
EditorMenuBubble
|
||||
} from 'tiptap'
|
||||
import EventHandler from './plugins/eventHandler.js'
|
||||
import {
|
||||
Heading,
|
||||
HardBreak,
|
||||
Blockquote,
|
||||
ListItem,
|
||||
BulletList,
|
||||
OrderedList,
|
||||
HorizontalRule,
|
||||
Placeholder,
|
||||
Bold,
|
||||
Italic,
|
||||
Strike,
|
||||
Underline,
|
||||
Link,
|
||||
History
|
||||
} from 'tiptap-extensions'
|
||||
|
||||
let throttleInputEvent
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EditorContent,
|
||||
EditorFloatingMenu,
|
||||
EditorMenuBubble
|
||||
},
|
||||
props: {
|
||||
value: { type: String, default: '' },
|
||||
doc: { type: Object, default: () => {} }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lastValueHash: null,
|
||||
editor: new Editor({
|
||||
content: this.value || '',
|
||||
doc: this.doc,
|
||||
extensions: [
|
||||
new EventHandler(),
|
||||
new Heading(),
|
||||
new HardBreak(),
|
||||
new Blockquote(),
|
||||
new BulletList(),
|
||||
new OrderedList(),
|
||||
new HorizontalRule(),
|
||||
new Bold(),
|
||||
new Italic(),
|
||||
new Strike(),
|
||||
new Underline(),
|
||||
new Link(),
|
||||
new Heading({ levels: [3, 4] }),
|
||||
new ListItem(),
|
||||
new Placeholder({
|
||||
emptyNodeClass: 'is-empty',
|
||||
emptyNodeText: 'Schreib etwas inspirerendes…'
|
||||
}),
|
||||
new History()
|
||||
],
|
||||
onUpdate: e => {
|
||||
clearTimeout(throttleInputEvent)
|
||||
throttleInputEvent = setTimeout(() => this.onUpdate(e), 300)
|
||||
}
|
||||
}),
|
||||
linkUrl: null,
|
||||
linkMenuIsActive: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
immediate: true,
|
||||
handler: function(content, old) {
|
||||
const contentHash = stringHash(content)
|
||||
if (!content || contentHash === this.lastValueHash) {
|
||||
return
|
||||
}
|
||||
this.lastValueHash = contentHash
|
||||
this.editor.setContent(content)
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
methods: {
|
||||
onUpdate(e) {
|
||||
const content = e.getHTML()
|
||||
const contentHash = stringHash(content)
|
||||
if (contentHash !== this.lastValueHash) {
|
||||
this.lastValueHash = contentHash
|
||||
this.$emit('input', content)
|
||||
}
|
||||
},
|
||||
showLinkMenu(attrs) {
|
||||
this.linkUrl = attrs.href
|
||||
this.linkMenuIsActive = true
|
||||
this.$nextTick(() => {
|
||||
try {
|
||||
const $el = this.$refs.linkInput.$el.getElementsByTagName('input')[0]
|
||||
$el.focus()
|
||||
$el.select()
|
||||
} catch (err) {}
|
||||
})
|
||||
},
|
||||
hideLinkMenu() {
|
||||
this.linkUrl = null
|
||||
this.linkMenuIsActive = false
|
||||
this.editor.focus()
|
||||
},
|
||||
hideMenu(isActive) {
|
||||
isActive = false
|
||||
this.hideLinkMenu()
|
||||
},
|
||||
setLinkUrl(command, url) {
|
||||
const links = linkify().match(url)
|
||||
if (links) {
|
||||
// add valid link
|
||||
command({
|
||||
href: links.pop().url
|
||||
})
|
||||
this.hideLinkMenu()
|
||||
this.editor.focus()
|
||||
} else if (!url) {
|
||||
// remove link
|
||||
command({ href: null })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ProseMirror {
|
||||
padding: $space-base;
|
||||
margin: -$space-base;
|
||||
min-height: $space-large;
|
||||
}
|
||||
|
||||
.ProseMirror:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.editor p.is-empty:first-child::before {
|
||||
content: attr(data-empty-text);
|
||||
float: left;
|
||||
color: $text-color-disabled;
|
||||
padding-left: $space-xx-small;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.menubar__button {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
li > p {
|
||||
margin-top: $space-xx-small;
|
||||
margin-bottom: $space-xx-small;
|
||||
}
|
||||
|
||||
.editor {
|
||||
&__floating-menu {
|
||||
position: absolute;
|
||||
margin-top: -0.25rem;
|
||||
margin-left: $space-xx-small;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s, visibility 0.2s;
|
||||
background-color: #fff;
|
||||
|
||||
&.is-active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
.menububble {
|
||||
position: absolute;
|
||||
// margin-top: -0.5rem;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 200ms, visibility 200ms;
|
||||
// transition-delay: 50ms;
|
||||
transform: translate(-50%, -10%);
|
||||
|
||||
background-color: $background-color-inverse-soft;
|
||||
// color: $text-color-inverse;
|
||||
border-radius: $border-radius-base;
|
||||
padding: $space-xx-small;
|
||||
box-shadow: $box-shadow-large;
|
||||
|
||||
.ds-button {
|
||||
color: $text-color-inverse;
|
||||
|
||||
&.ds-button-hover,
|
||||
&:hover {
|
||||
color: $text-color-base;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
left: calc(50% - 10px);
|
||||
}
|
||||
|
||||
input,
|
||||
button {
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.ds-input {
|
||||
height: auto;
|
||||
}
|
||||
input {
|
||||
padding: $space-xx-small $space-x-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
83
components/Editor/plugins/eventHandler.js
Normal file
83
components/Editor/plugins/eventHandler.js
Normal file
@ -0,0 +1,83 @@
|
||||
import { Extension, Plugin } from 'tiptap'
|
||||
// import { Slice, Fragment } from 'prosemirror-model'
|
||||
|
||||
export default class EventHandler extends Extension {
|
||||
get name() {
|
||||
return 'event_handler'
|
||||
}
|
||||
get plugins() {
|
||||
return [
|
||||
new Plugin({
|
||||
props: {
|
||||
transformPastedText(text) {
|
||||
// console.log('#### transformPastedText', text)
|
||||
return text.trim()
|
||||
},
|
||||
transformPastedHTML(html) {
|
||||
html = html
|
||||
// remove all tags with "space only"
|
||||
.replace(/<[a-z-]+>[\s]+<\/[a-z-]+>/gim, '')
|
||||
// remove all iframes
|
||||
.replace(
|
||||
/(<iframe(?!.*?src=(['"]).*?\2)[^>]*)(>)[^>]*\/*>/gim,
|
||||
''
|
||||
)
|
||||
.replace(/[\n]{3,}/gim, '\n\n')
|
||||
.replace(/(\r\n|\n\r|\r|\n)/g, '<br>$1')
|
||||
|
||||
// replace all p tags with line breaks (and spaces) only by single linebreaks
|
||||
// limit linebreaks to max 2 (equivalent to html "br" linebreak)
|
||||
.replace(/(<br ?\/?>\s*){2,}/gim, '<br>')
|
||||
// remove additional linebreaks after p tags
|
||||
.replace(
|
||||
/<\/(p|div|th|tr)>\s*(<br ?\/?>\s*)+\s*<(p|div|th|tr)>/gim,
|
||||
'</p><p>'
|
||||
)
|
||||
// remove additional linebreaks inside p tags
|
||||
.replace(
|
||||
/<[a-z-]+>(<[a-z-]+>)*\s*(<br ?\/?>\s*)+\s*(<\/[a-z-]+>)*<\/[a-z-]+>/gim,
|
||||
''
|
||||
)
|
||||
// remove additional linebreaks when first child inside p tags
|
||||
.replace(/<p>(\s*<br ?\/?>\s*)+/gim, '<p>')
|
||||
// remove additional linebreaks when last child inside p tags
|
||||
.replace(/(\s*<br ?\/?>\s*)+<\/p>/gim, '</p>')
|
||||
// console.log('#### transformPastedHTML', html)
|
||||
return html
|
||||
}
|
||||
// transformPasted(slice) {
|
||||
// // console.log('#### transformPasted', slice.content)
|
||||
// let content = []
|
||||
// let size = 0
|
||||
// slice.content.forEach((node, offset, index) => {
|
||||
// // console.log(node)
|
||||
// // console.log('isBlock', node.type.isBlock)
|
||||
// // console.log('childCount', node.content.childCount)
|
||||
// // console.log('index', index)
|
||||
// if (node.content.childCount) {
|
||||
// content.push(node.content)
|
||||
// size += node.content.size
|
||||
// }
|
||||
// })
|
||||
// console.log(content)
|
||||
// console.log(slice.content)
|
||||
// let fragment = Fragment.fromArray(content)
|
||||
// fragment.size = size
|
||||
// console.log('#fragment', fragment, slice.content)
|
||||
// console.log('----')
|
||||
// console.log('#1', slice)
|
||||
// // const newSlice = new Slice(fragment, slice.openStart, slice.openEnd)
|
||||
// slice.fragment = fragment
|
||||
// // slice.content.content = fragment.content
|
||||
// // slice.content.size = fragment.size
|
||||
// console.log('#2', slice)
|
||||
// // console.log(newSlice)
|
||||
// console.log('----')
|
||||
// return slice
|
||||
// // return newSlice
|
||||
// }
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -55,6 +55,7 @@
|
||||
context="contribution"
|
||||
:item-id="post.id"
|
||||
:name="post.title"
|
||||
:is-owner="isAuthor"
|
||||
/>
|
||||
</no-ssr>
|
||||
</div>
|
||||
@ -86,13 +87,16 @@ export default {
|
||||
computed: {
|
||||
excerpt() {
|
||||
// remove all links from excerpt to prevent issues with the serounding link
|
||||
let excerpt = this.post.contentExcerpt.replace(/<a.*>(.+)<\/a>/gim, '')
|
||||
let excerpt = this.post.contentExcerpt.replace(/<a.*>(.+)<\/a>/gim, '$1')
|
||||
// do not display content that is only linebreaks
|
||||
if (excerpt.replace(/<br>/gim, '').trim() === '') {
|
||||
excerpt = ''
|
||||
}
|
||||
|
||||
return excerpt
|
||||
},
|
||||
isAuthor() {
|
||||
return this.$store.getters['auth/user'].id === this.post.author.id
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
6
cypress.env.template.json
Normal file
6
cypress.env.template.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"SEED_SERVER_HOST": "http://localhost:4001",
|
||||
"NEO4J_URI": "bolt://localhost:7687",
|
||||
"NEO4J_USERNAME": "neo4j",
|
||||
"NEO4J_PASSWORD": "letmein"
|
||||
}
|
||||
@ -4,11 +4,7 @@ Feature: Authentication
|
||||
In order to attribute posts and other contributions to their authors
|
||||
|
||||
Background:
|
||||
Given my account has the following details:
|
||||
| name | email | password | type
|
||||
| Peter Lustig | admin@example.org | 1234 | Admin
|
||||
| Bob der Bausmeister | moderator@example.org | 1234 | Moderator
|
||||
| Jenny Rostock" | user@example.org | 1234 | User
|
||||
Given I have a user account
|
||||
|
||||
Scenario: Log in
|
||||
When I visit the "/login" page
|
||||
|
||||
@ -14,28 +14,27 @@ Feature: Tags and Categories
|
||||
looking at the popularity of a tag.
|
||||
|
||||
Background:
|
||||
Given we have a selection of tags and categories as well as posts
|
||||
And my user account has the role "administrator"
|
||||
Given I am logged in
|
||||
Given my user account has the role "admin"
|
||||
And we have a selection of tags and categories as well as posts
|
||||
And I am logged in
|
||||
|
||||
Scenario: See an overview of categories
|
||||
When I navigate to the administration dashboard
|
||||
And I click on "Categories"
|
||||
Then I can see a list of categories ordered by post count:
|
||||
| Icon | Name | Post Count |
|
||||
| | Just For Fun | 5 |
|
||||
| | Happyness & Values | 2 |
|
||||
| | Health & Wellbeing | 1 |
|
||||
| Icon | Name | Posts |
|
||||
| | Just For Fun | 2 |
|
||||
| | Happyness & Values | 1 |
|
||||
| | Health & Wellbeing | 0 |
|
||||
|
||||
Scenario: See an overview of tags
|
||||
When I navigate to the administration dashboard
|
||||
And I click on "Tags"
|
||||
Then I can see a list of tags ordered by user and post count:
|
||||
| # | Name | Nutzer | Beiträge |
|
||||
| 1 | Naturschutz | 2 | 2 |
|
||||
| 2 | Freiheit | 2 | 2 |
|
||||
| 3 | Umwelt | 1 | 1 |
|
||||
| 4 | Demokratie | 1 | 1 |
|
||||
Then I can see a list of tags ordered by user count:
|
||||
| # | Name | Users | Posts |
|
||||
| 1 | Democracy | 2 | 3 |
|
||||
| 2 | Ecology | 1 | 1 |
|
||||
| 3 | Nature | 1 | 2 |
|
||||
|
||||
|
||||
|
||||
|
||||
@ -7,21 +7,18 @@ Feature: About me and location
|
||||
to search for users by location.
|
||||
|
||||
Background:
|
||||
Given I am logged in
|
||||
Given I have a user account
|
||||
And I am logged in
|
||||
And I am on the "settings" page
|
||||
|
||||
Scenario: Change username
|
||||
When I save "Hansi" as my new name
|
||||
Then I can see my new name "Hansi" when I click on my profile picture in the top right
|
||||
|
||||
Scenario: Keep changes after refresh
|
||||
When I changed my username to "Hansi" previously
|
||||
And I refresh the page
|
||||
Then my new username is still there
|
||||
And when I refresh the page
|
||||
Then the name "Hansi" is still there
|
||||
|
||||
Scenario Outline: I set my location to "<location>"
|
||||
When I save "<location>" as my location
|
||||
And my username is "Peter Lustig"
|
||||
When people visit my profile page
|
||||
Then they can see the location in the info box below my avatar
|
||||
|
||||
@ -36,10 +33,5 @@ Feature: About me and location
|
||||
"""
|
||||
Ich lebe fettlos, fleischlos, fischlos dahin, fühle mich aber ganz wohl dabei
|
||||
"""
|
||||
And my username is "Peter Lustig"
|
||||
When people visit my profile page
|
||||
Then they can see the text in the info box below my avatar
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -9,13 +9,13 @@ Feature: Report and Moderate
|
||||
|
||||
Background:
|
||||
Given we have the following posts in our database:
|
||||
| Author | Title | Content | Slug |
|
||||
| David Irving | The Truth about the Holocaust | It never existed! | the-truth-about-the-holocaust |
|
||||
| Author | id | title | content |
|
||||
| David Irving | p1 | The Truth about the Holocaust | It never existed! |
|
||||
|
||||
Scenario Outline: Report a post from various pages
|
||||
Given I am logged in with a "user" role
|
||||
And I see David Irving's post on the <Page>
|
||||
When I click on "Report Contribution" from the triple dot menu of the post
|
||||
When I see David Irving's post on the <Page>
|
||||
And I click on "Report Contribution" from the triple dot menu of the post
|
||||
And I confirm the reporting dialog because it is a criminal act under German law:
|
||||
"""
|
||||
Do you really want to report the contribution "The Truth about the Holocaust"?
|
||||
@ -45,8 +45,8 @@ Feature: Report and Moderate
|
||||
|
||||
Scenario: Review reported content
|
||||
Given somebody reported the following posts:
|
||||
| Slug |
|
||||
| the-truth-about-the-holocaust |
|
||||
| id |
|
||||
| p1 |
|
||||
And I am logged in with a "moderator" role
|
||||
When I click on the avatar menu in the top right corner
|
||||
And I click on "Moderation"
|
||||
|
||||
25
cypress/integration/06.WritePost.feature
Normal file
25
cypress/integration/06.WritePost.feature
Normal file
@ -0,0 +1,25 @@
|
||||
Feature: Create a post
|
||||
As a user
|
||||
I would like to create a post
|
||||
To say something to everyone in the community
|
||||
|
||||
Background:
|
||||
Given I have a user account
|
||||
And I am logged in
|
||||
And I am on the "landing" page
|
||||
|
||||
Scenario: Create a post
|
||||
When I click on the big plus icon in the bottom right corner to create post
|
||||
And I choose "My first post" as the title of the post
|
||||
And I type in the following text:
|
||||
"""
|
||||
Human Connection is a free and open-source social network
|
||||
for active citizenship.
|
||||
"""
|
||||
And I click on "Save"
|
||||
Then I get redirected to "/post/my-first-post/"
|
||||
And the post was saved successfully
|
||||
|
||||
Scenario: See a post on the landing page
|
||||
Given I previously created a post
|
||||
Then the post shows up on the landing page at position 1
|
||||
@ -2,18 +2,6 @@ import { When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
|
||||
/* global cy */
|
||||
|
||||
const lastColumnIsSortedInDescendingOrder = () => {
|
||||
cy.get('tbody')
|
||||
.find('tr td:last-child')
|
||||
.then(lastColumn => {
|
||||
cy.wrap(lastColumn)
|
||||
const values = lastColumn
|
||||
.map((i, td) => parseInt(td.textContent))
|
||||
.toArray()
|
||||
const orderedDescending = values.slice(0).sort((a, b) => b - a)
|
||||
return cy.wrap(values).should('deep.eq', orderedDescending)
|
||||
})
|
||||
}
|
||||
|
||||
When('I navigate to the administration dashboard', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
@ -23,17 +11,27 @@ When('I navigate to the administration dashboard', () => {
|
||||
})
|
||||
|
||||
Then('I can see a list of categories ordered by post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
cy.get('thead')
|
||||
.find('tr th')
|
||||
.should('have.length', 3)
|
||||
lastColumnIsSortedInDescendingOrder()
|
||||
table.hashes().forEach(({Name, Posts}, index) => {
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(2)`)
|
||||
.should('contain', Name)
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(3)`)
|
||||
.should('contain', Posts)
|
||||
})
|
||||
})
|
||||
|
||||
Then('I can see a list of tags ordered by user and post count:', table => {
|
||||
// TODO: match the table in the feature with the html table
|
||||
Then('I can see a list of tags ordered by user count:', table => {
|
||||
cy.get('thead')
|
||||
.find('tr th')
|
||||
.should('have.length', 4)
|
||||
lastColumnIsSortedInDescendingOrder()
|
||||
table.hashes().forEach(({Name, Users, Posts}, index) => {
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(2)`)
|
||||
.should('contain', Name)
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(3)`)
|
||||
.should('contain', Users)
|
||||
cy.get(`tbody > :nth-child(${index + 1}) > :nth-child(4)`)
|
||||
.should('contain', Posts)
|
||||
})
|
||||
})
|
||||
|
||||
@ -3,9 +3,9 @@ import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
/* global cy */
|
||||
|
||||
let lastReportTitle
|
||||
let dummyReportedPostTitle = 'Hacker, Freaks und Funktionäre'
|
||||
let dummyReportedPostSlug = 'hacker-freaks-und-funktionareder-ccc'
|
||||
let dummyAuthorName = 'Jenny Rostock'
|
||||
let davidIrvingPostTitle = 'The Truth about the Holocaust'
|
||||
let davidIrvingPostSlug = 'the-truth-about-the-holocaust'
|
||||
let davidIrvingName = 'David Irving'
|
||||
|
||||
const savePostTitle = $post => {
|
||||
return $post
|
||||
@ -23,21 +23,27 @@ Given("I see David Irving's post on the landing page", page => {
|
||||
})
|
||||
|
||||
Given("I see David Irving's post on the post page", page => {
|
||||
cy.visit(`/post/${dummyReportedPostSlug}`)
|
||||
cy.contains(dummyReportedPostTitle) // wait
|
||||
cy.visit(`/post/${davidIrvingPostSlug}`)
|
||||
cy.contains(davidIrvingPostTitle) // wait
|
||||
})
|
||||
|
||||
Given('I am logged in with a {string} role', role => {
|
||||
cy.loginAs(role)
|
||||
cy.factory().create('User', {
|
||||
email: `${role}@example.org`,
|
||||
password: '1234',
|
||||
role
|
||||
})
|
||||
cy.login({
|
||||
email: `${role}@example.org`,
|
||||
password: '1234'
|
||||
})
|
||||
})
|
||||
|
||||
When(
|
||||
'I click on "Report Contribution" from the triple dot menu of the post',
|
||||
() => {
|
||||
//TODO: match the created post title, not a dummy post title
|
||||
cy.contains('.ds-card', dummyReportedPostTitle)
|
||||
cy.contains('.ds-card', davidIrvingPostTitle)
|
||||
.find('.content-menu-trigger')
|
||||
.first()
|
||||
.click()
|
||||
|
||||
cy.get('.popover .ds-menu-item-link')
|
||||
@ -49,8 +55,7 @@ When(
|
||||
When(
|
||||
'I click on "Report User" from the triple dot menu in the user info box',
|
||||
() => {
|
||||
//TODO: match the created post author, not a dummy author
|
||||
cy.contains('.ds-card', dummyAuthorName)
|
||||
cy.contains('.ds-card', davidIrvingName)
|
||||
.find('.content-menu-trigger')
|
||||
.first()
|
||||
.click()
|
||||
@ -106,12 +111,8 @@ Then(`I can't see the moderation menu item`, () => {
|
||||
.should('not.exist')
|
||||
})
|
||||
|
||||
When(/^I confirm the reporting dialog .*:$/, () => {
|
||||
//TODO: take message from method argument
|
||||
//TODO: match the right post
|
||||
const message = 'Do you really want to report the'
|
||||
When(/^I confirm the reporting dialog .*:$/, (message) => {
|
||||
cy.contains(message) // wait for element to become visible
|
||||
//TODO: cy.get('.ds-modal').contains(dummyReportedPostTitle)
|
||||
cy.get('.ds-modal').within(() => {
|
||||
cy.get('button')
|
||||
.contains('Send Report')
|
||||
@ -120,22 +121,28 @@ When(/^I confirm the reporting dialog .*:$/, () => {
|
||||
})
|
||||
|
||||
Given('somebody reported the following posts:', table => {
|
||||
table.hashes().forEach(row => {
|
||||
//TODO: calll factory here
|
||||
// const options = Object.assign({}, row, { reported: true })
|
||||
//create('post', options)
|
||||
table.hashes().forEach(({ id }) => {
|
||||
const reporter = {
|
||||
email: `reporter${id}@example.org`,
|
||||
password: '1234'
|
||||
}
|
||||
cy.factory()
|
||||
.create('User', reporter)
|
||||
.authenticateAs(reporter)
|
||||
.create('Report', {
|
||||
description: "I don't like this post",
|
||||
resource: { id, type: 'contribution' }
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Then('I see all the reported posts including the one from above', () => {
|
||||
//TODO: match the right post
|
||||
cy.get('table tbody').within(() => {
|
||||
cy.contains('tr', dummyReportedPostTitle)
|
||||
cy.contains('tr', davidIrvingPostTitle)
|
||||
})
|
||||
})
|
||||
|
||||
Then('each list item links to the post page', () => {
|
||||
//TODO: match the right post
|
||||
cy.contains(dummyReportedPostTitle).click()
|
||||
cy.contains(davidIrvingPostTitle).click()
|
||||
cy.location('pathname').should('contain', '/post')
|
||||
})
|
||||
|
||||
@ -4,7 +4,6 @@ import { When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
|
||||
let aboutMeText
|
||||
let myLocation
|
||||
let myName
|
||||
|
||||
const matchNameInUserMenu = name => {
|
||||
cy.get('.avatar-menu').click() // open
|
||||
@ -12,18 +11,13 @@ const matchNameInUserMenu = name => {
|
||||
cy.get('.avatar-menu').click() // close again
|
||||
}
|
||||
|
||||
const setUserName = name => {
|
||||
When('I save {string} as my new name', name => {
|
||||
cy.get('input[id=name]')
|
||||
.clear()
|
||||
.type(name)
|
||||
cy.get('[type=submit]')
|
||||
.click()
|
||||
.not('[disabled]')
|
||||
myName = name
|
||||
}
|
||||
|
||||
When('I save {string} as my new name', name => {
|
||||
setUserName(name)
|
||||
})
|
||||
|
||||
When('I save {string} as my location', location => {
|
||||
@ -47,31 +41,20 @@ When('I have the following self-description:', text => {
|
||||
aboutMeText = text
|
||||
})
|
||||
|
||||
When('my username is {string}', name => {
|
||||
if (myName !== name) {
|
||||
setUserName(name)
|
||||
}
|
||||
matchNameInUserMenu(name)
|
||||
})
|
||||
|
||||
When('people visit my profile page', url => {
|
||||
cy.visitMyProfile()
|
||||
cy.openPage('/profile/peter-pan')
|
||||
})
|
||||
|
||||
When('they can see the text in the info box below my avatar', () => {
|
||||
cy.contains(aboutMeText)
|
||||
})
|
||||
|
||||
When('I changed my username to {string} previously', name => {
|
||||
myName = name
|
||||
})
|
||||
|
||||
Then('they can see the location in the info box below my avatar', () => {
|
||||
matchNameInUserMenu(myName)
|
||||
cy.contains(myLocation)
|
||||
})
|
||||
|
||||
Then('my new username is still there', () => {
|
||||
matchNameInUserMenu(myName)
|
||||
Then('the name {string} is still there', name => {
|
||||
matchNameInUserMenu(name)
|
||||
})
|
||||
|
||||
Then(
|
||||
|
||||
@ -1,26 +1,87 @@
|
||||
import { Given, When, Then } from 'cypress-cucumber-preprocessor/steps'
|
||||
import { getLangByName } from '../../support/helpers'
|
||||
import users from '../../fixtures/users.json'
|
||||
|
||||
/* global cy */
|
||||
|
||||
let lastPost = {}
|
||||
|
||||
const loginCredentials = {
|
||||
email: 'peterpan@example.org',
|
||||
password: '1234'
|
||||
}
|
||||
const narratorParams = {
|
||||
name: 'Peter Pan',
|
||||
...loginCredentials
|
||||
}
|
||||
|
||||
Given('I am logged in', () => {
|
||||
cy.loginAs('admin')
|
||||
})
|
||||
Given('I am logged in as {string}', userType => {
|
||||
cy.loginAs(userType)
|
||||
cy.login(loginCredentials)
|
||||
})
|
||||
|
||||
Given('we have a selection of tags and categories as well as posts', () => {
|
||||
// TODO: use db factories instead of seed data
|
||||
cy.factory()
|
||||
.authenticateAs(loginCredentials)
|
||||
.create('Category', {
|
||||
id: 'cat1',
|
||||
name: 'Just For Fun',
|
||||
slug: 'justforfun',
|
||||
icon: 'smile'
|
||||
})
|
||||
.create('Category', {
|
||||
id: 'cat2',
|
||||
name: 'Happyness & Values',
|
||||
slug: 'happyness-values',
|
||||
icon: 'heart-o'
|
||||
})
|
||||
.create('Category', {
|
||||
id: 'cat3',
|
||||
name: 'Health & Wellbeing',
|
||||
slug: 'health-wellbeing',
|
||||
icon: 'medkit'
|
||||
})
|
||||
.create('Tag', { id: 't1', name: 'Ecology' })
|
||||
.create('Tag', { id: 't2', name: 'Nature' })
|
||||
.create('Tag', { id: 't3', name: 'Democracy' })
|
||||
|
||||
const someAuthor = {
|
||||
id: 'authorId',
|
||||
email: 'author@example.org',
|
||||
password: '1234'
|
||||
}
|
||||
cy.factory()
|
||||
.create('User', someAuthor)
|
||||
.authenticateAs(someAuthor)
|
||||
.create('Post', { id: 'p0' })
|
||||
.create('Post', { id: 'p1' })
|
||||
cy.factory()
|
||||
.authenticateAs(loginCredentials)
|
||||
.create('Post', { id: 'p2' })
|
||||
.relate('Post', 'Categories', { from: 'p0', to: 'cat1' })
|
||||
.relate('Post', 'Categories', { from: 'p1', to: 'cat2' })
|
||||
.relate('Post', 'Categories', { from: 'p2', to: 'cat1' })
|
||||
.relate('Post', 'Tags', { from: 'p0', to: 't1' })
|
||||
.relate('Post', 'Tags', { from: 'p0', to: 't2' })
|
||||
.relate('Post', 'Tags', { from: 'p0', to: 't3' })
|
||||
.relate('Post', 'Tags', { from: 'p1', to: 't2' })
|
||||
.relate('Post', 'Tags', { from: 'p1', to: 't3' })
|
||||
.relate('Post', 'Tags', { from: 'p2', to: 't3' })
|
||||
})
|
||||
|
||||
Given('my account has the following details:', table => {
|
||||
// TODO: use db factories instead of seed data
|
||||
Given('we have the following user accounts:', table => {
|
||||
table.hashes().forEach(params => {
|
||||
cy.factory().create('User', params)
|
||||
})
|
||||
})
|
||||
|
||||
Given('I have a user account', () => {
|
||||
cy.factory().create('User', narratorParams)
|
||||
})
|
||||
|
||||
Given('my user account has the role {string}', role => {
|
||||
// TODO: use db factories instead of seed data
|
||||
cy.factory().create('User', {
|
||||
role,
|
||||
...loginCredentials
|
||||
})
|
||||
})
|
||||
|
||||
When('I log out', cy.logout)
|
||||
@ -34,10 +95,10 @@ Given('I am on the {string} page', page => {
|
||||
})
|
||||
|
||||
When('I fill in my email and password combination and click submit', () => {
|
||||
cy.login('admin@example.org', 1234)
|
||||
cy.login(loginCredentials)
|
||||
})
|
||||
|
||||
When('I refresh the page', () => {
|
||||
When(/(?:when )?I refresh the page/, () => {
|
||||
cy.reload()
|
||||
})
|
||||
|
||||
@ -49,7 +110,7 @@ When('I log out through the menu in the top right corner', () => {
|
||||
})
|
||||
|
||||
Then('I can see my name {string} in the dropdown menu', () => {
|
||||
cy.get('.avatar-menu-popover').should('contain', users.admin.name)
|
||||
cy.get('.avatar-menu-popover').should('contain', narratorParams.name)
|
||||
})
|
||||
|
||||
Then('I see the login screen again', () => {
|
||||
@ -63,7 +124,7 @@ Then('I can click on my profile picture in the top right corner', () => {
|
||||
|
||||
Then('I am still logged in', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover').contains(users.admin.name)
|
||||
cy.get('.avatar-menu-popover').contains(narratorParams.name)
|
||||
})
|
||||
|
||||
When('I select {string} in the language menu', name => {
|
||||
@ -90,9 +151,18 @@ When('I press {string}', label => {
|
||||
})
|
||||
|
||||
Given('we have the following posts in our database:', table => {
|
||||
table.hashes().forEach(row => {
|
||||
//TODO: calll factory here
|
||||
//create('post', row)
|
||||
table.hashes().forEach(({ Author, id, title, content }) => {
|
||||
cy.factory()
|
||||
.create('User', {
|
||||
name: Author,
|
||||
email: `${Author}@example.org`,
|
||||
password: '1234'
|
||||
})
|
||||
.authenticateAs({
|
||||
email: `${Author}@example.org`,
|
||||
password: '1234'
|
||||
})
|
||||
.create('Post', { id, title, content })
|
||||
})
|
||||
})
|
||||
|
||||
@ -103,3 +173,42 @@ Then('I see a success message:', message => {
|
||||
When('I click on the avatar menu in the top right corner', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
})
|
||||
|
||||
When(
|
||||
'I click on the big plus icon in the bottom right corner to create post',
|
||||
() => {
|
||||
cy.get('.post-add-button').click()
|
||||
}
|
||||
)
|
||||
|
||||
Given('I previously created a post', () => {
|
||||
cy.factory()
|
||||
.authenticateAs(loginCredentials)
|
||||
.create('Post', lastPost)
|
||||
})
|
||||
|
||||
When('I choose {string} as the title of the post', title => {
|
||||
lastPost.title = title.replace('\n', ' ')
|
||||
cy.get('input[name="title"]').type(lastPost.title)
|
||||
})
|
||||
|
||||
When('I type in the following text:', text => {
|
||||
lastPost.content = text.replace('\n', ' ')
|
||||
cy.get('.ProseMirror').type(lastPost.content)
|
||||
})
|
||||
|
||||
Then('the post shows up on the landing page at position {int}', index => {
|
||||
cy.openPage('landing')
|
||||
const selector = `:nth-child(${index}) > .ds-card > .ds-card-content`
|
||||
cy.get(selector).should('contain', lastPost.title)
|
||||
cy.get(selector).should('contain', lastPost.content)
|
||||
})
|
||||
|
||||
Then('I get redirected to {string}', route => {
|
||||
cy.location('pathname').should('contain', route)
|
||||
})
|
||||
|
||||
Then('the post was saved successfully', () => {
|
||||
cy.get('.ds-card-header > .ds-heading').should('contain', lastPost.title)
|
||||
cy.get('.content').should('contain', lastPost.content)
|
||||
})
|
||||
|
||||
@ -35,14 +35,7 @@ Cypress.Commands.add('switchLanguage', (name, force) => {
|
||||
}
|
||||
})
|
||||
|
||||
Cypress.Commands.add('visitMyProfile', () => {
|
||||
cy.get('.avatar-menu').click()
|
||||
cy.get('.avatar-menu-popover')
|
||||
.find('a[href^="/profile/"]')
|
||||
.click()
|
||||
})
|
||||
|
||||
Cypress.Commands.add('login', (email, password) => {
|
||||
Cypress.Commands.add('login', ({ email, password }) => {
|
||||
cy.visit(`/login`)
|
||||
cy.get('input[name=email]')
|
||||
.trigger('focus')
|
||||
@ -56,11 +49,6 @@ Cypress.Commands.add('login', (email, password) => {
|
||||
cy.location('pathname').should('eq', '/') // we're in!
|
||||
})
|
||||
|
||||
Cypress.Commands.add('loginAs', role => {
|
||||
role = role || 'admin'
|
||||
cy.login(users[role].email, users[role].password)
|
||||
})
|
||||
|
||||
Cypress.Commands.add('logout', (email, password) => {
|
||||
cy.visit(`/logout`)
|
||||
cy.location('pathname').should('contain', '/login') // we're out
|
||||
|
||||
43
cypress/support/factories.js
Normal file
43
cypress/support/factories.js
Normal file
@ -0,0 +1,43 @@
|
||||
// TODO: find a better way how to import the factories
|
||||
import Factory from '../../../Nitro-Backend/src/seed/factories'
|
||||
import { getDriver } from '../../../Nitro-Backend/src/bootstrap/neo4j'
|
||||
|
||||
const neo4jDriver = getDriver({
|
||||
uri: Cypress.env('NEO4J_URI'),
|
||||
username: Cypress.env('NEO4J_USERNAME'),
|
||||
password: Cypress.env('NEO4J_PASSWORD')
|
||||
})
|
||||
const factory = Factory({ neo4jDriver })
|
||||
const seedServerHost = Cypress.env('SEED_SERVER_HOST')
|
||||
|
||||
beforeEach(async () => {
|
||||
await factory.cleanDatabase({ seedServerHost, neo4jDriver })
|
||||
})
|
||||
|
||||
Cypress.Commands.add('factory', () => {
|
||||
return Factory({seedServerHost})
|
||||
})
|
||||
|
||||
Cypress.Commands.add(
|
||||
'create',
|
||||
{ prevSubject: true },
|
||||
(factory, node, properties) => {
|
||||
return factory.create(node, properties)
|
||||
}
|
||||
)
|
||||
|
||||
Cypress.Commands.add(
|
||||
'relate',
|
||||
{ prevSubject: true },
|
||||
(factory, node, relationship, properties) => {
|
||||
return factory.relate(node, relationship, properties)
|
||||
}
|
||||
)
|
||||
|
||||
Cypress.Commands.add(
|
||||
'authenticateAs',
|
||||
{ prevSubject: true },
|
||||
(factory, loginCredentials) => {
|
||||
return factory.authenticateAs(loginCredentials)
|
||||
}
|
||||
)
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
import './factories'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
@ -8,7 +8,9 @@ services:
|
||||
volumes:
|
||||
- .:/nitro-web
|
||||
- node_modules:/nitro-web/node_modules
|
||||
- nuxt:/nitro-web/.nuxt
|
||||
command: yarn run dev
|
||||
|
||||
volumes:
|
||||
node_modules:
|
||||
nuxt:
|
||||
|
||||
@ -5,3 +5,5 @@ services:
|
||||
build:
|
||||
context: .
|
||||
target: build-and-test
|
||||
environment:
|
||||
- BACKEND_URL=http://backend:4123
|
||||
|
||||
28
graphql/PostMutations.js
Normal file
28
graphql/PostMutations.js
Normal file
@ -0,0 +1,28 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default app => {
|
||||
return {
|
||||
CreatePost: gql(`
|
||||
mutation($title: String!, $content: String!) {
|
||||
CreatePost(title: $title, content: $content) {
|
||||
id
|
||||
title
|
||||
slug
|
||||
content
|
||||
contentExcerpt
|
||||
}
|
||||
}
|
||||
`),
|
||||
UpdatePost: gql(`
|
||||
mutation($id: ID!, $title: String!, $content: String!) {
|
||||
UpdatePost(id: $id, title: $title, content: $content) {
|
||||
id
|
||||
title
|
||||
slug
|
||||
content
|
||||
contentExcerpt
|
||||
}
|
||||
}
|
||||
`)
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,8 @@
|
||||
"create": "Erstellen",
|
||||
"save": "Speichern",
|
||||
"edit": "Bearbeiten",
|
||||
"delete": "Löschen"
|
||||
"delete": "Löschen",
|
||||
"cancel": "Abbrechen"
|
||||
},
|
||||
"login": {
|
||||
"copy": "Wenn Du bereits ein Konto bei Human Connection hast, melde Dich bitte hier an.",
|
||||
@ -100,6 +101,14 @@
|
||||
"reporter": "gemeldet von"
|
||||
}
|
||||
},
|
||||
"contribution": {
|
||||
"edit": "Beitrag bearbeiten",
|
||||
"delete": "Beitrag löschen"
|
||||
},
|
||||
"comment": {
|
||||
"edit": "Kommentar bearbeiten",
|
||||
"delete": "Kommentar löschen"
|
||||
},
|
||||
"disable": {
|
||||
"user": {
|
||||
"title": "Nutzer sperren",
|
||||
|
||||
@ -5,7 +5,8 @@
|
||||
"create": "Create",
|
||||
"save": "Save",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete"
|
||||
"delete": "Delete",
|
||||
"cancel": "Cancel"
|
||||
},
|
||||
"login": {
|
||||
"copy": "If you already have a human-connection account, login here.",
|
||||
@ -100,6 +101,14 @@
|
||||
"reporter": "reported by"
|
||||
}
|
||||
},
|
||||
"contribution": {
|
||||
"edit": "Edit Contribution",
|
||||
"delete": "Delete Contribution"
|
||||
},
|
||||
"comment": {
|
||||
"edit": "Edit Comment",
|
||||
"delete": "Delete Comment"
|
||||
},
|
||||
"disable": {
|
||||
"user": {
|
||||
"title": "Disable User",
|
||||
|
||||
@ -46,18 +46,22 @@
|
||||
"express": "~4.16.4",
|
||||
"graphql": "~14.1.1",
|
||||
"jsonwebtoken": "~8.5.0",
|
||||
"linkify-it": "~2.1.0",
|
||||
"nuxt": "~2.4.3",
|
||||
"nuxt-env": "~0.1.0",
|
||||
"portal-vue": "~1.5.1",
|
||||
"@human-connection/styleguide": "~0.5.2",
|
||||
"v-tooltip": "~2.0.0-rc.33",
|
||||
"vue-count-to": "~1.0.13",
|
||||
"string-hash": "^1.1.3",
|
||||
"tiptap": "^1.13.0",
|
||||
"tiptap-extensions": "^1.13.0",
|
||||
"vue-izitoast": "1.1.2",
|
||||
"vue-sweetalert-icons": "~3.2.0",
|
||||
"vuex-i18n": "~1.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.3.3",
|
||||
"@babel/core": "~7.3.4",
|
||||
"@babel/preset-env": "~7.3.1",
|
||||
"@vue/cli-shared-utils": "~3.4.0",
|
||||
"@vue/eslint-config-prettier": "~4.0.1",
|
||||
|
||||
@ -13,6 +13,16 @@
|
||||
<hc-post-card :post="post" />
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
<no-ssr>
|
||||
<ds-button
|
||||
v-tooltip="{content: 'Create a new Post', placement: 'left', delay: { show: 500 }}"
|
||||
:path="{ name: 'post-create' }"
|
||||
class="post-add-button"
|
||||
icon="plus"
|
||||
size="x-large"
|
||||
primary
|
||||
/>
|
||||
</no-ssr>
|
||||
<hc-load-more
|
||||
v-if="true"
|
||||
:loading="$apollo.loading"
|
||||
@ -82,7 +92,7 @@ export default {
|
||||
query() {
|
||||
return gql(`
|
||||
query Post($first: Int, $offset: Int) {
|
||||
Post(first: $first, offset: $offset) {
|
||||
Post(first: $first, offset: $offset, orderBy: createdAt_desc) {
|
||||
id
|
||||
title
|
||||
contentExcerpt
|
||||
@ -123,8 +133,20 @@ export default {
|
||||
first: this.pageSize,
|
||||
offset: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'cache-and-network'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.post-add-button {
|
||||
z-index: 100;
|
||||
position: fixed;
|
||||
top: 100vh;
|
||||
left: 100vw;
|
||||
transform: translate(-120%, -120%);
|
||||
box-shadow: $box-shadow-x-large;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
context="contribution"
|
||||
:item-id="post.id"
|
||||
:name="post.title"
|
||||
:is-owner="isAuthor(post.author.id)"
|
||||
/>
|
||||
</no-ssr>
|
||||
<ds-space margin-bottom="small" />
|
||||
@ -97,6 +98,7 @@
|
||||
style="float-right"
|
||||
:item-id="comment.id"
|
||||
:name="comment.author.name"
|
||||
:is-owner="isAuthor(comment.author.id)"
|
||||
/>
|
||||
</no-ssr>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
@ -160,6 +162,11 @@ export default {
|
||||
this.title = this.post.title
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isAuthor(id) {
|
||||
return this.$store.getters['auth/user'].id === id
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
Post: {
|
||||
query() {
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
<ds-flex-item
|
||||
v-for="relatedPost in post.relatedContributions"
|
||||
:key="relatedPost.id"
|
||||
:width="{ base: '50%' }"
|
||||
:width="{ base: '100%', lg: 1 }"
|
||||
>
|
||||
<hc-post-card :post="relatedPost" />
|
||||
</ds-flex-item>
|
||||
@ -70,7 +70,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
post() {
|
||||
return this.Post ? this.Post[0] : {}
|
||||
return this.Post ? this.Post[0] || {} : {}
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
|
||||
24
pages/post/create.vue
Normal file
24
pages/post/create.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<ds-flex
|
||||
:width="{ base: '100%' }"
|
||||
gutter="base"
|
||||
>
|
||||
<ds-flex-item :width="{ base: '100%', md: 3 }">
|
||||
<hc-contribution-form />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }">
|
||||
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import HcContributionForm from '~/components/ContributionForm.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcContributionForm
|
||||
}
|
||||
}
|
||||
</script>
|
||||
77
pages/post/edit/_id.vue
Normal file
77
pages/post/edit/_id.vue
Normal file
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<ds-flex
|
||||
:width="{ base: '100%' }"
|
||||
gutter="base"
|
||||
>
|
||||
<ds-flex-item :width="{ base: '100%', md: 3 }">
|
||||
<hc-contribution-form :contribution="contribution" />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }">
|
||||
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
import HcContributionForm from '~/components/ContributionForm.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcContributionForm
|
||||
},
|
||||
computed: {
|
||||
user() {
|
||||
return this.$store.getters['auth/user']
|
||||
},
|
||||
author() {
|
||||
return this.contribution ? this.contribution.author : {}
|
||||
},
|
||||
contribution() {
|
||||
return this.Post ? this.Post[0] : {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
contribution() {
|
||||
if (this.author.id !== this.user.id) {
|
||||
throw new Error(`You can't edit that!`)
|
||||
}
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
Post: {
|
||||
query() {
|
||||
return gql(`
|
||||
query($id: ID!) {
|
||||
Post(id: $id) {
|
||||
id
|
||||
title
|
||||
content
|
||||
createdAt
|
||||
slug
|
||||
image
|
||||
author {
|
||||
id
|
||||
}
|
||||
tags {
|
||||
name
|
||||
}
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
id: this.$route.params.id || 'p1'
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'cache-and-network'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -23,6 +23,7 @@
|
||||
context="user"
|
||||
:item-id="user.id"
|
||||
:name="user.name"
|
||||
:is-owner="myProfile"
|
||||
/>
|
||||
</no-ssr>
|
||||
<ds-space margin="small">
|
||||
@ -251,6 +252,17 @@
|
||||
</ds-flex>
|
||||
</ds-card>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item style="text-align: center">
|
||||
<ds-button
|
||||
v-if="myProfile"
|
||||
v-tooltip="{content: 'Create a new Post', placement: 'left', delay: { show: 500 }}"
|
||||
:path="{ name: 'post-create' }"
|
||||
class="profile-post-add-button"
|
||||
icon="plus"
|
||||
size="large"
|
||||
primary
|
||||
/>
|
||||
</ds-flex-item>
|
||||
<template v-if="activePosts.length">
|
||||
<ds-flex-item
|
||||
v-for="post in activePosts"
|
||||
|
||||
5
styleguide/src/system/icons/svg/bold.svg
Executable file
5
styleguide/src/system/icons/svg/bold.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>bold</title>
|
||||
<path d="M16 7h-9v18h11c2.8 0 5-2.2 5-5 0-2.2-1.4-4-3.3-4.7 0.8-0.9 1.3-2 1.3-3.3 0-2.8-2.2-5-5-5zM9 15v-6h7c1.7 0 3 1.3 3 3s-1.3 3-3 3h-7zM9 23v-6h9c1.7 0 3 1.3 3 3s-1.3 3-3 3h-9zM16 5v0c3.9 0 7 3.1 7 7 0 0.9-0.2 1.8-0.5 2.6 1.5 1.3 2.5 3.3 2.5 5.4 0 3.9-3.1 7-7 7h-13v-22h11zM11 11v0 2h5c0.6 0 1-0.4 1-1s-0.4-1-1-1h-5zM11 19v0 2h7c0.6 0 1-0.4 1-1s-0.4-1-1-1h-7z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 531 B |
5
styleguide/src/system/icons/svg/italic.svg
Executable file
5
styleguide/src/system/icons/svg/italic.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>italic</title>
|
||||
<path d="M11.75 5h10.031l-0.094 1.063-0.188 3-0.063 0.938h-2l-0.875 12h2l-0.063 1.063-0.188 3-0.063 0.938h-10.031l0.094-1.063 0.188-3 0.063-0.938h2l0.875-12h-2l0.063-1.063 0.188-3zM13.625 7l-0.063 1h2l-0.063 1.063-1 14-0.063 0.938h-2l-0.063 1h6l0.063-1h-2l0.063-1.063 1-14 0.063-0.938h2l0.063-1h-6z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 468 B |
5
styleguide/src/system/icons/svg/list-ol.svg
Executable file
5
styleguide/src/system/icons/svg/list-ol.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>list-ol</title>
|
||||
<path d="M5.969 3h2.031v7h-2v-4.531c-0.444 0.255-0.913 0.531-1.594 0.531v-2c0.494 0 1.25-0.656 1.25-0.656zM11 6h17v2h-17v-2zM6.5 12c1.383 0 2.5 1.117 2.5 2.5 0 0.481-0.248 1.090-0.75 1.5l0.031 0.031-0.125 0.094-0.875 0.875h1.719v2h-5v-1.625l0.313-0.281 2.688-2.594c0-0.217-0.283-0.5-0.5-0.5s-0.5 0.283-0.5 0.5v0.5h-2v-0.5c0-1.383 1.117-2.5 2.5-2.5zM11 15h17v2h-17v-2zM4 21h4v1.469l-0.125 0.25-0.406 0.688c0.853 0.398 1.531 1.089 1.531 2.094 0 1.383-1.117 2.5-2.5 2.5h-2.5v-2h2.5c0.217 0 0.5-0.283 0.5-0.5s-0.283-0.5-0.5-0.5h-1.5v-1.375l0.125-0.219 0.25-0.406h-1.375v-2zM11 24h17v2h-17v-2z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 759 B |
5
styleguide/src/system/icons/svg/list-ul.svg
Executable file
5
styleguide/src/system/icons/svg/list-ul.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>list-ul</title>
|
||||
<path d="M4 5h6v6h-6v-6zM6 7v2h2v-2h-2zM12 7h15v2h-15v-2zM4 13h6v6h-6v-6zM6 15v2h2v-2h-2zM12 15h15v2h-15v-2zM4 21h6v6h-6v-6zM6 23v2h2v-2h-2zM12 23h15v2h-15v-2z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 330 B |
5
styleguide/src/system/icons/svg/paragraph.svg
Executable file
5
styleguide/src/system/icons/svg/paragraph.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>paragraph</title>
|
||||
<path d="M12 5h12v2h-2v20h-2v-20h-2v20h-2v-10h-4c-3.302 0-6-2.698-6-6s2.698-6 6-6zM12 7c-2.22 0-4 1.78-4 4s1.78 4 4 4h4v-8h-4z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 299 B |
5
styleguide/src/system/icons/svg/quote-right.svg
Executable file
5
styleguide/src/system/icons/svg/quote-right.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>quote-right</title>
|
||||
<path d="M4 8h10v10c0 3.302-2.698 6-6 6v-2c2.22 0 4-1.78 4-4h-8v-10zM18 8h10v10c0 3.302-2.698 6-6 6v-2c2.22 0 4-1.78 4-4h-8v-10zM6 10v6h6v-6h-6zM20 10v6h6v-6h-6z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 336 B |
274
yarn.lock
274
yarn.lock
@ -41,18 +41,18 @@
|
||||
semver "^5.4.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/core@^7.1.0", "@babel/core@^7.2.2", "@babel/core@~7.3.3":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.3.tgz#d090d157b7c5060d05a05acaebc048bd2b037947"
|
||||
integrity sha512-w445QGI2qd0E0GlSnq6huRZWPMmQGCp5gd5ZWS4hagn0EiwzxD5QMFkpchyusAyVC1n27OKXzQ0/88aVU9n4xQ==
|
||||
"@babel/core@^7.1.0", "@babel/core@^7.2.2", "@babel/core@~7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.3.4.tgz#921a5a13746c21e32445bf0798680e9d11a6530b"
|
||||
integrity sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/generator" "^7.3.3"
|
||||
"@babel/generator" "^7.3.4"
|
||||
"@babel/helpers" "^7.2.0"
|
||||
"@babel/parser" "^7.3.3"
|
||||
"@babel/parser" "^7.3.4"
|
||||
"@babel/template" "^7.2.2"
|
||||
"@babel/traverse" "^7.2.2"
|
||||
"@babel/types" "^7.3.3"
|
||||
"@babel/traverse" "^7.3.4"
|
||||
"@babel/types" "^7.3.4"
|
||||
convert-source-map "^1.1.0"
|
||||
debug "^4.1.0"
|
||||
json5 "^2.1.0"
|
||||
@ -61,12 +61,12 @@
|
||||
semver "^5.4.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.0.0", "@babel/generator@^7.2.2", "@babel/generator@^7.3.3":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.3.tgz#185962ade59a52e00ca2bdfcfd1d58e528d4e39e"
|
||||
integrity sha512-aEADYwRRZjJyMnKN7llGIlircxTCofm3dtV5pmY6ob18MSIuipHpA2yZWkPlycwu5HJcx/pADS3zssd8eY7/6A==
|
||||
"@babel/generator@^7.0.0", "@babel/generator@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e"
|
||||
integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.3.3"
|
||||
"@babel/types" "^7.3.4"
|
||||
jsesc "^2.5.1"
|
||||
lodash "^4.17.11"
|
||||
source-map "^0.5.0"
|
||||
@ -264,10 +264,10 @@
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.2.2", "@babel/parser@^7.2.3", "@babel/parser@^7.3.3":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87"
|
||||
integrity sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg==
|
||||
"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.2.2", "@babel/parser@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c"
|
||||
integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==
|
||||
|
||||
"@babel/plugin-proposal-async-generator-functions@^7.1.0", "@babel/plugin-proposal-async-generator-functions@^7.2.0":
|
||||
version "7.2.0"
|
||||
@ -816,25 +816,25 @@
|
||||
"@babel/parser" "^7.2.2"
|
||||
"@babel/types" "^7.2.2"
|
||||
|
||||
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.2", "@babel/traverse@^7.2.3":
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.2.3.tgz#7ff50cefa9c7c0bd2d81231fdac122f3957748d8"
|
||||
integrity sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==
|
||||
"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.2.3", "@babel/traverse@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06"
|
||||
integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
"@babel/generator" "^7.2.2"
|
||||
"@babel/generator" "^7.3.4"
|
||||
"@babel/helper-function-name" "^7.1.0"
|
||||
"@babel/helper-split-export-declaration" "^7.0.0"
|
||||
"@babel/parser" "^7.2.3"
|
||||
"@babel/types" "^7.2.2"
|
||||
"@babel/parser" "^7.3.4"
|
||||
"@babel/types" "^7.3.4"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.10"
|
||||
lodash "^4.17.11"
|
||||
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
|
||||
version "7.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.3.tgz#6c44d1cdac2a7625b624216657d5bc6c107ab436"
|
||||
integrity sha512-2tACZ80Wg09UnPg5uGAOUvvInaqLk3l/IAhQzlxLQOIXacr6bMsra5SH6AWw/hIDRCSbCdHP2KzSOD+cT7TzMQ==
|
||||
"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.4":
|
||||
version "7.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed"
|
||||
integrity sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
lodash "^4.17.11"
|
||||
@ -4930,6 +4930,13 @@ fastparse@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
|
||||
integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
|
||||
|
||||
fault@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.2.tgz#c3d0fec202f172a3a4d414042ad2bb5e2a3ffbaa"
|
||||
integrity sha512-o2eo/X2syzzERAtN5LcGbiVQ0WwZSlN3qLtadwAz3X8Bu+XWD16dja/KMsjZLiQr+BLGPDnHGkc4yUJf1Xpkpw==
|
||||
dependencies:
|
||||
format "^0.2.2"
|
||||
|
||||
fb-watchman@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
|
||||
@ -5142,6 +5149,11 @@ form-data@~2.3.2:
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
format@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b"
|
||||
integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=
|
||||
|
||||
forwarded@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||
@ -5608,6 +5620,11 @@ hex-color-regex@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
|
||||
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
|
||||
|
||||
highlight.js@~9.13.0:
|
||||
version "9.13.1"
|
||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e"
|
||||
integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==
|
||||
|
||||
hmac-drbg@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
|
||||
@ -7118,6 +7135,13 @@ levn@^0.3.0, levn@~0.3.0:
|
||||
prelude-ls "~1.1.2"
|
||||
type-check "~0.3.2"
|
||||
|
||||
linkify-it@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.1.0.tgz#c4caf38a6cd7ac2212ef3c7d2bde30a91561f9db"
|
||||
integrity sha512-4REs8/062kV2DSHxNfq5183zrqXMl7WP0WzABH9IeJI+NLm429FgE1PDecltYfnOoFDFlZGh2T8PfZn0r+GTRg==
|
||||
dependencies:
|
||||
uc.micro "^1.0.1"
|
||||
|
||||
load-json-file@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
||||
@ -7335,6 +7359,14 @@ lowercase-keys@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
|
||||
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
|
||||
|
||||
lowlight@^1.11.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.11.0.tgz#1304d83005126d4e8b1dc0f07981e9b689ec2efc"
|
||||
integrity sha512-xrGGN6XLL7MbTMdPD6NfWPwY43SNkjf/d0mecSx/CW36fUZTjRHEq0/Cdug3TWKtRXLWi7iMl1eP0olYxj/a4A==
|
||||
dependencies:
|
||||
fault "^1.0.2"
|
||||
highlight.js "~9.13.0"
|
||||
|
||||
lru-cache@^4.0.1, lru-cache@^4.1.2, lru-cache@^4.1.3:
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
|
||||
@ -8222,6 +8254,11 @@ ora@^3.0.0:
|
||||
strip-ansi "^5.0.0"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
orderedmap@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-1.0.0.tgz#d90fc2ba1ed085190907d601dec6e6a53f8d41ba"
|
||||
integrity sha1-2Q/Cuh7QhRkJB9YB3sbmpT+NQbo=
|
||||
|
||||
os-browserify@^0.3.0, os-browserify@~0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
|
||||
@ -9317,6 +9354,114 @@ prompts@^2.0.1:
|
||||
kleur "^3.0.2"
|
||||
sisteransi "^1.0.0"
|
||||
|
||||
prosemirror-commands@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.0.7.tgz#e5a2ba821e29ea7065c88277fe2c3d7f6b0b9d37"
|
||||
integrity sha512-IR8yMSdw7XlKuF68tydAak1J9P/lLD5ohsrL7pzoLsJAJAQU7mVPDXtGbQrrm0mesddFjcc1zNo/cJQN3lRYnA==
|
||||
dependencies:
|
||||
prosemirror-model "^1.0.0"
|
||||
prosemirror-state "^1.0.0"
|
||||
prosemirror-transform "^1.0.0"
|
||||
|
||||
prosemirror-dropcursor@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.1.1.tgz#c60ed1ed6c58804a06a75db06a0d993b087b7622"
|
||||
integrity sha512-GeUyMO/tOEf8MXrP7Xb7UIMrfK86OGh0fnyBrHfhav4VjY9cw65mNoqHy87CklE5711AhCP5Qzfp8RL/hVKusg==
|
||||
dependencies:
|
||||
prosemirror-state "^1.0.0"
|
||||
prosemirror-transform "^1.1.0"
|
||||
prosemirror-view "^1.1.0"
|
||||
|
||||
prosemirror-gapcursor@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.3.tgz#acc6537fc5a35e9b38966f91a199a382dfc715c4"
|
||||
integrity sha512-X+hJhr42PcHWiSWL+lI5f/UeOhXCxlBFb8M6O8aG1hssmaRrW7sS2/Fjg5jFV+pTdS1REFkmm1occh01FMdDIQ==
|
||||
dependencies:
|
||||
prosemirror-keymap "^1.0.0"
|
||||
prosemirror-model "^1.0.0"
|
||||
prosemirror-state "^1.0.0"
|
||||
prosemirror-view "^1.0.0"
|
||||
|
||||
prosemirror-history@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.0.3.tgz#5fb8591adfc272afaaf0b41bec64ee7d9522a118"
|
||||
integrity sha512-IfFGbhafSx+R3aq7nLJGkXeu2iaUiP8mkU3aRu2uQcIIjU8Fq7RJfuvhIOJ2RNUoSyqF/ANkdTjnZ74F5eHs1Q==
|
||||
dependencies:
|
||||
prosemirror-state "^1.2.2"
|
||||
prosemirror-transform "^1.0.0"
|
||||
rope-sequence "^1.2.0"
|
||||
|
||||
prosemirror-inputrules@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.0.1.tgz#f63305fd966379f218e82ca76a2a9b328b66dc7b"
|
||||
integrity sha512-UHy22NmwxS5WIMQYkzraDttQAF8mpP82FfbJsmKFfx6jwkR/SZa+ZhbkLY0zKQ5fBdJN7euj36JG/B5iAlrpxA==
|
||||
dependencies:
|
||||
prosemirror-state "^1.0.0"
|
||||
prosemirror-transform "^1.0.0"
|
||||
|
||||
prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.0.1.tgz#03ef32b828e3a859dfb570eb84928bf2e5330bc2"
|
||||
integrity sha512-e79ApE7PXXZMFtPz7WbjycjAFd1NPjgY1MkecVz98tqwlBSggXWXYQnWFk6x7UkmnBYRHHbXHkR/RXmu2wyBJg==
|
||||
dependencies:
|
||||
prosemirror-state "^1.0.0"
|
||||
w3c-keyname "^1.1.8"
|
||||
|
||||
prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.7.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.7.0.tgz#1fde0fd7cb2f9ead0be1581ad9f04593002a65aa"
|
||||
integrity sha512-/6ul6guiqyAl5I+0qbnL7SlmuX0DEfYqjvzeLUVEnb7nwF/vmKZuWqbjEG2tqi/9SSudvd3UxQTBDHvxy9hQwA==
|
||||
dependencies:
|
||||
orderedmap "^1.0.0"
|
||||
|
||||
prosemirror-schema-list@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.0.2.tgz#8381fb0c1eaf439d848059f62e2fac517033c2ef"
|
||||
integrity sha512-IJ4DEpUEymfO+NNA4DAgCMF39XiQqpmCoPYY3SXa1jYcVgObGpGfJlSjZYVFEpimoLI7/mLoOLDhCtpGCRhTfg==
|
||||
dependencies:
|
||||
prosemirror-model "^1.0.0"
|
||||
prosemirror-transform "^1.0.0"
|
||||
|
||||
prosemirror-state@^1.0.0, prosemirror-state@^1.2.1, prosemirror-state@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.2.2.tgz#8df26d95fd6fd327c0f9984a760e84d863204154"
|
||||
integrity sha512-j8aC/kf9BJSCQau485I/9pj39XQoce+TqH5xzekT7WWFARTsRYFLJtiXBcCKakv1VSeev+sC3bJP0pLfz7Ft8g==
|
||||
dependencies:
|
||||
prosemirror-model "^1.0.0"
|
||||
prosemirror-transform "^1.0.0"
|
||||
|
||||
prosemirror-tables@^0.7.10, prosemirror-tables@^0.7.9:
|
||||
version "0.7.10"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-0.7.10.tgz#4b0f623422b4b8f84cdc9c559f8a87579846b3ba"
|
||||
integrity sha512-VIu7UGS9keYEHs0Y6AEOTGbNE9QI2rL1OKng4vV6yoTshW/lYcb+s3hGXI12i+WLMjDVm7ujhfdWrpKpvFZOkQ==
|
||||
dependencies:
|
||||
prosemirror-keymap "^1.0.0"
|
||||
prosemirror-model "^1.0.0"
|
||||
prosemirror-state "^1.0.0"
|
||||
prosemirror-transform "^1.0.0"
|
||||
prosemirror-view "^1.0.0"
|
||||
|
||||
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.1.3.tgz#28cfdf1f9ee514edc40466be7b7db39eed545fdf"
|
||||
integrity sha512-1O6Di5lOL1mp4nuCnQNkHY7l2roIW5y8RH4ZG3hMYmkmDEWzTaFFnxxAAHsE5ipGLBSRcTlP7SsDhYBIdSuLpQ==
|
||||
dependencies:
|
||||
prosemirror-model "^1.0.0"
|
||||
|
||||
prosemirror-utils@^0.7.5:
|
||||
version "0.7.6"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-utils/-/prosemirror-utils-0.7.6.tgz#c462ddfbf2452e56e4b25d1f02b34caccddb0f33"
|
||||
integrity sha512-vzsCBTiJ56R3nRDpIJnKOJzsZP7KFO8BkXk7zvQgQiXpml2o/djPCRhuyaFc7VTqSHlLPQHVI1feTLAwHp+prQ==
|
||||
|
||||
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.7.1:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.7.1.tgz#f0ea75faa6d7bd25ea22897dd5bae35708c59a28"
|
||||
integrity sha512-UFY/h4i5H1Yen8u2ZTve0WL+nh/y1qU3geC3SrWl5yIKSgGbvllD5vr5LxmeRgVsY8hb+oDXRHk5KvLwqmu7Lg==
|
||||
dependencies:
|
||||
prosemirror-model "^1.1.0"
|
||||
prosemirror-state "^1.0.0"
|
||||
prosemirror-transform "^1.1.0"
|
||||
|
||||
proto-list@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
|
||||
@ -9889,6 +10034,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
||||
hash-base "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
|
||||
rope-sequence@^1.2.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.2.2.tgz#49c4e5c2f54a48e990b050926771e2871bcb31ce"
|
||||
integrity sha1-ScTlwvVKSOmQsFCSZ3HihxvLMc4=
|
||||
|
||||
rsvp@^3.3.3:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a"
|
||||
@ -10508,6 +10658,11 @@ string-argv@0.0.2:
|
||||
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736"
|
||||
integrity sha1-2sMECGkMIfPDYwo/86BYd73L1zY=
|
||||
|
||||
string-hash@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
|
||||
integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=
|
||||
|
||||
string-length@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed"
|
||||
@ -10890,6 +11045,57 @@ timsort@^0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
|
||||
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
|
||||
|
||||
tiptap-commands@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.6.0.tgz#567b7b218bd7d1c1214534a2007acbb7b8d06688"
|
||||
integrity sha512-9HO8UYJz1qGyqsHn0+PifmndlRTInqfcb7vjNDvqWQA2P7r8koJqrP8CYMR0DXQHlys1druJnaBaOzLa1d5PQQ==
|
||||
dependencies:
|
||||
prosemirror-commands "^1.0.7"
|
||||
prosemirror-inputrules "^1.0.1"
|
||||
prosemirror-schema-list "^1.0.2"
|
||||
prosemirror-state "^1.2.2"
|
||||
tiptap-utils "^1.2.0"
|
||||
|
||||
tiptap-extensions@^1.13.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/tiptap-extensions/-/tiptap-extensions-1.13.0.tgz#1c78223d68f4c321909c5448764d2b5a32bad7f3"
|
||||
integrity sha512-56y5uXAnkdZ/9MmTuk2fmbglUwmfECVOz2DZh/5OI5nsPclVNk+OFjNFEbZ91rb3fC4NOtFdfNQVKyqrBe9pNA==
|
||||
dependencies:
|
||||
lowlight "^1.11.0"
|
||||
prosemirror-history "^1.0.3"
|
||||
prosemirror-state "^1.2.2"
|
||||
prosemirror-tables "^0.7.10"
|
||||
prosemirror-utils "^0.7.5"
|
||||
prosemirror-view "^1.7.1"
|
||||
tiptap "^1.13.0"
|
||||
tiptap-commands "^1.6.0"
|
||||
|
||||
tiptap-utils@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.2.0.tgz#e1e566af1212acff6b2e3c4ca6edc21ebf306440"
|
||||
integrity sha512-p8Q0UfNhYHXqMDSwvCc6x0Vm95AYgM/f1V+8oNu9FI0aRWwXpTwIJj+1CAGO1mb6NFUSxn9HcZaUvEcBKR5WzQ==
|
||||
dependencies:
|
||||
prosemirror-model "^1.7.0"
|
||||
prosemirror-state "^1.2.2"
|
||||
prosemirror-tables "^0.7.9"
|
||||
prosemirror-utils "^0.7.5"
|
||||
|
||||
tiptap@^1.13.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/tiptap/-/tiptap-1.13.0.tgz#52b086fc8d4df7534123d31571366dd90ee62a23"
|
||||
integrity sha512-kwzgtOY5PnbSfzMyNPFchI/Cyi1O3kFNiRP7K4p6t0zcNCXy9EaWgaM/U2bKArI0/HxG/GSPM6RTTCCOF3I6EA==
|
||||
dependencies:
|
||||
prosemirror-commands "^1.0.7"
|
||||
prosemirror-dropcursor "^1.1.1"
|
||||
prosemirror-gapcursor "^1.0.3"
|
||||
prosemirror-inputrules "^1.0.1"
|
||||
prosemirror-keymap "^1.0.1"
|
||||
prosemirror-model "^1.7.0"
|
||||
prosemirror-state "^1.2.1"
|
||||
prosemirror-view "^1.7.1"
|
||||
tiptap-commands "^1.6.0"
|
||||
tiptap-utils "^1.2.0"
|
||||
|
||||
title-case@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"
|
||||
@ -11100,6 +11306,11 @@ ua-parser-js@^0.7.19:
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.19.tgz#94151be4c0a7fb1d001af7022fdaca4642659e4b"
|
||||
integrity sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==
|
||||
|
||||
uc.micro@^1.0.1:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
||||
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
||||
|
||||
uglify-js@3.4.x, uglify-js@^3.1.4:
|
||||
version "3.4.9"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
|
||||
@ -11581,6 +11792,11 @@ w3c-hr-time@^1.0.1:
|
||||
dependencies:
|
||||
browser-process-hrtime "^0.1.2"
|
||||
|
||||
w3c-keyname@^1.1.8:
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-1.1.8.tgz#4e2219663760fd6535b7a1550f1552d71fc9372c"
|
||||
integrity sha512-2HAdug8GTiu3b4NYhssdtY8PXRue3ICnh1IlxvZYl+hiINRq0GfNWei3XOPDg8L0PsxbmYjWVLuLj6BMRR/9vA==
|
||||
|
||||
walker@~1.0.5:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user