Meld a chaotic commit history into one commit

Some important commit messages:

```
    Fix youtu.be not being embedded

    And also try to maintain the old behaviour matching
    `provider.provider_url`.
```

```
    Remove confusing code comments and obsolete code

    I discovered that the behaviour of no duplicate notifications being send
    out is caused by the frontend: When the editor reads html from the
    backend, it will parse hashtags and mentions as ordinary links, not as
    their respective nodes during editing. Also, we don't have to worry
    about duplicate ids being found: The cypher statement will implicitly
    suppress duplicate notification nodes for the same user.

    So let's remove the code to avoid confusing the next developer.
```

```
    Test editor.getHTML()

    I do this because I'm not able to test the content of `this.editor` from
    a wrapper of `vue-test-utils`. If I call `this.editor.getHTML` directly
    and use it as a computed property `renderedContent` to populate a `<div
    v-html="renderedContent" />` this will not work for the embeds. So, my
    current best bet is to test the editor object isolated from a real
    component. ;(
```

```
    Add core-js as explicit dependency

    Because of build errors on Travis.

    See: https://stackoverflow.com/a/55313456

    Remove as soon as this issue is resolved:
    https://github.com/storybookjs/storybook/issues/7591

```

```
    Refactor: Keep Runtime-only builds

    See: https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
```
This commit is contained in:
Robert Schäfer 2019-08-01 00:12:20 +02:00
parent 34f86c95a0
commit 72edf78889
33 changed files with 710 additions and 504 deletions

View File

@ -86,6 +86,7 @@
"metascraper-url": "^5.5.0",
"metascraper-video": "^5.6.3",
"metascraper-youtube": "^4.8.5",
"minimatch": "^3.0.4",
"neo4j-driver": "~1.7.4",
"neo4j-graphql-js": "^2.6.3",
"neode": "^0.2.16",

View File

@ -64,7 +64,7 @@ describe('currentUser { notifications }', () => {
let post
const title = 'Mentioning Al Capone'
const content =
'Hey <a class="mention" href="/profile/you/al-capone">@al-capone</a> how do you do?'
'Hey <a class="mention" data-mention-id="you" href="/profile/you/al-capone">@al-capone</a> how do you do?'
beforeEach(async () => {
const createPostMutation = gql`
@ -88,7 +88,7 @@ describe('currentUser { notifications }', () => {
it('sends you a notification', async () => {
const expectedContent =
'Hey <a href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?'
'Hey <a class="mention" data-mention-id="you" href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do?'
const expected = {
currentUser: {
notifications: [
@ -108,14 +108,22 @@ describe('currentUser { notifications }', () => {
).resolves.toEqual(expected)
})
describe('who mentions me again', () => {
describe('who mentions me many times', () => {
beforeEach(async () => {
const updatedContent = `${post.content} One more mention to <a href="/profile/you" class="mention">@al-capone</a>`
// The response `post.content` contains a link but the XSSmiddleware
// should have the `mention` CSS class removed. I discovered this
// during development and thought: A feature not a bug! This way we
// can encode a re-mentioning of users when you edit your post or
// comment.
const updatedContent = `
One more mention to
<a data-mention-id="you" class="mention" href="/profile/you">
@al-capone
</a>
and again:
<a data-mention-id="you" class="mention" href="/profile/you">
@al-capone
</a>
and again
<a data-mention-id="you" class="mention" href="/profile/you">
@al-capone
</a>
`
const updatePostMutation = gql`
mutation($id: ID!, $title: String!, $content: String!) {
UpdatePost(id: $id, content: $content, title: $title) {
@ -136,7 +144,7 @@ describe('currentUser { notifications }', () => {
it('creates exactly one more notification', async () => {
const expectedContent =
'Hey <a href="/profile/you/al-capone" target="_blank">@al-capone</a> how do you do? One more mention to <a href="/profile/you" target="_blank">@al-capone</a>'
'<br>One more mention to<br><a data-mention-id="you" class="mention" href="/profile/you" target="_blank"><br>@al-capone<br></a><br>and again:<br><a data-mention-id="you" class="mention" href="/profile/you" target="_blank"><br>@al-capone<br></a><br>and again<br><a data-mention-id="you" class="mention" href="/profile/you" target="_blank"><br>@al-capone<br></a><br>'
const expected = {
currentUser: {
notifications: [

View File

@ -1,20 +1,13 @@
import cheerio from 'cheerio'
const ID_REGEX = /\/profile\/([\w\-.!~*'"(),]+)/g
export default function(content) {
if (!content) return []
const $ = cheerio.load(content)
const urls = $('.mention')
let userIds = $('a.mention[data-mention-id]')
.map((_, el) => {
return $(el).attr('href')
return $(el).attr('data-mention-id')
})
.get()
const ids = []
urls.forEach(url => {
let match
while ((match = ID_REGEX.exec(url)) != null) {
ids.push(match[1])
}
})
return ids
userIds = userIds.map(id => id.trim()).filter(id => !!id)
return userIds
}

View File

@ -1,5 +1,12 @@
import extractMentionedUsers from './extractMentionedUsers'
const contentWithMentions =
'<p>Something inspirational about <a href="/profile/u2" class="not-a-mention" data-mention-id="bobs-id" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" data-mention-id="u3" target="_blank">@jenny-rostock</a>.</p>'
const contentEmptyMentions =
'<p>Something inspirational about <a href="/profile/u2" data-mention-id="" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" data-mention-id target="_blank">@jenny-rostock</a>.</p>'
const contentWithLinks =
'<p>Something inspirational about <a class="mention" href="/profile/u2" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3" target="_blank">@jenny-rostock</a>.</p>'
describe('extractMentionedUsers', () => {
describe('content undefined', () => {
it('returns empty array', () => {
@ -7,53 +14,17 @@ describe('extractMentionedUsers', () => {
})
})
describe('searches through links', () => {
it('ignores links without .mention class', () => {
const content =
'<p>Something inspirational about <a href="/profile/u2" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3" target="_blank">@jenny-rostock</a>.</p>'
expect(extractMentionedUsers(content)).toEqual([])
it('ignores links without .mention class', () => {
expect(extractMentionedUsers(contentWithLinks)).toEqual([])
})
describe('given a link with .mention class and `data-mention-id` attribute ', () => {
it('extracts ids', () => {
expect(extractMentionedUsers(contentWithMentions)).toEqual(['u3'])
})
describe('given a link with .mention class', () => {
it('extracts ids', () => {
const content =
'<p>Something inspirational about <a href="/profile/u2" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock" class="mention" target="_blank">@jenny-rostock</a>.</p>'
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
})
describe('handles links', () => {
it('with slug and id', () => {
const content =
'<p>Something inspirational about <a href="/profile/u2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/u3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
})
it('with domains', () => {
const content =
'<p>Something inspirational about <a href="http://localhost:3000/profile/u2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="http://localhost:3000//profile/u3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
expect(extractMentionedUsers(content)).toEqual(['u2', 'u3'])
})
it('special characters', () => {
const content =
'<p>Something inspirational about <a href="http://localhost:3000/profile/u!*(),2/bob-der-baumeister" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="http://localhost:3000//profile/u.~-3/jenny-rostock/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
expect(extractMentionedUsers(content)).toEqual(['u!*(),2', 'u.~-3'])
})
})
describe('does not crash if', () => {
it('`href` contains no user id', () => {
const content =
'<p>Something inspirational about <a href="/profile" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="/profile/" class="mention" target="_blank">@jenny-rostock</a>.</p>'
expect(extractMentionedUsers(content)).toEqual([])
})
it('`href` is empty or invalid', () => {
const content =
'<p>Something inspirational about <a href="" class="mention" target="_blank">@bob-der-baumeister</a> and <a href="not-a-url" class="mention" target="_blank">@jenny-rostock</a>.</p>'
expect(extractMentionedUsers(content)).toEqual([])
})
})
it('ignores empty `data-mention-id` attributes', () => {
expect(extractMentionedUsers(contentEmptyMentions)).toEqual([])
})
})
})

View File

@ -2,30 +2,17 @@ import walkRecursive from '../helpers/walkRecursive'
// import { getByDot, setByDot, getItems, replaceItems } from 'feathers-hooks-common'
import sanitizeHtml from 'sanitize-html'
// import { isEmpty, intersection } from 'lodash'
import cheerio from 'cheerio'
import linkifyHtml from 'linkifyjs/html'
const embedToAnchor = content => {
const $ = cheerio.load(content)
$('div[data-url-embed]').each((i, el) => {
let url = el.attribs['data-url-embed']
let aTag = $(`<a href="${url}" target="_blank" data-url-embed="">${url}</a>`)
$(el).replaceWith(aTag)
})
return $('body').html()
}
function clean(dirty) {
if (!dirty) {
return dirty
}
// Convert embeds to a-tags
dirty = embedToAnchor(dirty)
dirty = linkifyHtml(dirty)
dirty = sanitizeHtml(dirty, {
allowedTags: [
'iframe',
'img',
'p',
'h3',
@ -50,35 +37,24 @@ function clean(dirty) {
a: ['href', 'class', 'target', 'data-*', 'contenteditable'],
span: ['contenteditable', 'class', 'data-*'],
img: ['src'],
iframe: ['src', 'class', 'frameborder', 'allowfullscreen'],
},
allowedIframeHostnames: ['www.youtube.com', 'player.vimeo.com'],
parser: {
lowerCaseTags: true,
},
transformTags: {
iframe: function(tagName, attribs) {
return {
tagName: 'a',
text: attribs.src,
attribs: {
href: attribs.src,
target: '_blank',
'data-url-embed': '',
},
}
},
h1: 'h3',
h2: 'h3',
h3: 'h3',
h4: 'h4',
h5: 'strong',
i: 'em',
a: function(tagName, attribs) {
a: (tagName, attribs) => {
return {
tagName: 'a',
attribs: {
href: attribs.href,
...attribs,
href: attribs.href || '',
target: '_blank',
rel: 'noopener noreferrer nofollow',
},
@ -86,33 +62,6 @@ function clean(dirty) {
},
b: 'strong',
s: 'strike',
img: function(tagName, attribs) {
let src = attribs.src
if (!src) {
// remove broken images
return {}
}
// if (isEmpty(hook.result)) {
// const config = hook.app.get('thumbor')
// if (config && src.indexOf(config < 0)) {
// // download image
// // const ThumborUrlHelper = require('../helper/thumbor-helper')
// // const Thumbor = new ThumborUrlHelper(config.key || null, config.url || null)
// // src = Thumbor
// // .setImagePath(src)
// // .buildUrl('740x0')
// }
// }
return {
tagName: 'img',
attribs: {
// TODO: use environment variables
src: `http://localhost:3050/images?url=${src}`,
},
}
},
},
})
@ -120,8 +69,6 @@ function clean(dirty) {
dirty = dirty
// 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')
@ -144,8 +91,7 @@ const fields = ['content', 'contentExcerpt']
export default {
Mutation: async (resolve, root, args, context, info) => {
args = walkRecursive(args, fields, clean)
const result = await resolve(root, args, context, info)
return result
return resolve(root, args, context, info)
},
Query: async (resolve, root, args, context, info) => {
const result = await resolve(root, args, context, info)

View File

@ -0,0 +1,26 @@
import fs from 'fs'
import path from 'path'
import minimatch from 'minimatch'
let oEmbedProvidersFile = fs.readFileSync(path.join(__dirname, './providers.json'), 'utf8')
// some providers allow a format parameter
// we need JSON
oEmbedProvidersFile = oEmbedProvidersFile.replace(/\{format\}/g, 'json')
const oEmbedProviders = JSON.parse(oEmbedProvidersFile)
export default function(embedUrl) {
for (let provider of oEmbedProviders) {
for (let endpoint of provider.endpoints) {
const { schemes = [], url } = endpoint
if (schemes.some(scheme => minimatch(embedUrl, scheme))) return url
}
const { hostname } = new URL(embedUrl)
if (provider.provider_url.includes(hostname)) {
const {
endpoints: [{ url }],
} = provider
return url
}
}
return null
}

View File

@ -0,0 +1,35 @@
import findProvider from './findProvider'
describe('Vimeo', () => {
it('matches `https://vimeo.com/showcase/2098620/video/4082288`', () => {
expect(findProvider('https://vimeo.com/showcase/2098620/video/4082288')).toEqual(
'https://vimeo.com/api/oembed.json',
)
})
})
describe('RiffReporter', () => {
it('matches `https://www.riffreporter.de/flugbegleiter-koralle/`', () => {
expect(findProvider('https://www.riffreporter.de/flugbegleiter-koralle/')).toEqual(
'https://www.riffreporter.de/service/oembed',
)
})
})
describe('Youtube', () => {
it('matches `https://www.youtube.com/watch?v=qkdXAtO40Fo`', () => {
expect(findProvider('https://www.youtube.com/watch?v=qkdXAtO40Fo')).toEqual(
'https://www.youtube.com/oembed',
)
})
it('matches `https://youtu.be/qkdXAtO40Fo`', () => {
expect(findProvider(`https://youtu.be/qkdXAtO40Fo`)).toEqual('https://www.youtube.com/oembed')
})
it('matches `https://youtu.be/qkdXAtO40Fo?t=41`', () => {
expect(findProvider(`https://youtu.be/qkdXAtO40Fo?t=41`)).toEqual(
'https://www.youtube.com/oembed',
)
})
})

View File

@ -1,12 +1,11 @@
import Metascraper from 'metascraper'
import fetch from 'node-fetch'
import fs from 'fs'
import path from 'path'
import { ApolloError } from 'apollo-server'
import isEmpty from 'lodash/isEmpty'
import isArray from 'lodash/isArray'
import mergeWith from 'lodash/mergeWith'
import findProvider from './findProvider'
const error = require('debug')('embed:error')
@ -30,24 +29,11 @@ const metascraper = Metascraper([
// require('./rules/metascraper-embed')()
])
let oEmbedProvidersFile = fs.readFileSync(path.join(__dirname, './providers.json'), 'utf8')
// some providers allow a format parameter
// we need JSON
oEmbedProvidersFile = oEmbedProvidersFile.replace('{format}', 'json')
const oEmbedProviders = JSON.parse(oEmbedProvidersFile)
const fetchEmbed = async url => {
const provider = oEmbedProviders.find(provider => {
return provider.provider_url.includes(url.hostname)
})
if (!provider) return {}
const {
endpoints: [endpoint],
} = provider
const endpointUrl = new URL(endpoint.url)
endpointUrl.searchParams.append('url', url.href)
let endpointUrl = findProvider(url)
if (!endpointUrl) return {}
endpointUrl = new URL(endpointUrl)
endpointUrl.searchParams.append('url', url)
endpointUrl.searchParams.append('format', 'json')
let json
try {
@ -70,7 +56,7 @@ const fetchEmbed = async url => {
const fetchResource = async url => {
const response = await fetch(url)
const html = await response.text()
const resource = await metascraper({ html, url: url.href })
const resource = await metascraper({ html, url })
return {
sources: ['resource'],
...resource,
@ -78,12 +64,6 @@ const fetchResource = async url => {
}
export default async function scrape(url) {
url = new URL(url)
if (url.hostname === 'youtu.be') {
// replace youtu.be to get proper results
url.hostname = 'youtube.com'
}
const [meta, embed] = await Promise.all([fetchResource(url), fetchEmbed(url)])
const output = mergeWith(meta, embed, (objValue, srcValue) => {
if (isArray(objValue)) {

View File

@ -7,4 +7,4 @@ type Tag {
taggedCountUnique: Int! @cypher(statement: "MATCH (this)<-[:TAGGED]-(p)<-[:WROTE]-(u:User) RETURN COUNT(DISTINCT u)")
deleted: Boolean
disabled: Boolean
}
}

View File

@ -230,7 +230,7 @@ When("I choose {string} as the title of the post", title => {
When("I type in the following text:", text => {
lastPost.content = text.replace("\n", " ");
cy.get(".ProseMirror").type(lastPost.content);
cy.get(".editor .ProseMirror").type(lastPost.content);
});
Then("the post shows up on the landing page at position {int}", index => {

View File

@ -45,7 +45,11 @@
{{ $t('comment.show.more') }}
</a>
</div>
<div v-if="!isCollapsed" v-html="comment.content" style="padding-left: 40px;" />
<content-viewer
v-if="!isCollapsed"
:content="comment.content"
style="padding-left: 40px;"
/>
<div style="text-align: right; margin-right: 20px; margin-top: -12px;">
<a v-if="!isCollapsed" @click="isCollapsed = !isCollapsed" style="padding-left: 40px; ">
{{ $t('comment.show.less') }}
@ -62,6 +66,7 @@ import gql from 'graphql-tag'
import { mapGetters, mapMutations } from 'vuex'
import HcUser from '~/components/User'
import ContentMenu from '~/components/ContentMenu'
import ContentViewer from '~/components/Editor/ContentViewer'
import HcEditCommentForm from '~/components/comments/EditCommentForm/EditCommentForm'
export default {
@ -74,6 +79,7 @@ export default {
components: {
HcUser,
ContentMenu,
ContentViewer,
HcEditCommentForm,
},
props: {

View File

@ -0,0 +1,32 @@
<template>
<editor-content :editor="editor" />
</template>
<script>
import defaultExtensions from './defaultExtensions.js'
import { Editor, EditorContent } from 'tiptap'
export default {
name: 'ContentViewer',
components: {
EditorContent,
},
props: {
content: { type: String, default: '' },
doc: { type: Object, default: () => {} },
},
data() {
return {
editor: new Editor({
doc: this.doc,
content: this.content,
editable: false,
extensions: defaultExtensions(this),
}),
}
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>

View File

@ -1,9 +1,27 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import HcEditor from '~/components/Editor/Editor.vue'
import helpers from './helpers'
import helpers from '~/storybook/helpers'
import Vue from 'vue'
helpers.init()
const embed = {
html:
'<iframe width="480" height="270" src="https://www.youtube.com/embed/qkdXAtO40Fo?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>',
}
const plugins = [
(app = {}) => {
app.$apollo = {
mutate: () => {},
query: () => {
return { data: { embed } }
},
}
Vue.prototype.$apollo = app.$apollo
return app
},
]
helpers.init({ plugins })
const users = [{ id: 1, slug: 'peter' }, { id: 1, slug: 'sandra' }, { id: 1, slug: 'jane' }]
@ -47,7 +65,7 @@ storiesOf('Editor', module)
<p>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
<h5>Heading 5</h5>
<p>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
<h3>Unordered List</h3>
<ul>
<li><p>Also some list</p></li>
@ -55,7 +73,7 @@ storiesOf('Editor', module)
<li><p>several</p></li>
<li><p>points</p></li>
</ul>
<h3>Ordered List</h3>
<ol>
<li><p>justo</p></li>
@ -74,7 +92,7 @@ storiesOf('Editor', module)
users,
content: `
<p>
Here you can mention people like
Here you can mention people like
<a class="mention" href="/profile/1" target="_blank" contenteditable="false">@sandra</a> and others.
Try it out!
</p>
@ -102,9 +120,12 @@ storiesOf('Editor', module)
data: () => ({
users,
content: `
<p>The following link should be rendered with metainformation for its destination such as: Title, Description, Image, Pagename and Favicon.</p>
<a class="embed" href="https://human-connection.org">Human Connection</a>
<p>At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
<p>
The following link should render a youtube video in addition to the link.
</p>
<a class="embed" href="https://www.youtube.com/watch?v=qkdXAtO40Fo">
<em>https://www.youtube.com/watch?v=qkdXAtO40Fo</em>
</a>
`,
}),
template: `<hc-editor :users="users" :value="content" />`,

View File

@ -183,32 +183,16 @@
</template>
<script>
import defaultExtensions from './defaultExtensions.js'
import linkify from 'linkify-it'
import stringHash from 'string-hash'
import Fuse from 'fuse.js'
import tippy from 'tippy.js'
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'
import Mention from './nodes/Mention.js'
import Embed from './nodes/Embed.js'
import Link from './nodes/Link.js'
import { History } from 'tiptap-extensions'
import Hashtag from './nodes/Hashtag.js'
import Mention from './nodes/Mention.js'
import { mapGetters } from 'vuex'
let throttleInputEvent
@ -232,25 +216,8 @@ export default {
content: this.value || '',
doc: this.doc,
extensions: [
...defaultExtensions(this),
new EventHandler(),
new Heading(),
new HardBreak(),
new Blockquote(),
new BulletList(),
new OrderedList(),
new HorizontalRule(),
new Bold(),
new Italic(),
new Strike(),
new Underline(),
new Embed(),
new Link(),
new Heading({ levels: [3, 4] }),
new ListItem(),
new Placeholder({
emptyNodeClass: 'is-empty',
emptyNodeText: this.placeholder || this.$t('editor.placeholder'),
}),
new History(),
new Mention({
// a list of all suggested items
@ -496,13 +463,11 @@ export default {
selectItem(item) {
const typeAttrs = {
mention: {
// TODO: use router here
url: `/profile/${item.id}`,
id: item.id,
label: item.slug,
},
hashtag: {
// TODO: Fill up with input hashtag in search field
url: `/search/hashtag/${item.name}`,
id: item.name,
label: item.name,
},
}

View File

@ -0,0 +1,49 @@
import { Plugin } from 'prosemirror-state'
import { Slice, Fragment } from 'prosemirror-model'
export default function(regexp, type, getAttrs) {
const handler = fragment => {
const nodes = []
fragment.forEach(child => {
if (child.isText) {
const { text } = child
let pos = 0
let match
do {
match = regexp.exec(text)
if (match) {
const start = match.index
const end = start + match[0].length
const attrs = getAttrs instanceof Function ? getAttrs(match[0]) : getAttrs
if (start > 0) {
nodes.push(child.cut(pos, start))
}
// only difference to `pasteRule` of `tiptap-commands`:
// we replace the node instead of adding markup
nodes.push(type.create(attrs, child.cut(start, end)))
pos = end
}
} while (match)
if (pos < text.length) {
nodes.push(child.cut(pos))
}
} else {
nodes.push(child.copy(handler(child.content)))
}
})
return Fragment.fromArray(nodes)
}
return new Plugin({
props: {
transformPasted: slice => new Slice(handler(slice.content), slice.openStart, slice.openEnd),
},
})
}

View File

@ -0,0 +1,48 @@
import Embed from '~/components/Editor/nodes/Embed.js'
import Link from '~/components/Editor/nodes/Link.js'
import EmbedQuery from '~/graphql/EmbedQuery.js'
import {
Heading,
HardBreak,
Blockquote,
ListItem,
BulletList,
OrderedList,
HorizontalRule,
Placeholder,
Bold,
Italic,
Strike,
Underline,
} from 'tiptap-extensions'
export default function defaultExtensions(component) {
const { placeholder, $t, $apollo } = component
return [
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: placeholder || $t('editor.placeholder'),
}),
new Embed({
onEmbed: async ({ url }) => {
const {
data: { embed },
} = await $apollo.query({ query: EmbedQuery(), variables: { url } })
return embed
},
}),
]
}

View File

@ -0,0 +1,88 @@
import defaultExtensions from './defaultExtensions.js'
import { Editor } from 'tiptap'
let content
let createEditor
describe('defaultExtensions', () => {
describe('editor', () => {
createEditor = () => {
const componentStub = {
placeholder: 'placeholder',
$t: jest.fn(),
$apollo: {
mutate: jest.fn(),
},
}
return new Editor({
content,
extensions: [...defaultExtensions(componentStub)],
})
}
})
it('renders', () => {
content = ''
expect(createEditor().getHTML()).toEqual('<p></p>')
})
describe('`content` contains a mentioning', () => {
beforeEach(() => {
content =
'<p>This is a post content mentioning <a class="mention" href="/profile/f0628376-e692-4167-bdb4-d521de5a014f" target="_blank">@alicia-luettgen</a>.</p>'
})
it('renders mentioning as link', () => {
const editor = createEditor()
const expected =
'<p>This is a post content mentioning <a href="/profile/f0628376-e692-4167-bdb4-d521de5a014f" rel="noopener noreferrer nofollow">@alicia-luettgen</a>.</p>'
expect(editor.getHTML()).toEqual(expected)
})
})
describe('`content` contains a hashtag', () => {
beforeEach(() => {
content =
'<p>This is a post content with a hashtag <a class="hashtag" href="/search/hashtag/metoo" target="_blank">#metoo</a>.</p>'
})
it('renders hashtag as link', () => {
const editor = createEditor()
const expected =
'<p>This is a post content with a hashtag <a href="/search/hashtag/metoo" rel="noopener noreferrer nofollow">#metoo</a>.</p>'
expect(editor.getHTML()).toEqual(expected)
})
})
describe('`content` contains embed code', () => {
beforeEach(() => {
content =
'<p>Baby loves cat: </p><a href="https://www.youtube.com/watch?v=qkdXAtO40Fo" class="embed" target="_blank"></a>'
})
it('recognizes embed code', () => {
const editor = createEditor()
const expected = {
content: [
{
content: [
{
text: 'Baby loves cat:',
type: 'text',
},
],
type: 'paragraph',
},
{
attrs: {
dataEmbedUrl: 'https://www.youtube.com/watch?v=qkdXAtO40Fo',
},
type: 'embed',
},
],
type: 'doc',
}
expect(editor.getJSON()).toEqual(expected)
})
})
})

View File

@ -1,14 +1,40 @@
import { Node } from 'tiptap'
import pasteRule from '../commands/pasteRule'
import { compileToFunctions } from 'vue-template-compiler'
const template = `
<a class="embed" :href="dataEmbedUrl" rel="noopener noreferrer nofollow">
<div v-if="embedHtml" v-html="embedHtml" />
<em> {{ dataEmbedUrl }} </em>
</a>
`
const compiledTemplate = compileToFunctions(template)
export default class Embed extends Node {
get name() {
return 'embed'
}
get defaultOptions() {
return {
onEmbed: () => ({}),
}
}
pasteRules({ type, schema }) {
return [
pasteRule(
/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-zA-Z]{2,}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g,
type,
url => ({ dataEmbedUrl: url }),
),
]
}
get schema() {
return {
attrs: {
href: {
dataEmbedUrl: {
default: null,
},
},
@ -16,17 +42,17 @@ export default class Embed extends Node {
selectable: false,
parseDOM: [
{
tag: 'a[class=embed]',
tag: 'a[href].embed',
getAttrs: dom => ({
href: dom.getAttribute('href'),
dataEmbedUrl: dom.getAttribute('href'),
}),
},
],
toDOM: node => [
'a',
{
href: node.attrs.dataEmbedUrl,
class: 'embed',
href: node.attrs.href,
},
],
}
@ -34,26 +60,36 @@ export default class Embed extends Node {
get view() {
return {
props: ['node', 'updateAttrs', 'view'],
props: ['node', 'updateAttrs', 'options'],
data: () => ({
title: 'Link Title',
description: 'Some Link Description text which talks a bit about the link.',
embedData: {},
}),
async created() {
if (!this.options) return {}
this.embedData = await this.options.onEmbed({ url: this.dataEmbedUrl })
},
computed: {
href: {
embedClass() {
return this.embedHtml ? 'embed' : ''
},
embedHtml() {
const { html = '' } = this.embedData
return html
},
dataEmbedUrl: {
get() {
return this.node.attrs.href
return this.node.attrs.dataEmbedUrl
},
set(href) {
set(dataEmbedUrl) {
this.updateAttrs({
href,
dataEmbedUrl,
})
},
},
},
template: `
<a class="embed" :href="href"><h4>{{ title }}</h4><p>{{ description }}</p><em>{{ href }}</em></a>
`,
render(createElement) {
return compiledTemplate.render.call(this, createElement)
},
}
}
}

View File

@ -0,0 +1,66 @@
import { shallowMount } from '@vue/test-utils'
import Embed from './Embed'
let Wrapper
let propsData
const someUrl = 'https://www.youtube.com/watch?v=qkdXAtO40Fo'
describe('Embed.vue', () => {
beforeEach(() => {
propsData = {}
const component = new Embed()
Wrapper = ({ mocks, propsData }) => {
return shallowMount(component.view, { propsData })
}
})
it('renders anchor', () => {
propsData = {
node: { attrs: { href: someUrl } },
}
expect(Wrapper({ propsData }).is('a')).toBe(true)
})
describe('given a href', () => {
describe('onEmbed returned embed data', () => {
beforeEach(() => {
propsData.options = {
onEmbed: () => ({
type: 'video',
title: 'Baby Loves Cat',
author: 'Merkley Family',
publisher: 'YouTube',
date: '2015-08-16T00:00:00.000Z',
description:
'Shes incapable of controlling her limbs when her kitty is around. The obsession grows every day. Ps. Thats a sleep sack shes in. Not a starfish outfit. Al...',
url: someUrl,
image: 'https://i.ytimg.com/vi/qkdXAtO40Fo/maxresdefault.jpg',
audio: null,
video: null,
lang: 'de',
sources: ['resource', 'oembed'],
html:
'<iframe width="480" height="270" src="https://www.youtube.com/embed/qkdXAtO40Fo?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>',
}),
}
})
it('renders the given html code', async () => {
propsData.node = { attrs: { href: 'https://www.youtube.com/watch?v=qkdXAtO40Fo' } }
const wrapper = Wrapper({ propsData })
await wrapper.html()
expect(wrapper.find('div iframe').attributes('src')).toEqual(
'https://www.youtube.com/embed/qkdXAtO40Fo?feature=oembed',
)
})
})
describe('without embedded html but some meta data instead', () => {
it.todo('renders description and link')
})
describe('without any meta data', () => {
it.todo('renders a link without `embed` class')
})
})
})

View File

@ -18,27 +18,24 @@ export default class Hashtag extends TipTapMention {
}
get schema() {
const patchedSchema = super.schema
patchedSchema.attrs = {
url: {},
label: {},
return {
...super.schema,
toDOM: node => {
return [
'a',
{
class: this.options.mentionClass,
href: `/search/hashtag/${node.attrs.id}`,
'data-hashtag-id': node.attrs.id,
target: '_blank',
},
`${this.options.matcher.char}${node.attrs.label}`,
]
},
parseDOM: [
// simply don't parse mentions from html
// just treat them as normal links
],
}
patchedSchema.toDOM = node => {
return [
'a',
{
class: this.options.mentionClass,
href: node.attrs.url,
target: '_blank',
// contenteditable: 'true',
},
`${this.options.matcher.char}${node.attrs.label}`,
]
}
patchedSchema.parseDOM = [
// this is not implemented
]
return patchedSchema
}
}

View File

@ -1,6 +1,10 @@
import { Link as TipTapLink } from 'tiptap-extensions'
export default class Link extends TipTapLink {
pasteRules({ type }) {
return []
}
get schema() {
return {
attrs: {

View File

@ -6,26 +6,24 @@ export default class Mention extends TipTapMention {
}
get schema() {
const patchedSchema = super.schema
patchedSchema.attrs = {
url: {},
label: {},
return {
...super.schema,
toDOM: node => {
return [
'a',
{
class: this.options.mentionClass,
href: `/profile/${node.attrs.id}`,
'data-mention-id': node.attrs.id,
target: '_blank',
},
`${this.options.matcher.char}${node.attrs.label}`,
]
},
parseDOM: [
// simply don't parse mentions from html
// just treat them as normal links
],
}
patchedSchema.toDOM = node => {
return [
'a',
{
class: this.options.mentionClass,
href: node.attrs.url,
target: '_blank',
},
`${this.options.matcher.char}${node.attrs.label}`,
]
}
patchedSchema.parseDOM = [
// this is not implemented
]
return patchedSchema
}
}

View File

@ -1,7 +1,7 @@
import { storiesOf } from '@storybook/vue'
import { withA11y } from '@storybook/addon-a11y'
import HcPostCard from '~/components/PostCard'
import helpers from './helpers'
import helpers from '~/storybook/helpers'
helpers.init()

View File

@ -0,0 +1,23 @@
import gql from 'graphql-tag'
export default function() {
return gql`
query($url: String!) {
embed(url: $url) {
type
title
author
publisher
date
description
url
image
audio
video
lang
sources
html
}
}
`
}

View File

@ -116,7 +116,7 @@
</ds-container>
</div>
<ds-container style="word-break: break-all">
<div class="main-container" :width="{ base: '100%', md: '96%' }">
<div class="main-container">
<nuxt />
</div>
</ds-container>

View File

@ -12,7 +12,7 @@
"scripts": {
"dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server",
"dev:styleguide": "cross-env STYLEGUIDE_DEV=true yarn dev",
"storybook": "start-storybook -p 9001 -c .storybook",
"storybook": "start-storybook -p 3002 -c storybook/",
"build": "nuxt build",
"start": "cross-env node server/index.js",
"generate": "nuxt generate",
@ -83,10 +83,10 @@
"devDependencies": {
"@babel/core": "~7.5.5",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/preset-env": "~7.5.5",
"@storybook/addon-a11y": "^5.1.9",
"@storybook/addon-actions": "^5.1.9",
"@storybook/vue": "~5.1.9",
"@babel/preset-env": "~7.5.5",
"@vue/cli-shared-utils": "~3.9.0",
"@vue/eslint-config-prettier": "~5.0.0",
"@vue/server-test-utils": "~1.0.0-beta.29",
@ -97,6 +97,7 @@
"babel-loader": "~8.0.6",
"babel-preset-vue": "~2.0.2",
"css-loader": "~2.1.1",
"core-js": "~2.6.9",
"eslint": "~5.16.0",
"eslint-config-prettier": "~6.0.0",
"eslint-config-standard": "~12.0.0",
@ -121,6 +122,6 @@
"vue-jest": "~3.0.4",
"vue-loader": "~15.7.0",
"vue-svg-loader": "~0.12.0",
"vue-template-compiler": "~2.6.10"
"vue-template-compiler": "^2.6.10"
}
}

View File

@ -20,10 +20,7 @@
<ds-space margin-bottom="small" />
<ds-heading tag="h3" no-margin>{{ post.title }}</ds-heading>
<ds-space margin-bottom="small" />
<!-- Content -->
<!-- eslint-disable vue/no-v-html -->
<!-- TODO: replace editor content with tiptap render view -->
<div class="content hc-editor-content" v-html="post.content" />
<content-viewer class="content" :content="post.content" />
<!-- eslint-enable vue/no-v-html -->
<ds-space margin="xx-large" />
<!-- Categories -->
@ -62,6 +59,7 @@
</template>
<script>
import ContentViewer from '~/components/Editor/ContentViewer'
import HcCategory from '~/components/Category'
import HcTag from '~/components/Tag'
import ContentMenu from '~/components/ContentMenu'
@ -86,6 +84,7 @@ export default {
ContentMenu,
HcCommentForm,
HcCommentList,
ContentViewer,
},
head() {
return {

View File

@ -23,7 +23,7 @@ Vue.component('v-popover', {
})
// Automatically import all files ending in *.stories.js
const req = require.context('../stories', true, /.story.js$/)
const req = require.context('../components', true, /.story.js$/)
function loadStories() {
req.keys().forEach(req)

View File

@ -6,7 +6,7 @@ import Filters from '~/plugins/vue-filters'
import layout from './layout.vue'
const helpers = {
init() {
init(options = {}) {
Vue.use(Vuex)
Vue.use(Styleguide)
Vue.use(Filters)
@ -16,6 +16,9 @@ const helpers = {
Vue.i18n.add('de', require('~/locales/de.json'))
Vue.i18n.set('en')
Vue.i18n.fallback('en')
const { plugins = [] } = options
plugins.forEach(plugin => Vue.use(plugin))
},
store: new Vuex.Store({
modules: {

View File

@ -729,7 +729,7 @@
dependencies:
regenerator-runtime "^0.12.0"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.3", "@babel/runtime@^7.5.0":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.3":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==
@ -1443,16 +1443,16 @@
warning "^3.0.0"
"@storybook/addon-a11y@^5.1.9":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-5.1.10.tgz#0bf37a8e2827cdaa199b293b14e71e8434246591"
integrity sha512-YiRj/8IQ5zq/I+x+aRyfS5PP9nTfuTU7O90+WtNomqCJPMBOrR3BYsEcl510jOy2iwhQwh76MFT5s1tKpMclAA==
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/addon-a11y/-/addon-a11y-5.1.9.tgz#3feea3f49680f6c311cefd1838b82721d59f397e"
integrity sha512-5u90lEpJtO1W8unwNy5fKTKQG7Sbe3IZJpiC6rf1MdGk0avSwoxDyblt0NImPDBHTh4LeUcuCn57D7AVNLUplg==
dependencies:
"@storybook/addons" "5.1.10"
"@storybook/api" "5.1.10"
"@storybook/client-logger" "5.1.10"
"@storybook/components" "5.1.10"
"@storybook/core-events" "5.1.10"
"@storybook/theming" "5.1.10"
"@storybook/addons" "5.1.9"
"@storybook/api" "5.1.9"
"@storybook/client-logger" "5.1.9"
"@storybook/components" "5.1.9"
"@storybook/core-events" "5.1.9"
"@storybook/theming" "5.1.9"
axe-core "^3.2.2"
common-tags "^1.8.0"
core-js "^3.0.1"
@ -1466,15 +1466,15 @@
util-deprecate "^1.0.2"
"@storybook/addon-actions@^5.1.9":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.1.10.tgz#8ed4272a6afc68f4a30372da2eeff414f0fe6ecd"
integrity sha512-njl2AHBGi27NvisOB8LFnWH/3RcyJT/CW7tl1cvV2j5FH2oBjq5MsjxKyJIcKwC677k1Wr8G8fw/zSEHrPpmgA==
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.1.9.tgz#a515b62b109cb886ccd75ef2f5b12f8c27b43dd3"
integrity sha512-h/csHPotBESyEUYlML3yyF2jUlDChB+u3TUNC3Ztzh/x7HzLqy88SL0INSIdY0dCBGx4TK5Gh+rMI7z28Hfdyw==
dependencies:
"@storybook/addons" "5.1.10"
"@storybook/api" "5.1.10"
"@storybook/components" "5.1.10"
"@storybook/core-events" "5.1.10"
"@storybook/theming" "5.1.10"
"@storybook/addons" "5.1.9"
"@storybook/api" "5.1.9"
"@storybook/components" "5.1.9"
"@storybook/core-events" "5.1.9"
"@storybook/theming" "5.1.9"
core-js "^3.0.1"
fast-deep-equal "^2.0.1"
global "^4.3.2"
@ -1485,28 +1485,28 @@
react-inspector "^3.0.2"
uuid "^3.3.2"
"@storybook/addons@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.1.10.tgz#2d8d8ca20b6d9b4652744f5fc00ead483f705435"
integrity sha512-M9b2PCp9RZxDC6wL7vVt2SCKCGXrrEAOsdpMvU569yB1zoUPEiiqElVDwb91O2eAGPnmd2yjImp90kOpKUW0EA==
"@storybook/addons@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.1.9.tgz#ecf218d08508b97ca5e6e0f1ed361081385bd3ff"
integrity sha512-1bavbcS/NiE65DwyKj8c0DmWmz9VekOinB+has2Pqt2bOffZoZwVnbmepcz9hH3GUyvp5fQBYbxTEmTDvF2lLA==
dependencies:
"@storybook/api" "5.1.10"
"@storybook/channels" "5.1.10"
"@storybook/client-logger" "5.1.10"
"@storybook/api" "5.1.9"
"@storybook/channels" "5.1.9"
"@storybook/client-logger" "5.1.9"
core-js "^3.0.1"
global "^4.3.2"
util-deprecate "^1.0.2"
"@storybook/api@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.1.10.tgz#5eeb5d9a7c268e5c89bd40c9a80293a7c72343b8"
integrity sha512-YeZe/71zLMmgT95IMAEZOc9AwL6Y23mWvkZMwFbkokxS9+bU/qmVlQ0B9c3JBzO3OSs7sXaRqyP1o3QkQgVsiw==
"@storybook/api@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/api/-/api-5.1.9.tgz#eec5b2f775392ce0803930104c6ce14fa4931e8b"
integrity sha512-d1HhpOkW+706/WJ9lP5nCqOrp/icvbm0o+6jFFOGJ35AW5O9D8vDBxzvgMEO45jjN4I+rtbcNHQCxshSbPvP9w==
dependencies:
"@storybook/channels" "5.1.10"
"@storybook/client-logger" "5.1.10"
"@storybook/core-events" "5.1.10"
"@storybook/router" "5.1.10"
"@storybook/theming" "5.1.10"
"@storybook/channels" "5.1.9"
"@storybook/client-logger" "5.1.9"
"@storybook/core-events" "5.1.9"
"@storybook/router" "5.1.9"
"@storybook/theming" "5.1.9"
core-js "^3.0.1"
fast-deep-equal "^2.0.1"
global "^4.3.2"
@ -1520,33 +1520,33 @@
telejson "^2.2.1"
util-deprecate "^1.0.2"
"@storybook/channel-postmessage@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.1.10.tgz#e0a58461d56ef20a87d8bc4df1067e7afc76950e"
integrity sha512-kQZIwltN2cWDXluhCfdModFDK1LHV9ZhNQ1b/uD9vn1c65rQ9u7r4lRajCfS0X1dmAWqz48cBcEurAubNgmswg==
"@storybook/channel-postmessage@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.1.9.tgz#bd710ca74d7998a234c6b1f38009020d7c34bbc0"
integrity sha512-H71PsnDKW81eflOS48Lv9yK4O8AcoqXL6ohsWvLdrHWIBsH4zpjOIhdWHtmAaT3hyfMy+l49DQ+uCHLECEt55g==
dependencies:
"@storybook/channels" "5.1.10"
"@storybook/client-logger" "5.1.10"
"@storybook/channels" "5.1.9"
"@storybook/client-logger" "5.1.9"
core-js "^3.0.1"
global "^4.3.2"
telejson "^2.2.1"
"@storybook/channels@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.1.10.tgz#04fd35c05032c675f7816ea1ca873c1a0415c6d9"
integrity sha512-w7n/bV1BLu51KI1eLc75lN9H1ssBc3PZMXk88GkMiKyBVRzPlJA5ixnzH86qwYGReE0dhRpsgHXZ5XmoKaVmPA==
"@storybook/channels@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.1.9.tgz#003cfca0b9f1ba6cf47ce68304aedd71bdb55e74"
integrity sha512-R6i7859FsXgY9XFFErVe7gS37wGYpQEEWsO1LzUW7YptGuFTUa8yLgKkNkgfy7Zs61Xm+GiBq8PvS/CWxjotPw==
dependencies:
core-js "^3.0.1"
"@storybook/client-api@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.1.10.tgz#a10f028f2d33d044e5c3b3daea5d8375323e6a66"
integrity sha512-v2PqiNUhwDlVDLYL94f6LFjdYMToTpuwWh9aeqzt/4PAJUnIcA+2P8+qXiYdJTqQy/u7P72HFMlc9Ru4tl3QFg==
"@storybook/client-api@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.1.9.tgz#b598efe4ab07bffaeb4cb9e30ed9c21add739df1"
integrity sha512-J5HDtOS7x5YRpF/CMiHdxywV5NIh1i/03Xh2RhG15lmPy87VStIGpLzhF71uCRPLEJinYelcjuXRNAJgRzUOlg==
dependencies:
"@storybook/addons" "5.1.10"
"@storybook/client-logger" "5.1.10"
"@storybook/core-events" "5.1.10"
"@storybook/router" "5.1.10"
"@storybook/addons" "5.1.9"
"@storybook/client-logger" "5.1.9"
"@storybook/core-events" "5.1.9"
"@storybook/router" "5.1.9"
common-tags "^1.8.0"
core-js "^3.0.1"
eventemitter3 "^3.1.0"
@ -1556,20 +1556,20 @@
memoizerific "^1.11.3"
qs "^6.6.0"
"@storybook/client-logger@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.1.10.tgz#f83a8717924dd222e0a6df82ae74701f27e0bb35"
integrity sha512-vB1NoFWRTgcERwodhbgoDwI00eqU8++nXI7GhMS1CY8haZaSp3gyKfHRWyfH+M+YjQuGBRUcvIk4gK6OtSrDOw==
"@storybook/client-logger@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.1.9.tgz#87e2f7578416269adeccd407584010bc353f14d3"
integrity sha512-1+Otcn0EFgWNviDPNCR5LtUViADlboz9fmpZc7UY7bgaY5FVNIUO01E4T43tO7fduiRZoEvdltwTuQRm260Vjw==
dependencies:
core-js "^3.0.1"
"@storybook/components@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.1.10.tgz#4b6436f0b5bb2483fb231bee263d173a9ed7d241"
integrity sha512-QUQeeQp1xNWiL4VlxFAea0kqn2zvBfmfPlUddOFO9lBhT6pVy0xYPjXjbTVWjVcYzZpyUNWw5GplqrR5jhlaCA==
"@storybook/components@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.1.9.tgz#2a5258780fff07172d103287759946dbb4b13e2d"
integrity sha512-F4xcRlifSAfqkuFWtCKRvQDahXyfWBWV2Wa+kYy4YGwEfm3kKtIHVlgdgARL22g9BdYpRFEOJ+42juOu5YvIeQ==
dependencies:
"@storybook/client-logger" "5.1.10"
"@storybook/theming" "5.1.10"
"@storybook/client-logger" "5.1.9"
"@storybook/theming" "5.1.9"
core-js "^3.0.1"
global "^4.3.2"
markdown-to-jsx "^6.9.1"
@ -1587,32 +1587,32 @@
recompose "^0.30.0"
simplebar-react "^1.0.0-alpha.6"
"@storybook/core-events@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.1.10.tgz#5aed88c572036b6bd6dfff28976ee96e6e175d7a"
integrity sha512-Lvu/rNcgS+XCkQKSGdNpUSWjpFF9AOSHPXsvkwHbRwJYdMDn3FznlXfDUiubOWtsziXHB6vl3wkKDlH+ckb32Q==
"@storybook/core-events@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.1.9.tgz#441a6297e2ccfa743e15d1db1f4ac445b91f40d8"
integrity sha512-jHe2uyoLj9i6fntHtOj5azfGdLOb75LF0e1xXE8U2SX7Zp3uwbLAcfJ+dPStdc/q+f/wBiip3tH1dIjaNuUiMw==
dependencies:
core-js "^3.0.1"
"@storybook/core@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.1.10.tgz#53d23d07716aa2721e1572d44a7f05967d7da39e"
integrity sha512-zkNjufOFrLpFpmr73F/gaJh0W0vWqXIo5zrKvQt1LqmMeCU/v8MstHi4XidlK43UpeogfaXl5tjNCQDO/bd0Dw==
"@storybook/core@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.1.9.tgz#8b30507676531fd41ac333b7c71b1c0db6b8da35"
integrity sha512-P3aavCnl3Cl3WMXVERjQqnqV1Z8tN0tyOTqqiGb1fMxITSE8uZNvp33Dl0K3jr1PBl9trW+2t7eHH4h0sguLlQ==
dependencies:
"@babel/plugin-proposal-class-properties" "^7.3.3"
"@babel/plugin-proposal-object-rest-spread" "^7.3.2"
"@babel/plugin-syntax-dynamic-import" "^7.2.0"
"@babel/plugin-transform-react-constant-elements" "^7.2.0"
"@babel/preset-env" "^7.4.5"
"@storybook/addons" "5.1.10"
"@storybook/channel-postmessage" "5.1.10"
"@storybook/client-api" "5.1.10"
"@storybook/client-logger" "5.1.10"
"@storybook/core-events" "5.1.10"
"@storybook/node-logger" "5.1.10"
"@storybook/router" "5.1.10"
"@storybook/theming" "5.1.10"
"@storybook/ui" "5.1.10"
"@storybook/addons" "5.1.9"
"@storybook/channel-postmessage" "5.1.9"
"@storybook/client-api" "5.1.9"
"@storybook/client-logger" "5.1.9"
"@storybook/core-events" "5.1.9"
"@storybook/node-logger" "5.1.9"
"@storybook/router" "5.1.9"
"@storybook/theming" "5.1.9"
"@storybook/ui" "5.1.9"
airbnb-js-shims "^1 || ^2"
autoprefixer "^9.4.9"
babel-plugin-add-react-displayname "^0.0.5"
@ -1666,10 +1666,10 @@
webpack-dev-middleware "^3.7.0"
webpack-hot-middleware "^2.25.0"
"@storybook/node-logger@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.1.10.tgz#92c80b46177687cd8fda1f93a055c22711984154"
integrity sha512-Z4UKh7QBOboQhUF5S/dKOx3OWWCNZGwYu8HZa/O+P68+XnQDhuZCYwqWG49xFhZd0Jb0W9gdUL2mWJw5POG9PA==
"@storybook/node-logger@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.1.9.tgz#4aacf0096811fde1639fc9d1d2d521f7220dd4be"
integrity sha512-rcSuI5n53hDMHW83gl5TR0Yn885/i2XY0AzX1DsbTeGOl3x5LhrCSZsZWetKGcx7zsO4n7o5mQszLuN1JlyE8A==
dependencies:
chalk "^2.4.2"
core-js "^3.0.1"
@ -1677,10 +1677,10 @@
pretty-hrtime "^1.0.3"
regenerator-runtime "^0.12.1"
"@storybook/router@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.1.10.tgz#d3cffd3f1105eb665882f389746ccabbb98c3c16"
integrity sha512-BdG6/essPZFHCP2ewCG0gYFQfmuuTSHXAB5fd/rwxLSYj1IzNznC5OxkvnSaTr4rgoxxaW/z1hbN1NuA0ivlFA==
"@storybook/router@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.1.9.tgz#8cd97bea4f2acf8ec5f6694d06fb0633dde33417"
integrity sha512-eAmeerE/OTIwCV7WBnb1BPINVN1GTSMsUXLNWpqSISuyWJ+NZAJlObFkvXoc57QSQlv0cvXlm1FMkmRt8ku1Hw==
dependencies:
"@reach/router" "^1.2.1"
core-js "^3.0.1"
@ -1688,14 +1688,14 @@
memoizerific "^1.11.3"
qs "^6.6.0"
"@storybook/theming@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.1.10.tgz#f9bd519cdf9cccf730656e3f5fd56a339dd07c9f"
integrity sha512-5cN1lmdVUwAR8U3T49Lfb8JW5RBvxBSPGZpUmbLGz1zi0tWBJgYXoGtw4RbTBjV9kCQOXkHGH12AsdDxHh931w==
"@storybook/theming@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.1.9.tgz#c425f5867fae0db79e01112853b1808332a5f1a2"
integrity sha512-4jIFJwTWVf9tsv27noLoFHlKC2Jl9DHV3q+rxGPU8bTNbufCu4oby82SboO5GAKuS3eu1cxL1YY9pYad9WxfHg==
dependencies:
"@emotion/core" "^10.0.9"
"@emotion/styled" "^10.0.7"
"@storybook/client-logger" "5.1.10"
"@storybook/client-logger" "5.1.9"
common-tags "^1.8.0"
core-js "^3.0.1"
deep-object-diff "^1.1.0"
@ -1706,19 +1706,19 @@
prop-types "^15.7.2"
resolve-from "^5.0.0"
"@storybook/ui@5.1.10":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.1.10.tgz#4262b1b09efa43d125d694452ae879b89071edd1"
integrity sha512-ezkoVtzoKh93z2wzkqVIqyrIzTkj8tizgAkoPa7mUAbLCxu6LErHITODQoyEiJWI4Epy3yU9GYXFWwT71hdwsA==
"@storybook/ui@5.1.9":
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.1.9.tgz#406667469e6dbdf320086647d8d80776bb051a51"
integrity sha512-guzKv4VYM+06BzMXeO3QqlX0IwUHyeS6lwdPCL8Oy2V4Gi2IYHHiD6Hr1NgnBO18j9luxE38f4Ii7gEIzXMFbQ==
dependencies:
"@storybook/addons" "5.1.10"
"@storybook/api" "5.1.10"
"@storybook/channels" "5.1.10"
"@storybook/client-logger" "5.1.10"
"@storybook/components" "5.1.10"
"@storybook/core-events" "5.1.10"
"@storybook/router" "5.1.10"
"@storybook/theming" "5.1.10"
"@storybook/addons" "5.1.9"
"@storybook/api" "5.1.9"
"@storybook/channels" "5.1.9"
"@storybook/client-logger" "5.1.9"
"@storybook/components" "5.1.9"
"@storybook/core-events" "5.1.9"
"@storybook/router" "5.1.9"
"@storybook/theming" "5.1.9"
copy-to-clipboard "^3.0.8"
core-js "^3.0.1"
core-js-pure "^3.0.1"
@ -1747,11 +1747,11 @@
util-deprecate "^1.0.2"
"@storybook/vue@~5.1.9":
version "5.1.10"
resolved "https://registry.yarnpkg.com/@storybook/vue/-/vue-5.1.10.tgz#37916c93faf2eca21497b359748109727ccf3216"
integrity sha512-UeRbQ5bOWUTx5oBMfPf+ZtP5E5X74nFFhrkg0yNakohW6pLuTVoci/G8hDJ4wsjT7PgNjoE1/dggf4JKCU9tjA==
version "5.1.9"
resolved "https://registry.yarnpkg.com/@storybook/vue/-/vue-5.1.9.tgz#ff37730e3d9575b389dddc6870a07c34c7a53e47"
integrity sha512-ssBQOHdArHFn/FXVsXqi+FiiSvnulux6CIjmaZTjWMgktDa1Hp7TWFN3rlYCM+WxO2KBtydK5AyRWd8+r9YelQ==
dependencies:
"@storybook/core" "5.1.10"
"@storybook/core" "5.1.9"
common-tags "^1.8.0"
core-js "^3.0.1"
global "^4.3.2"
@ -2312,11 +2312,6 @@ acorn@^6.0.1, acorn@^6.0.2, acorn@^6.0.5, acorn@^6.0.7:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f"
integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==
acorn@^6.2.0:
version "6.2.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.1.tgz#3ed8422d6dec09e6121cc7a843ca86a330a86b51"
integrity sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==
address@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9"
@ -3444,7 +3439,7 @@ bluebird@^3.1.1, bluebird@^3.5.1, bluebird@^3.5.3:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.4.tgz#d6cc661595de30d5b3af5fcedd3c0b3ef6ec5714"
integrity sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==
bluebird@^3.3.5, bluebird@^3.5.5:
bluebird@^3.3.5:
version "3.5.5"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
@ -3719,27 +3714,6 @@ cacache@^11.0.2, cacache@^11.3.2:
unique-filename "^1.1.1"
y18n "^4.0.0"
cacache@^12.0.2:
version "12.0.2"
resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.2.tgz#8db03205e36089a3df6954c66ce92541441ac46c"
integrity sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==
dependencies:
bluebird "^3.5.5"
chownr "^1.1.1"
figgy-pudding "^3.5.1"
glob "^7.1.4"
graceful-fs "^4.1.15"
infer-owner "^1.0.3"
lru-cache "^5.1.1"
mississippi "^3.0.0"
mkdirp "^0.5.1"
move-concurrently "^1.0.1"
promise-inflight "^1.0.1"
rimraf "^2.6.3"
ssri "^6.0.1"
unique-filename "^1.1.1"
y18n "^4.0.0"
cache-base@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
@ -3853,9 +3827,9 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000939, caniuse-lite@^1.0.30000957, can
integrity sha512-rUBIbap+VJfxTzrM4akJ00lkvVb5/n5v3EGXfWzSH5zT8aJmGzjA8HWhJ4U6kCpzxozUSnB+yvAYDRPY6mRpgQ==
caniuse-lite@^1.0.30000955:
version "1.0.30000988"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000988.tgz#742f35ec1b8b75b9628d705d7652eea1fef983db"
integrity sha512-lPj3T8poYrRc/bniW5SQPND3GRtSrQdUM/R4mCYTbZxyi3jQiggLvZH4+BYUuX0t4TXjU+vMM7KFDQg+rSzZUQ==
version "1.0.30000985"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000985.tgz#0eb40f6c8a8c219155cbe43c4975c0efb4a0f77f"
integrity sha512-1ngiwkgqAYPG0JSSUp3PUDGPKKY59EK7NrGGX+VOxaKCNzRbNc7uXMny+c3VJfZxtoK3wSImTvG9T9sXiTw2+w==
caniuse-lite@^1.0.30000973:
version "1.0.30000973"
@ -4218,7 +4192,7 @@ commander@2.17.x:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.0:
commander@^2.18.0, commander@^2.19.0, commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
@ -4465,18 +4439,23 @@ core-js@^3.0.1, core-js@^3.0.4:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07"
integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==
core-js@~2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
corejs-upgrade-webpack-plugin@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/corejs-upgrade-webpack-plugin/-/corejs-upgrade-webpack-plugin-2.2.0.tgz#503293bf1fdcb104918eb40d0294e4776ad6923a"
integrity sha512-J0QMp9GNoiw91Kj/dkIQFZeiCXgXoja/Wlht1SPybxerBWh4NCmb0pOgCv61lrlQZETwvVVfAFAA3IqoEO9aqQ==
version "2.1.0"
resolved "https://registry.yarnpkg.com/corejs-upgrade-webpack-plugin/-/corejs-upgrade-webpack-plugin-2.1.0.tgz#6afa44672486353ae639c297548c0686b64fb325"
integrity sha512-gc+S4t8VT9YFSgOPrhZlD6kDoGZtUq71QwXxS2neGNPhli0veKhbzzilODIpy73TjXGUrCHCpevK8vBnzUPuhw==
dependencies:
resolve-from "^5.0.0"
webpack "^4.38.0"
webpack "^4.33.0"
cors@^2.8.4:
version "2.8.5"
@ -5285,9 +5264,9 @@ ejs@^2.6.1:
integrity sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==
electron-to-chromium@^1.3.122:
version "1.3.208"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.208.tgz#6df90b89e8b9af139db3c8d7a6b935db0801e61c"
integrity sha512-ljgZXaKSfRg32jEl1V8zRJaT3u653jxfZRztKQWM/I1kE+ifBCQKRY+jOPzb4JS48a4czvT/LQfjdiDq5qjU4g==
version "1.3.200"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.200.tgz#78fb858b466269e8eb46d31a52562f00c865127f"
integrity sha512-PUurrpyDA74MuAjJRD+79ss5BqJlU3mdArRbuu4wO/dt6jc3Ic/6BDmFJxkdwbfq39cHf/XKm2vW98XSvut9Dg==
electron-to-chromium@^1.3.133:
version "1.3.137"
@ -7128,11 +7107,6 @@ indexof@0.0.1:
resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=
infer-owner@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@ -8339,11 +8313,11 @@ launch-editor@^2.2.1:
shell-quote "^1.6.1"
lazy-universal-dotenv@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz#a6c8938414bca426ab8c9463940da451a911db38"
integrity sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==
version "3.0.0"
resolved "https://registry.yarnpkg.com/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.0.tgz#e71f07f89d8de6bbf491478e4503df3c96729b8d"
integrity sha512-Mbf5AeGOs74lE5BdQXHFJ7Rt383jxnWKNfW2EWL0Pibnhea5JRStRIiUpdTenyMxCGuCjlMpYQhhay1XZBSSQA==
dependencies:
"@babel/runtime" "^7.5.0"
"@babel/runtime" "^7.0.0"
app-root-dir "^1.0.2"
core-js "^3.0.4"
dotenv "^8.0.0"
@ -8489,6 +8463,11 @@ lodash.debounce@^4.0.8:
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168=
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
@ -8817,9 +8796,9 @@ merge-stream@^1.0.1:
readable-stream "^2.0.1"
merge2@^1.2.3:
version "1.2.4"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.4.tgz#c9269589e6885a60cf80605d9522d4b67ca646e3"
integrity sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A==
version "1.2.3"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==
methods@~1.1.2:
version "1.1.2"
@ -11133,9 +11112,9 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
strip-json-comments "~2.0.1"
react-clientside-effect@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.2.tgz#6212fb0e07b204e714581dd51992603d1accc837"
integrity sha512-nRmoyxeok5PBO6ytPvSjKp9xwXg9xagoTK1mMjwnQxqM9Hd7MNPl+LS1bOSOe+CV2+4fnEquc7H/S8QD3q697A==
version "1.2.1"
resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.1.tgz#feb81abe9531061d4987941c15a00f2b3d0b6071"
integrity sha512-foSwZatJak6r+F4OqJ8a+MOWcBi3jwa7/RPdJIDZI1Ck0dn/FJZkkFu7YK+SiZxsCZIrotolxHSobcnBHgIjfw==
dependencies:
"@babel/runtime" "^7.0.0"
@ -12241,14 +12220,6 @@ source-map-support@^0.5.6, source-map-support@~0.5.10:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-support@~0.5.12:
version "0.5.13"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@ -12736,16 +12707,16 @@ tar@^4:
yallist "^3.0.2"
telejson@^2.2.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/telejson/-/telejson-2.2.2.tgz#d61d721d21849a6e4070d547aab302a9bd22c720"
integrity sha512-YyNwnKY0ilabOwYgC/J754En1xOe5PBIUIw+C9e0+5HjVVcnQE5/gdu2yET2pmSbp5bxIDqYNjvndj2PUkIiYA==
version "2.2.1"
resolved "https://registry.yarnpkg.com/telejson/-/telejson-2.2.1.tgz#d9ee7e7eba0c81d9378257342fde7142a03787e2"
integrity sha512-JtFAnITek+Z9t+uQjVl4Fxur9Z3Bi3flytBLc3KZVXmMUHLXdtAxiP0g8IBkHvKn1kQIYZC57IG0jjGH1s64HQ==
dependencies:
global "^4.3.2"
is-function "^1.0.1"
is-regex "^1.0.4"
is-symbol "^1.0.2"
isobject "^3.0.1"
lodash "^4.17.11"
lodash.get "^4.4.2"
memoizerific "^1.11.3"
term-size@^1.2.0:
@ -12774,22 +12745,7 @@ terser-webpack-plugin@^1.1.0:
webpack-sources "^1.1.0"
worker-farm "^1.5.2"
terser-webpack-plugin@^1.2.4:
version "1.4.1"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4"
integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==
dependencies:
cacache "^12.0.2"
find-cache-dir "^2.1.0"
is-wsl "^1.1.0"
schema-utils "^1.0.0"
serialize-javascript "^1.7.0"
source-map "^0.6.1"
terser "^4.1.2"
webpack-sources "^1.4.0"
worker-farm "^1.7.0"
terser-webpack-plugin@^1.3.0:
terser-webpack-plugin@^1.2.4, terser-webpack-plugin@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz#69aa22426299f4b5b3775cbed8cb2c5d419aa1d4"
integrity sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg==
@ -12823,15 +12779,6 @@ terser@^4.0.0:
source-map "~0.6.1"
source-map-support "~0.5.10"
terser@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.2.tgz#b2656c8a506f7ce805a3f300a2ff48db022fa391"
integrity sha512-jvNoEQSPXJdssFwqPSgWjsOrb+ELoE+ILpHPKXC83tIxOlh2U75F1KuB2luLD/3a6/7K3Vw5pDn+hvu0C4AzSw==
dependencies:
commander "^2.20.0"
source-map "~0.6.1"
source-map-support "~0.5.12"
test-exclude@^5.2.3:
version "5.2.3"
resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0"
@ -13672,7 +13619,7 @@ vue-sweetalert-icons@~3.2.0:
resolved "https://registry.yarnpkg.com/vue-sweetalert-icons/-/vue-sweetalert-icons-3.2.0.tgz#2926d3af5590b81c0ba3b104212922fc1709396d"
integrity sha512-N18uG8++ZfdCnXO0gHNTmwpB2mAE8WWrwjGeWGa8CnHu6l1emn4RG6E8r1P9crVJ+fx3R9gTUezC+cdVu0mN7w==
vue-template-compiler@^2.6.10, vue-template-compiler@~2.6.10:
vue-template-compiler@^2.6.10:
version "2.6.10"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz#323b4f3495f04faa3503337a82f5d6507799c9cc"
integrity sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==
@ -13821,14 +13768,6 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.3.0:
source-list-map "^2.0.0"
source-map "~0.6.1"
webpack-sources@^1.4.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.1.tgz#b91b2c5b1c4e890ff50d1d35b7fa3657040da1da"
integrity sha512-XSz38193PTo/1csJabKaV4b53uRVotlMgqJXm3s3eje0Bu6gQTxYDqpD38CmQfDBA+gN+QqaGjasuC8I/7eW3Q==
dependencies:
source-list-map "^2.0.0"
source-map "~0.6.1"
webpack@^4.33.0:
version "4.33.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.33.0.tgz#c30fc4307db432e5c5e3333aaa7c16a15a3b277e"
@ -13859,35 +13798,6 @@ webpack@^4.33.0:
watchpack "^1.5.0"
webpack-sources "^1.3.0"
webpack@^4.38.0:
version "4.38.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.38.0.tgz#6d77108404b08883c78f4e7e45a43c4e5c47c931"
integrity sha512-lbuFsVOq8PZY+1Ytz/mYOvYOo+d4IJ31hHk/7iyoeWtwN33V+5HYotSH+UIb9tq914ey0Hot7z6HugD+je3sWw==
dependencies:
"@webassemblyjs/ast" "1.8.5"
"@webassemblyjs/helper-module-context" "1.8.5"
"@webassemblyjs/wasm-edit" "1.8.5"
"@webassemblyjs/wasm-parser" "1.8.5"
acorn "^6.2.0"
ajv "^6.1.0"
ajv-keywords "^3.1.0"
chrome-trace-event "^1.0.0"
enhanced-resolve "^4.1.0"
eslint-scope "^4.0.0"
json-parse-better-errors "^1.0.2"
loader-runner "^2.3.0"
loader-utils "^1.1.0"
memory-fs "~0.4.1"
micromatch "^3.1.8"
mkdirp "~0.5.0"
neo-async "^2.5.0"
node-libs-browser "^2.0.0"
schema-utils "^1.0.0"
tapable "^1.1.0"
terser-webpack-plugin "^1.1.0"
watchpack "^1.5.0"
webpack-sources "^1.3.0"
webpackbar@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/webpackbar/-/webpackbar-3.2.0.tgz#bdaad103fad11a4e612500e72aaae98b08ba493f"