Merge tag '1.1.3' into chapril

This commit is contained in:
Tykayn 2021-05-04 12:41:01 +02:00 committed by tykayn
commit 8a259c4c62
35 changed files with 2007 additions and 2236 deletions

View File

@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 1.1.3 - 03-05-2021
### Changed
- Lower the frequency for refreshment of external groups
### Fixes
- Fixed spaces being eaten in the rich text editor (event description, comments and public posts)
- Fixed event physical address display
- Fixed tags being limited to 20 characters
- Fixed some ActivityPub errors
### Translations
- Galician
- Russian
- Spanish
## 1.1.2 - 28-04-2021
### Changed
@ -25,7 +44,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Translations
- Italian
- German
- Slovenian
- Russian
## 1.1.1 - 22-04-2021

View File

@ -270,7 +270,7 @@ config :mobilizon, Oban,
{Oban.Plugins.Cron,
crontab: [
{"@hourly", Mobilizon.Service.Workers.BuildSiteMap, queue: :background},
{"17 * * * *", Mobilizon.Service.Workers.RefreshGroups, queue: :background},
{"17 4 * * *", Mobilizon.Service.Workers.RefreshGroups, queue: :background},
# To be activated in Mobilizon 1.2
# {"@hourly", Mobilizon.Service.Workers.CleanOrphanMediaWorker, queue: :background},
{"@hourly", Mobilizon.Service.Workers.CleanUnconfirmedUsersWorker, queue: :background},

View File

@ -1,9 +1,9 @@
FROM elixir:latest
LABEL maintainer="Thomas Citharel <tcit@tcit.fr>"
ENV REFRESHED_AT=2021-02-08
ENV REFRESHED_AT=2021-04-30
RUN apt-get update -yq && apt-get install -yq build-essential inotify-tools postgresql-client git curl gnupg xvfb libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 cmake exiftool
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash && apt-get install nodejs -yq
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash && apt-get install nodejs -yq
RUN npm install -g yarn wait-on
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN mix local.hex --force && mix local.rebar --force

View File

@ -1,6 +1,6 @@
{
"name": "mobilizon",
"version": "1.1.2",
"version": "1.1.3",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
@ -15,6 +15,19 @@
"@absinthe/socket": "^0.2.1",
"@absinthe/socket-apollo-link": "^0.2.1",
"@mdi/font": "^5.0.45",
"@tiptap/core": "^2.0.0-beta.41",
"@tiptap/extension-blockquote": "^2.0.0-beta.6",
"@tiptap/extension-bubble-menu": "^2.0.0-beta.9",
"@tiptap/extension-character-count": "^2.0.0-beta.5",
"@tiptap/extension-history": "^2.0.0-beta.5",
"@tiptap/extension-image": "^2.0.0-beta.6",
"@tiptap/extension-link": "^2.0.0-beta.8",
"@tiptap/extension-list-item": "^2.0.0-beta.6",
"@tiptap/extension-mention": "^2.0.0-beta.42",
"@tiptap/extension-ordered-list": "^2.0.0-beta.6",
"@tiptap/extension-underline": "^2.0.0-beta.7",
"@tiptap/starter-kit": "^2.0.0-beta.37",
"@tiptap/vue-2": "^2.0.0-beta.21",
"apollo-absinthe-upload-link": "^1.5.0",
"apollo-cache": "^1.3.5",
"apollo-cache-inmemory": "^1.6.6",
@ -35,11 +48,10 @@
"leaflet.locatecontrol": "^0.73.0",
"lodash": "^4.17.11",
"ngeohash": "^0.6.3",
"p-debounce": "^4.0.0",
"phoenix": "^1.4.11",
"register-service-worker": "^1.7.1",
"tippy.js": "^6.2.3",
"tiptap": "^1.32.0",
"tiptap-extensions": "^1.34.0",
"unfetch": "^4.2.0",
"v-tooltip": "^2.1.3",
"vue": "^2.6.11",

View File

@ -212,6 +212,7 @@ export default class Comment extends Vue {
// See https://github.com/kaorun343/vue-property-decorator/issues/257
@Ref() readonly commentEditor!: EditorComponent & {
replyToComment: (comment: IComment) => void;
focus: () => void;
};
currentActor!: IPerson;
@ -242,6 +243,11 @@ export default class Comment extends Vue {
return;
}
this.replyTo = true;
if (this.comment.actor) {
this.commentEditor.replyToComment(this.comment.actor);
await this.$nextTick; // wait for the mention to be injected
this.commentEditor.focus();
}
}
replyToComment(): void {

View File

@ -6,231 +6,198 @@
id="tiptab-editor"
:data-actor-id="currentActor && currentActor.id"
>
<editor-menu-bar
<div
class="menubar bar-is-hidden"
v-if="isDescriptionMode"
:editor="editor"
v-slot="{ commands, isActive, focused }"
>
<div class="menubar bar-is-hidden" :class="{ 'is-focused': focused }">
<button
class="menubar__button"
:class="{ 'is-active': isActive.bold() }"
@click="commands.bold"
type="button"
>
<b-icon icon="format-bold" />
</button>
<button
class="menubar__button"
:class="{ 'is-active': isActive.italic() }"
@click="commands.italic"
type="button"
>
<b-icon icon="format-italic" />
</button>
<button
class="menubar__button"
:class="{ 'is-active': isActive.underline() }"
@click="commands.underline"
type="button"
>
<b-icon icon="format-underline" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': isActive.heading({ level: 1 }) }"
@click="commands.heading({ level: 1 })"
type="button"
>
<b-icon icon="format-header-1" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': isActive.heading({ level: 2 }) }"
@click="commands.heading({ level: 2 })"
type="button"
>
<b-icon icon="format-header-2" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': isActive.heading({ level: 3 }) }"
@click="commands.heading({ level: 3 })"
type="button"
>
<b-icon icon="format-header-3" />
</button>
<button
class="menubar__button"
@click="showLinkMenu(commands.link, isActive.link())"
:class="{ 'is-active': isActive.link() }"
type="button"
>
<b-icon icon="link" />
</button>
<button
class="menubar__button"
v-if="!isBasicMode"
@click="showImagePrompt(commands.image)"
type="button"
>
<b-icon icon="image" />
</button>
<button
class="menubar__button"
v-if="!isBasicMode"
:class="{ 'is-active': isActive.bullet_list() }"
@click="commands.bullet_list"
type="button"
>
<b-icon icon="format-list-bulleted" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': isActive.ordered_list() }"
@click="commands.ordered_list"
type="button"
>
<b-icon icon="format-list-numbered" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': isActive.blockquote() }"
@click="commands.blockquote"
type="button"
>
<b-icon icon="format-quote-close" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
@click="commands.undo"
type="button"
>
<b-icon icon="undo" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
@click="commands.redo"
type="button"
>
<b-icon icon="redo" />
</button>
</div>
</editor-menu-bar>
<editor-menu-bubble
v-if="isCommentMode"
:editor="editor"
:keep-in-bounds="true"
v-slot="{ commands, isActive, menu }"
>
<div
class="menububble"
:class="{ 'is-active': menu.isActive }"
:style="`left: ${menu.left}px; bottom: ${menu.bottom}px;`"
<button
class="menubar__button"
:class="{ 'is-active': editor.isActive('bold') }"
@click="editor.chain().focus().toggleBold().run()"
type="button"
>
<button
class="menububble__button"
:class="{ 'is-active': isActive.bold() }"
@click="commands.bold"
type="button"
>
<b-icon icon="format-bold" />
<span class="visually-hidden">{{ $t("Bold") }}</span>
</button>
<b-icon icon="format-bold" />
</button>
<button
class="menububble__button"
:class="{ 'is-active': isActive.italic() }"
@click="commands.italic"
type="button"
>
<b-icon icon="format-italic" />
<span class="visually-hidden">{{ $t("Italic") }}</span>
</button>
</div>
</editor-menu-bubble>
<button
class="menubar__button"
:class="{ 'is-active': editor.isActive('italic') }"
@click="editor.chain().focus().toggleItalic().run()"
type="button"
>
<b-icon icon="format-italic" />
</button>
<button
class="menubar__button"
:class="{ 'is-active': editor.isActive('underline') }"
@click="editor.chain().focus().toggleUnderline().run()"
type="button"
>
<b-icon icon="format-underline" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
@click="editor.chain().focus().toggleHeading({ level: 1 }).run()"
type="button"
>
<b-icon icon="format-header-1" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
@click="editor.chain().focus().toggleHeading({ level: 2 }).run()"
type="button"
>
<b-icon icon="format-header-2" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': editor.isActive('heading', { level: 3 }) }"
@click="editor.chain().focus().toggleHeading({ level: 3 }).run()"
type="button"
>
<b-icon icon="format-header-3" />
</button>
<button
class="menubar__button"
@click="showLinkMenu()"
:class="{ 'is-active': editor.isActive('link') }"
type="button"
>
<b-icon icon="link" />
</button>
<button
v-if="editor.isActive('link')"
class="menubar__button"
@click="editor.chain().focus().unsetLink().run()"
type="button"
>
<b-icon icon="link-off" />
</button>
<button
class="menubar__button"
v-if="!isBasicMode"
@click="showImagePrompt()"
type="button"
>
<b-icon icon="image" />
</button>
<button
class="menubar__button"
v-if="!isBasicMode"
:class="{ 'is-active': editor.isActive('bulletList') }"
@click="editor.chain().focus().toggleBulletList().run()"
type="button"
>
<b-icon icon="format-list-bulleted" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': editor.isActive('orderedList') }"
@click="editor.chain().focus().toggleOrderedList().run()"
type="button"
>
<b-icon icon="format-list-numbered" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
:class="{ 'is-active': editor.isActive('blockquote') }"
@click="editor.chain().focus().toggleBlockquote().run()"
type="button"
>
<b-icon icon="format-quote-close" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
@click="editor.chain().focus().undo().run()"
type="button"
>
<b-icon icon="undo" />
</button>
<button
v-if="!isBasicMode"
class="menubar__button"
@click="editor.chain().focus().redo().run()"
type="button"
>
<b-icon icon="redo" />
</button>
</div>
<bubble-menu
v-if="editor && isCommentMode"
class="bubble-menu"
:editor="editor"
:tippy-options="{ duration: 100 }"
>
<button
class="menububble__button"
:class="{ 'is-active': editor.isActive('bold') }"
@click="editor.chain().focus().toggleBold().run()"
type="button"
>
<b-icon icon="format-bold" />
<span class="visually-hidden">{{ $t("Bold") }}</span>
</button>
<button
class="menububble__button"
:class="{ 'is-active': editor.isActive('italic') }"
@click="editor.chain().focus().toggleItalic().run()"
type="button"
>
<b-icon icon="format-italic" />
<span class="visually-hidden">{{ $t("Italic") }}</span>
</button>
</bubble-menu>
<editor-content class="editor__content" :editor="editor" />
</div>
<div class="suggestion-list" v-show="showSuggestions" ref="suggestions">
<template v-if="hasResults">
<div
v-for="(actor, index) in filteredActors"
:key="actor.id"
class="media suggestion-list__item"
:class="{ 'is-selected': navigatedActorIndex === index }"
@click="selectActor(actor)"
>
<div class="media-left">
<figure class="image is-16x16" v-if="actor.avatar">
<img :src="actor.avatar.url" alt="" />
</figure>
</div>
<div class="media-content">
{{ actor.name }}
</div>
</div>
</template>
<div v-else class="suggestion-list__item is-empty">
{{ $t("No profiles found") }}
</div>
</div>
</div>
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
import { Editor, EditorContent, EditorMenuBar, EditorMenuBubble } from "tiptap";
import {
Blockquote,
HardBreak,
Heading,
OrderedList,
BulletList,
ListItem,
TodoItem,
TodoList,
Bold,
Code,
Italic,
Link,
Underline,
History,
Placeholder,
Mention,
} from "tiptap-extensions";
import tippy, { Instance, sticky } from "tippy.js";
import { SEARCH_PERSONS } from "../graphql/search";
import { Actor, IActor, IPerson } from "../types/actor";
import Image from "./Editor/Image";
import MaxSize from "./Editor/MaxSize";
import { Editor, EditorContent, BubbleMenu } from "@tiptap/vue-2";
import { defaultExtensions } from "@tiptap/starter-kit";
import Document from "@tiptap/extension-document";
import Paragraph from "@tiptap/extension-paragraph";
import Text from "@tiptap/extension-text";
import { IActor, IPerson, usernameWithDomain } from "../types/actor";
import CustomImage from "./Editor/Image";
import { UPLOAD_MEDIA } from "../graphql/upload";
import { listenFileUpload } from "../utils/upload";
import { CURRENT_ACTOR_CLIENT } from "../graphql/actor";
import { IComment } from "../types/comment.model";
import Mention from "@tiptap/extension-mention";
import MentionOptions from "./Editor/Mention";
import OrderedList from "@tiptap/extension-ordered-list";
import ListItem from "@tiptap/extension-list-item";
import Underline from "@tiptap/extension-underline";
import Link from "@tiptap/extension-link";
import CharacterCount from "@tiptap/extension-character-count";
@Component({
components: { EditorContent, EditorMenuBar, EditorMenuBubble },
components: { EditorContent, BubbleMenu },
apollo: {
currentActor: {
query: CURRENT_ACTOR_CLIENT,
@ -248,19 +215,6 @@ export default class EditorComponent extends Vue {
editor: Editor | null = null;
/**
* Editor Suggestions
*/
query!: string | null;
filteredActors: IActor[] = [];
suggestionRange!: Record<string, unknown> | null;
navigatedActorIndex = 0;
popup!: Instance[] | null;
get isDescriptionMode(): boolean {
return this.mode === "description" || this.isBasicMode;
}
@ -273,14 +227,6 @@ export default class EditorComponent extends Vue {
return this.isBasicMode;
}
get hasResults(): boolean {
return this.filteredActors.length > 0;
}
get showSuggestions(): boolean {
return (this.query || this.hasResults) as boolean;
}
get isBasicMode(): boolean {
return this.mode === "basic";
}
@ -295,138 +241,39 @@ export default class EditorComponent extends Vue {
mounted(): void {
this.editor = new Editor({
extensions: [
new Blockquote(),
new BulletList(),
new HardBreak(),
new Heading({ levels: [1, 2, 3] }),
new Mention({
items: () => [],
onEnter: ({
items,
query,
range,
command,
virtualNode,
}: {
items: any;
query: any;
range: any;
command: any;
virtualNode: any;
}) => {
this.query = query;
this.filteredActors = items;
this.suggestionRange = range;
this.renderPopup(virtualNode);
// we save the command for inserting a selected mention
// this allows us to call it inside of our custom popup
// via keyboard navigation and on click
this.insertMention = command;
},
/**
* is called when a suggestion has changed
*/
onChange: ({
items,
query,
range,
virtualNode,
}: {
items: any;
query: any;
range: any;
virtualNode: any;
}) => {
this.query = query;
this.filteredActors = items;
this.suggestionRange = range;
this.navigatedActorIndex = 0;
this.renderPopup(virtualNode);
},
/**
* is called when a suggestion is cancelled
*/
onExit: () => {
// reset all saved values
this.query = null;
this.filteredActors = [];
this.suggestionRange = null;
this.navigatedActorIndex = 0;
this.destroyPopup();
},
/**
* is called on every keyDown event while a suggestion is active
*/
onKeyDown: ({ event }: { event: KeyboardEvent }) => {
if (event.key === "ArrowUp") {
this.upHandler();
return true;
}
if (event.key === "ArrowDown") {
this.downHandler();
return true;
}
if (event.key === "Enter") {
this.enterHandler();
return true;
}
return false;
},
onFilter: async (items: any, query: string) => {
if (!query) {
return items;
}
const result = await this.$apollo.query({
query: SEARCH_PERSONS,
variables: {
searchText: query,
},
});
// TipTap doesn't handle async for onFilter, hence the following line.
this.filteredActors = result.data.searchPersons.elements;
return this.filteredActors;
},
Document,
Paragraph,
Text,
OrderedList,
ListItem,
Mention.configure(MentionOptions),
CustomImage,
Underline,
Link,
CharacterCount.configure({
limit: this.maxSize,
}),
new ListItem(),
new OrderedList(),
new TodoItem(),
new TodoList(),
new Link(),
new Bold(),
new Code(),
new Italic(),
new Underline(),
new History(),
new Placeholder({
emptyEditorClass: "is-empty",
emptyNodeText: this.$t("Write something…") as string,
showOnlyWhenEditable: false,
}),
new Image(),
new MaxSize({ maxSize: this.maxSize }),
...defaultExtensions(),
],
// eslint-disable-next-line @typescript-eslint/ban-types
onUpdate: ({ getHTML }: { getHTML: Function }) => {
this.$emit("input", getHTML());
content: this.value,
onUpdate: () => {
this.$emit("input", this.editor?.getHTML());
},
});
this.editor.setContent(this.value);
}
@Watch("value")
onValueChanged(val: string): void {
if (!this.editor) return;
if (val !== this.editor.getHTML()) {
this.editor.setContent(val);
this.editor.commands.setContent(val, false);
}
}
// eslint-disable-next-line @typescript-eslint/ban-types
showLinkMenu(command: Function, active: boolean): Function | undefined {
if (!this.editor) return undefined;
if (active) return command({ href: null });
/**
* Show a popup to get the link from the URL
*/
showLinkMenu(): void {
this.$buefy.dialog.prompt({
message: this.$t("Enter the link URL") as string,
inputAttrs: {
@ -434,112 +281,16 @@ export default class EditorComponent extends Vue {
},
trapFocus: true,
onConfirm: (value) => {
command({ href: value });
if (!this.editor) return;
this.editor.focus();
if (!this.editor) return undefined;
this.editor.chain().focus().setLink({ href: value }).run();
},
});
return undefined;
}
upHandler(): void {
this.navigatedActorIndex =
(this.navigatedActorIndex + this.filteredActors.length - 1) %
this.filteredActors.length;
}
/**
* navigate to the next item
* if it's the last item, navigate to the first one
*/
downHandler(): void {
this.navigatedActorIndex =
(this.navigatedActorIndex + 1) % this.filteredActors.length;
}
enterHandler(): void {
const actor = this.filteredActors[this.navigatedActorIndex];
if (actor) {
this.selectActor(actor);
}
}
/**
* we have to replace our suggestion text with a mention
* so it's important to pass also the position of your suggestion text
* @param actor IActor
*/
selectActor(actor: IActor): void {
const actorModel = new Actor(actor);
this.insertMention({
range: this.suggestionRange,
attrs: {
id: actorModel.id,
// usernameWithDomain returns with a @ prefix and tiptap adds one itself
label: actorModel.usernameWithDomain().substring(1),
},
});
if (!this.editor) return;
this.editor.focus();
}
/** We use this to programatically insert an actor mention when creating a reply to comment */
replyToComment(comment: IComment): void {
if (!comment.actor) return;
const actorModel = new Actor(comment.actor);
if (!this.editor) return;
this.editor.commands.mention({
id: actorModel.id,
label: actorModel.usernameWithDomain().substring(1),
});
this.editor.focus();
}
/**
* renders a popup with suggestions
* tiptap provides a virtualNode object for using popper.js (or tippy.js) for popups
* @param node
*/
renderPopup(node: Element): void {
if (this.popup) {
return;
}
this.popup = tippy("#mobilizon", {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
getReferenceClientRect: node.getBoundingClientRect,
appendTo: () => document.body,
content: this.$refs.suggestions as HTMLElement,
trigger: "mouseenter",
interactive: true,
sticky: true, // make sure position of tippy is updated when content changes
plugins: [sticky],
showOnCreate: true,
theme: "dark",
placement: "top-start",
inertia: true,
duration: [400, 200],
}) as Instance[];
}
destroyPopup(): void {
if (this.popup) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this.popup[0].destroy();
this.popup = null;
}
if (this.observer) {
this.observer.disconnect();
}
}
/**
* Show a file prompt, upload picture and insert it into editor
* @param command
*/
// eslint-disable-next-line @typescript-eslint/ban-types
async showImagePrompt(command: Function): Promise<void> {
async showImagePrompt(): Promise<void> {
const image = await listenFileUpload();
try {
const { data } = await this.$apollo.mutate({
@ -549,11 +300,17 @@ export default class EditorComponent extends Vue {
name: image.name,
},
});
if (data.uploadMedia && data.uploadMedia.url) {
command({
src: data.uploadMedia.url,
"data-media-id": data.uploadMedia.id,
});
if (data.uploadMedia && data.uploadMedia.url && this.editor) {
this.editor
.chain()
.focus()
.setImage({
src: data.uploadMedia.url,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
"data-media-id": data.uploadMedia.id,
})
.run();
}
} catch (error) {
console.error(error);
@ -563,14 +320,36 @@ export default class EditorComponent extends Vue {
}
}
beforeDestroy(): void {
/**
* We use this to programatically insert an actor mention when creating a reply to comment
*/
replyToComment(actor: IActor): void {
if (!this.editor) return;
this.destroyPopup();
this.editor.destroy();
this.editor
.chain()
.focus()
.insertContent({
type: "mention",
attrs: {
id: usernameWithDomain(actor),
},
})
.insertContent(" ")
.run();
}
focus(): void {
this.editor?.chain().focus("end");
}
beforeDestroy(): void {
this.editor?.destroy();
}
}
</script>
<style lang="scss">
@import "./Editor/style.scss";
$color-black: #000;
$color-white: #eee;
@ -643,8 +422,6 @@ $color-white: #eee;
}
}
word-wrap: break-word;
h1 {
font-size: 2em;
}
@ -657,10 +434,6 @@ $color-white: #eee;
font-size: 1.25em;
}
* {
caret-color: currentColor;
}
ul,
ol {
padding-left: 1rem;
@ -694,58 +467,27 @@ $color-white: #eee;
}
}
.menububble {
position: absolute;
.bubble-menu {
display: flex;
z-index: 20;
background: $color-black;
border-radius: 5px;
padding: 0.3rem;
margin-bottom: 0.5rem;
transform: translateX(-50%);
visibility: hidden;
opacity: 0;
transition: opacity 0.2s, visibility 0.2s;
background-color: #0d0d0d;
padding: 0.2rem;
border-radius: 0.5rem;
&.is-active {
opacity: 1;
visibility: visible;
}
&__button {
display: inline-flex;
background: transparent;
border: 0;
color: $color-white;
padding: 0.2rem 0.5rem;
margin-right: 0.2rem;
border-radius: 3px;
button {
border: none;
background: none;
color: #fff;
font-size: 0.85rem;
font-weight: 500;
padding: 0 0.2rem;
opacity: 0.6;
cursor: pointer;
&:last-child {
margin-right: 0;
}
&:hover {
background-color: rgba($color-white, 0.1);
}
&:hover,
&.is-active {
background-color: rgba($color-white, 0.2);
opacity: 1;
}
}
&__form {
display: flex;
align-items: center;
}
&__input {
font: inherit;
border: none;
background: transparent;
color: $color-white;
}
}
.suggestion-list {

View File

@ -1,70 +1,32 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { Node } from "tiptap";
import { UPLOAD_MEDIA } from "@/graphql/upload";
import apolloProvider from "@/vue-apollo";
import ApolloClient from "apollo-client";
import { NormalizedCacheObject } from "apollo-cache-inmemory";
import { NodeType, NodeSpec } from "prosemirror-model";
import { EditorState, Plugin, TextSelection } from "prosemirror-state";
import { DispatchFn } from "tiptap-commands";
import { Plugin } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import Image from "@tiptap/extension-image";
/* eslint-disable class-methods-use-this */
export default class Image extends Node {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
get name() {
return "image";
}
get schema(): NodeSpec {
const CustomImage = Image.extend({
name: "image",
addAttributes() {
return {
inline: true,
attrs: {
src: {},
alt: {
default: null,
},
title: {
default: null,
},
"data-media-id": {},
src: {
default: null,
},
alt: {
default: null,
},
title: {
default: null,
},
"data-media-id": {
default: null,
},
group: "inline",
draggable: true,
parseDOM: [
{
tag: "img",
getAttrs: (dom: any) => ({
src: dom.getAttribute("src"),
title: dom.getAttribute("title"),
alt: dom.getAttribute("alt"),
"data-media-id": dom.getAttribute("data-media-id"),
}),
},
],
toDOM: (node: any) => ["img", node.attrs],
};
}
commands({ type }: { type: NodeType }): any {
return (attrs: { [key: string]: string }) => (
state: EditorState,
dispatch: DispatchFn
) => {
const { selection }: { selection: TextSelection } = state;
const position = selection.$cursor
? selection.$cursor.pos
: selection.$to.pos;
const node = type.create(attrs);
const transaction = state.tr.insert(position, node);
dispatch(transaction);
};
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
get plugins() {
},
addProseMirrorPlugins() {
return [
new Plugin({
props: {
@ -129,5 +91,7 @@ export default class Image extends Node {
},
}),
];
}
}
},
});
export default CustomImage;

View File

@ -1,39 +0,0 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
import { Extension, Plugin } from "tiptap";
export default class MaxSize extends Extension {
// eslint-disable-next-line class-methods-use-this
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
get name() {
return "maxSize";
}
// eslint-disable-next-line class-methods-use-this
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
get defaultOptions() {
return {
maxSize: null,
};
}
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
get plugins() {
return [
new Plugin({
appendTransaction: (transactions, oldState, newState) => {
const max = this.options.maxSize;
const oldLength = oldState.doc.content.size;
const newLength = newState.doc.content.size;
if (newLength > max && newLength > oldLength) {
const newTr = newState.tr;
newTr.insertText("", max + 1, newLength);
return newTr;
}
},
}),
];
}
}

View File

@ -0,0 +1,79 @@
import { SEARCH_PERSONS } from "@/graphql/search";
import { VueRenderer } from "@tiptap/vue-2";
import tippy from "tippy.js";
import MentionList from "./MentionList.vue";
import ApolloClient from "apollo-client";
import { NormalizedCacheObject } from "apollo-cache-inmemory";
import apolloProvider from "@/vue-apollo";
import { IPerson } from "@/types/actor";
import pDebounce from "p-debounce";
const client = apolloProvider.defaultClient as ApolloClient<NormalizedCacheObject>;
const fetchItems = async (query: string): Promise<IPerson[]> => {
const result = await client.query({
query: SEARCH_PERSONS,
variables: {
searchText: query,
},
});
// TipTap doesn't handle async for onFilter, hence the following line.
return result.data.searchPersons.elements;
};
const debouncedFetchItems = pDebounce(fetchItems, 200);
const mentionOptions: Partial<any> = {
HTMLAttributes: {
class: "mention",
},
suggestion: {
items: async (query: string): Promise<IPerson[]> => {
if (query === "") {
return [];
}
return await debouncedFetchItems(query);
},
render: () => {
let component: VueRenderer;
let popup: any;
return {
onStart: (props: any) => {
component = new VueRenderer(MentionList, {
parent: this,
propsData: props,
});
popup = tippy("body", {
getReferenceClientRect: props.clientRect,
appendTo: () => document.body,
content: component.element,
showOnCreate: true,
interactive: true,
trigger: "manual",
placement: "bottom-start",
});
},
onUpdate(props: any) {
component.updateProps(props);
popup[0].setProps({
getReferenceClientRect: props.clientRect,
});
},
onKeyDown(props: any) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return component.ref?.onKeyDown(props);
},
onExit() {
popup[0].destroy();
component.destroy();
},
};
},
},
};
export default mentionOptions;

View File

@ -0,0 +1,106 @@
<template>
<div class="items">
<button
class="item"
:class="{ 'is-selected': index === selectedIndex }"
v-for="(item, index) in items"
:key="index"
@click="selectItem(index)"
>
<actor-card :actor="item" />
</button>
</div>
</template>
<script lang="ts">
import { Vue, Component, Prop, Watch } from "vue-property-decorator";
import { displayName, usernameWithDomain } from "@/types/actor/actor.model";
import { IPerson } from "@/types/actor";
import ActorCard from "../../components/Account/ActorCard.vue";
@Component({
components: {
ActorCard,
},
})
export default class MentionList extends Vue {
@Prop({ type: Array, required: true }) items!: Array<IPerson>;
@Prop({ type: Function, required: true }) command!: any;
selectedIndex = 0;
displayName = displayName;
@Watch("items")
watchItems(): void {
this.selectedIndex = 0;
}
onKeyDown({ event }: { event: KeyboardEvent }): boolean {
if (event.key === "ArrowUp") {
this.upHandler();
return true;
}
if (event.key === "ArrowDown") {
this.downHandler();
return true;
}
if (event.key === "Enter") {
this.enterHandler();
return true;
}
return false;
}
upHandler(): void {
this.selectedIndex =
(this.selectedIndex + this.items.length - 1) % this.items.length;
}
downHandler(): void {
this.selectedIndex = (this.selectedIndex + 1) % this.items.length;
}
enterHandler(): void {
this.selectItem(this.selectedIndex);
}
selectItem(index: number): void {
const item = this.items[index];
if (item) {
this.command({ id: usernameWithDomain(item) });
}
}
}
</script>
<style lang="scss" scoped>
.items {
position: relative;
border-radius: 0.25rem;
background: white;
color: rgba(black, 0.8);
overflow: hidden;
font-size: 0.9rem;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0px 10px 20px rgba(0, 0, 0, 0.1);
}
.item {
display: block;
width: 100%;
text-align: left;
background: transparent;
border: none;
padding: 0.5rem 0.75rem;
&.is-selected,
&:hover {
color: $background-color;
background: rgba($background-color, 0.1);
}
}
</style>

View File

@ -0,0 +1,58 @@
/**
* From https://www.tiptap.dev/api/editor/#inject-css
* https://github.com/ueberdosis/tiptap/blob/main/packages/core/src/style.ts
*/
.ProseMirror {
position: relative;
word-wrap: break-word;
white-space: pre-wrap;
-webkit-font-variant-ligatures: none;
font-variant-ligatures: none;
& [contenteditable="false"] {
white-space: normal;
}
& [contenteditable="false"] [contenteditable="true"] {
white-space: pre-wrap;
}
pre {
white-space: pre-wrap;
}
}
.ProseMirror-gapcursor {
display: none;
pointer-events: none;
position: absolute;
&:after {
content: "";
display: block;
position: absolute;
top: -2px;
width: 20px;
border-top: 1px solid black;
animation: ProseMirror-cursor-blink 1.1s steps(2, start) infinite;
}
}
@keyframes ProseMirror-cursor-blink {
to {
visibility: hidden;
}
}
.ProseMirror-hideselection * {
&::selection {
background: transparent;
}
&::-moz-selection {
background: transparent;
}
caret-color: transparent;
}
.ProseMirror-focused .ProseMirror-gapcursor {
display: block;
}
.tippy-box[data-animation="fade"][data-state="hidden"] {
opacity: 0;
}

View File

@ -31,7 +31,6 @@ div.eventMetadataBlock {
margin-bottom: 1.75rem;
p {
flex: 1;
overflow: hidden;
&.padding-left {

View File

@ -138,7 +138,6 @@
"Click to upload": "Haz clic para subir (upload)",
"Close": "Cerrar",
"Close comments for all (except for admins)": "Cerrar comentarios para todos (excepto para administradores)",
"Events nearby": "Eventos cercanos",
"Closed": "Cerrado",
"Collections": "Colecciones",
"Comment deleted": "Comentario borrado",
@ -294,6 +293,7 @@
"Event {eventTitle} deleted": "Evento {eventTitle} eliminado",
"Event {eventTitle} reported": "Evento {eventTitle} declarado",
"Events": "Eventos",
"Events nearby": "Eventos cercanos",
"Events tagged with {tag}": "Eventos etiquetados con {tag}",
"Everything": "Todo",
"Ex: mobilizon.fr": "Ej: mobilizon.fr",
@ -521,6 +521,7 @@
"No moderation logs yet": "Aún no hay registros de moderación",
"No more activity to display.": "No hay más actividad para mostrar.",
"No notification settings yet": "Aún no hay configuración de notificaciones",
"No one is participating|One person participating|{going} people participating": "Nadie está participando|Una persona participando|{van} personas participando",
"No ongoing todos": "No hay tareas pendientes (\"to-do\") en marcha",
"No open reports yet": "Aún no hay informes abiertos",
"No participant matches the filters": "Ningún participante coincide con los filtros",
@ -601,7 +602,7 @@
"Participations": "Participaciones",
"Password": "Contraseña",
"Password (confirmation)": "Contraseña (confirmación)",
"Password reset": "Restablecimiento de contraseña",
"Password reset": "Restabler la contraseña",
"Past events": "Eventos pasados",
"Pending": "Pendiente",
"Personal feeds": "Flujos personales",
@ -1100,10 +1101,15 @@
"{moderator} added a note on {report}": "{moderator} agregó una nota en{report}",
"{moderator} closed {report}": "{moderator} cerrado {report}",
"{moderator} deleted an event named \"{title}\"": "{moderator} eliminó un evento llamado \"{title}\"",
"{moderator} has deleted a comment from {author}": "{moderator} ha eliminado un comentario de {author}",
"{moderator} has deleted a comment from {author} under the event {event}": "{moderator} ha eliminado un comentario de {author} según el evento {event}",
"{moderator} has deleted user {user}": "{moderator} ha eliminado el usuario {user}",
"{moderator} has done an unknown action": "{moderator} ha realizado una acción desconocida",
"{moderator} has unsuspended group {profile}": "{moderator} ha canceladola suspension del grupo {profile}",
"{moderator} has unsuspended profile {profile}": "{moderator} ha rehabilitado el perfil {profile}",
"{moderator} marked {report} as resolved": "{moderator} marcado {report} como resuelto",
"{moderator} reopened {report}": "{moderator} reabierto {report}",
"{moderator} suspended group {profile}": "{moderator} ha suspendido el grupo {perfil}",
"{moderator} suspended profile {profile}": "{moderator} perfil suspendido {profile}",
"{nb} km": "{nb} km",
"{number} members": "{number} miembros",

View File

@ -131,7 +131,6 @@
"Click to upload": "Preme para subir",
"Close": "Pechar",
"Close comments for all (except for admins)": "Pechar comentarios para todos (excepto admins)",
"Events nearby": "Pechar eventos",
"Closed": "Pechado",
"Comment deleted": "Comentario eliminado",
"Comment from @{username} reported": "Comentario de @{username} denunciado",
@ -278,6 +277,7 @@
"Event {eventTitle} deleted": "Eliminado o evento {eventTitle}",
"Event {eventTitle} reported": "Denunciado o evento {eventTitle}",
"Events": "Eventos",
"Events nearby": "Pechar eventos",
"Events tagged with {tag}": "Eventos etiquetados con {tag}",
"Everything": "Todo",
"Ex: mobilizon.fr": "Ex: mobilizon.fr",
@ -493,6 +493,7 @@
"No message": "Sen mensaxe",
"No moderation logs yet": "Sen rexistros da moderación",
"No more activity to display.": "Sen máis actividade que amosar.",
"No one is participating|One person participating|{going} people participating": "Ninguén está a participar|Unha persoa participa|{going} persoas participan",
"No open reports yet": "Aínda non se presentaron denuncias",
"No participant matches the filters": "Ningún participante para estos filtros",
"No participant to approve|Approve participant|Approve {number} participants": "Sen participantes que aprobar|Aprobar participante|Aprobar {number} participantes",
@ -1018,10 +1019,15 @@
"{moderator} added a note on {report}": "{moderator} engadeu unha nota a {report}",
"{moderator} closed {report}": "{moderator} pechou {report}",
"{moderator} deleted an event named \"{title}\"": "{moderator} eliminou o evento de nome \"{title}\"",
"{moderator} has deleted a comment from {author}": "{moderator} eleminou o comentario de {author}",
"{moderator} has deleted a comment from {author} under the event {event}": "{moderator} eliminou o comentario de {author} no evento {event}",
"{moderator} has deleted user {user}": "{moderator} eliminou a usuaria {user}",
"{moderator} has done an unknown action": "{moderator} realizou unha acción descoñecida",
"{moderator} has unsuspended group {profile}": "{moderator} retirou a suspensión ao grupo {profile}",
"{moderator} has unsuspended profile {profile}": "{moderator} reactivou o perfil {profile}",
"{moderator} marked {report} as resolved": "{moderator} marcou {report} como resolta",
"{moderator} reopened {report}": "{moderator} reabreu {report}",
"{moderator} suspended group {profile}": "{moderator} suspendeu o grupo {profile}",
"{moderator} suspended profile {profile}": "{moderator} suspendeu o perfil {profile}",
"{nb} km": "{nb} km",
"{number} members": "{number} membros",

View File

@ -452,6 +452,7 @@
"No message": "Нет сообщений",
"No moderation logs yet": "Журналов модерования пока нет",
"No more activity to display.": "Больше нет действия для отображения.",
"No one is participating|One person participating|{going} people participating": "Никто не участвует|Один человек участвует|{going} человек участвуют",
"No open reports yet": "Пока нет открытых отчётов",
"No participant matches the filters": "Ни один участник не соответствует критериям",
"No participant to approve|Approve participant|Approve {number} participants": "Нет участников для одобрения | Принять участника | Принять {number} участников",
@ -941,10 +942,15 @@
"{moderator} added a note on {report}": "{moderator} добавил примечание к {report}",
"{moderator} closed {report}": "{moderator} закрыл {report}",
"{moderator} deleted an event named \"{title}\"": "{moderator} удалил мероприятие с названием \"{title}\"",
"{moderator} has deleted a comment from {author}": "{moderator} удалил комментарий от {author}",
"{moderator} has deleted a comment from {author} under the event {event}": "{moderator} удалил комментарий от {author} под мероприятием {event}",
"{moderator} has deleted user {user}": "{moderator} удалил пользователя {user}",
"{moderator} has done an unknown action": "{moderator} совершил неизвестное действие",
"{moderator} has unsuspended group {profile}": "{moderator} разблокировал группу {profile}",
"{moderator} has unsuspended profile {profile}": "{modeator} снял блокировку профиля {profile}",
"{moderator} marked {report} as resolved": "{moderator} пометил {report} как решённый",
"{moderator} reopened {report}": "{moderator} повторно открыл {report}",
"{moderator} suspended group {profile}": "{moderator} заблокировал группу {profile}",
"{moderator} suspended profile {profile}": "{moderator} заблокировал профиль {profile}",
"{nb} km": "{nb} км",
"{number} members": "{number} участников",

View File

@ -52,9 +52,7 @@ export class Actor implements IActor {
}
public displayName(): string {
return this.name != null && this.name !== ""
? this.name
: this.usernameWithDomain();
return displayName(this);
}
}
@ -68,6 +66,12 @@ export function usernameWithDomain(actor: IActor, force = false): string {
return actor.preferredUsername;
}
export function displayName(actor: IActor): string {
return actor.name != null && actor.name !== ""
? actor.name
: usernameWithDomain(actor);
}
export function displayNameAndUsername(actor: IActor): string {
if (actor.name) {
return `${actor.name} (@${usernameWithDomain(actor)})`;

View File

@ -1,42 +0,0 @@
declare module "tiptap-commands" {
import { EditorView } from "prosemirror-view";
import { Transaction, EditorState, Plugin } from "prosemirror-state";
import { InputRule } from "prosemirror-inputrules";
import { NodeType, MarkType } from "prosemirror-model";
export interface DispatchFn {
(tr: Transaction): boolean;
}
export interface Command {
(...params: any[]): CommandFunction;
}
export interface CommandFunction {
(
state: EditorState,
dispatch: DispatchFn | undefined,
view: EditorView
): boolean;
}
export function toggleWrap(type: NodeType): Command;
export function wrappingInputRule(
regexp: RegExp,
nodeType: NodeType,
getAttrs?: (arg: {} | string[]) => object | undefined,
joinPredicate?: (strs: string[], node: Node) => boolean
): InputRule;
export function toggleMark(
type: MarkType,
attrs?: { [key: string]: any }
): Command;
export function pasteRule(
regexp: RegExp,
type: string,
getAttrs: (() => { [key: string]: any }) | { [key: string]: any }
): Plugin;
}

View File

@ -1,62 +0,0 @@
declare module "tiptap-extensions" {
import { Extension, Node, Mark } from "tiptap";
export interface PlaceholderOptions {
emptyNodeClass?: string;
emptyNodeText?: string;
showOnlyWhenEditable?: boolean;
showOnlyCurrent?: boolean;
emptyEditorClass: string;
}
export class Placeholder extends Extension {
constructor(options?: PlaceholderOptions);
}
export interface TrailingNodeOptions {
/**
* Node to be at the end of the document
*
* defaults to 'paragraph'
*/
node: string;
/**
* The trailing node will not be displayed after these specified nodes.
*/
notAfter: string[];
}
export class TrailingNode extends Extension {
constructor(options?: TrailingNodeOptions);
}
export interface HeadingOptions {
levels?: number[];
}
export class History extends Extension {}
export class Underline extends Mark {}
export class Strike extends Mark {}
export class Italic extends Mark {}
export class Bold extends Mark {}
export class BulletList extends Node {}
export class ListItem extends Node {}
export class OrderedList extends Node {}
export class HardBreak extends Node {}
export class Blockquote extends Node {}
export class CodeBlock extends Node {}
export class TodoItem extends Node {}
export class Code extends Node {}
export class HorizontalRule extends Node {}
export class Link extends Node {}
export class TodoList extends Node {}
export class Heading extends Node {
constructor(options?: HeadingOptions);
}
export class Table extends Node {}
export class TableCell extends Node {}
export class TableRow extends Node {}
export class TableHeader extends Node {}
export class Mention extends Node {}
}

View File

@ -1,331 +0,0 @@
declare module "tiptap" {
import {
MarkSpec,
MarkType,
Node as ProsemirrorNode,
NodeSpec,
NodeType,
ParseOptions,
Schema,
} from "prosemirror-model";
import { EditorState, Plugin, Transaction } from "prosemirror-state";
import { Command, CommandFunction } from "tiptap-commands";
import { EditorProps, EditorView } from "prosemirror-view";
import { VueConstructor } from "vue";
export const EditorContent: VueConstructor;
export const EditorMenuBubble: VueConstructor;
export const EditorMenuBar: VueConstructor;
export type ExtensionOption = Extension | Node | Mark;
// there are some props available
// `node` is a Prosemirror Node Object
// `updateAttrs` is a function to update attributes defined in `schema`
// `view` is the ProseMirror view instance
// `options` is an array of your extension options
// `selected`
export interface NodeView {
/** A Prosemirror Node Object */
node?: ProsemirrorNode;
/** A function to update attributes defined in `schema` */
updateAttrs?: (attrs: { [key: string]: any }) => any;
/** The ProseMirror view instance */
view?: EditorView;
/** An array of your extension options */
options?: { [key: string]: any };
/** Whether the node view is selected */
selected?: boolean;
}
export type CommandGetter =
| { [key: string]: (() => Command) | Command }
| (() => Command)
| Command
| (() => Command)[];
export interface EditorUpdateEvent {
state: EditorState;
getHTML: () => string;
getJSON: () => object;
transaction: Transaction;
}
export interface EditorOptions {
editorProps?: EditorProps;
/** defaults to true */
editable?: boolean;
/** defaults to false */
autoFocus?: boolean;
extensions?: ExtensionOption[];
content?: Object | string;
emptyDocument?: {
type: "doc";
content: [
{
type: "paragraph";
}
];
};
/** defaults to false */
useBuiltInExtensions?: boolean;
/** defaults to false */
disableInputRules?: boolean;
/** defaults to false */
disablePasteRules?: boolean;
dropCursor?: {};
parseOptions?: ParseOptions;
/** defaults to true */
injectCSS?: boolean;
onInit?: ({
view,
state,
}: {
view: EditorView;
state: EditorState;
}) => void;
onTransaction?: (event: EditorUpdateEvent) => void;
onUpdate?: (event: EditorUpdateEvent) => void;
onFocus?: ({
event,
state,
view,
}: {
event: FocusEvent;
state: EditorState;
view: EditorView;
}) => void;
onBlur?: ({
event,
state,
view,
}: {
event: FocusEvent;
state: EditorState;
view: EditorView;
}) => void;
onPaste?: (...args: any) => void;
onDrop?: (...args: any) => void;
}
export class Editor {
commands: { [key: string]: Command };
defaultOptions: { [key: string]: any };
element: Element;
extensions: Extension[];
inputRules: any[];
keymaps: any[];
marks: Mark[];
nodes: Node[];
pasteRules: any[];
plugins: Plugin[];
schema: Schema;
state: EditorState;
view: EditorView;
activeMarks: { [markName: string]: () => boolean };
activeNodes: { [nodeName: string]: () => boolean };
activeMarkAttrs: { [markName: string]: { [attr: string]: any } };
/**
* Creates an [Editor]
* @param options - An object of Editor options.
*/
constructor(options?: EditorOptions);
/**
* Replace the current content. You can pass an HTML string or a JSON document that matches the editor's schema.
* @param content Defaults to {}.
* @param emitUpdate Defaults to false.
*/
setContent(content?: string | object, emitUpdate?: boolean): void;
/**
* Clears the current editor content.
*
* @param emitUpdate Whether or not the change should trigger the onUpdate callback.
*/
clearContent(emitUpdate?: boolean): void;
/**
* Overwrites the current editor options.
* @param options Options an object of Editor options
*/
setOptions(options: EditorOptions): void;
/**
* Register a ProseMirror plugin.
* @param plugin
*/
registerPlugin(plugin: Plugin): void;
/** Get the current content as JSON. */
getJSON(): {};
/** Get the current content as HTML. */
getHTML(): string;
/** Focus the editor */
focus(): void;
/** Removes the focus from the editor. */
blur(): void;
/** Destroy the editor and free all Prosemirror-related objects from memory.
* You should always call this method on beforeDestroy() lifecycle hook of the Vue component wrapping the editor.
*/
destroy(): void;
on(event: string, callbackFn: (params: any) => void): void;
off(event: string, callbackFn: (params: any) => void): void;
getMarkAttrs(markName: string): { [attributeName: string]: any };
}
export class Extension<Options = any> {
/** Define a name for your extension */
name?: string | null;
/** Define some default options.The options are available as this.$options. */
defaultOptions?: Options;
/** Define a list of Prosemirror plugins. */
plugins?: Plugin[];
/** Called when options of extension are changed via editor.extensions.options */
update?: (view: EditorView) => any;
/** Options for that are either passed in from the extension constructor or set by defaultOptions() */
options?: Options;
constructor(options?: Options);
/** Define some keybindings. */
keys?({
schema,
}: {
schema: Schema | NodeSpec | MarkSpec;
}): { [keyCombo: string]: CommandFunction };
/** Define commands. */
commands?({
schema,
attrs,
}: {
schema: Schema | NodeSpec | MarkSpec;
attrs: { [key: string]: string };
}): CommandGetter;
inputRules?({ schema }: { schema: Schema }): any[];
pasteRules?({ schema }: { schema: Schema }): Plugin[];
}
export class Node<V extends NodeView = any> extends Extension {
schema?: NodeSpec;
/** Reference to a view component constructor
* See https://stackoverflow.com/questions/38311672/generic-and-typeof-t-in-the-parameters
*/
view?: { new (): V };
commands?({
type,
schema,
attrs,
}: {
type: NodeType;
schema: NodeSpec;
attrs: { [key: string]: string };
}): CommandGetter;
keys?({
type,
schema,
}: {
type: NodeType;
schema: NodeSpec;
}): { [keyCombo: string]: CommandFunction };
inputRules?({ type, schema }: { type: NodeType; schema: Schema }): any[];
pasteRules?({ type, schema }: { type: NodeType; schema: Schema }): Plugin[];
}
export class Mark<V extends NodeView = any> extends Extension {
schema?: MarkSpec;
/** Reference to a view component constructor
* See https://stackoverflow.com/questions/38311672/generic-and-typeof-t-in-the-parameters
*/
view?: { new (): V };
commands?({
type,
schema,
attrs,
}: {
type: MarkType;
schema: MarkSpec;
attrs: { [key: string]: string };
}): CommandGetter;
keys?({
type,
schema,
}: {
type: MarkType;
schema: MarkSpec;
}): { [keyCombo: string]: CommandFunction };
inputRules?({ type, schema }: { type: MarkType; schema: Schema }): any[];
pasteRules?({ type, schema }: { type: MarkType; schema: Schema }): Plugin[];
}
export class Text extends Node {}
export class Paragraph extends Node {}
export class Doc extends Node {}
/** A set of commands registered to the editor. */
export interface EditorCommandSet {
[key: string]: Command;
}
/**
* The properties passed into <editor-menu-bar /> component
*/
export interface MenuData {
/** Whether the editor has focus. */
focused: boolean;
/** Function to focus the editor. */
focus: () => void;
/** A set of commands registered. */
commands: EditorCommandSet;
/** Check whether a node or mark is currently active. */
isActive: IsActiveChecker;
/** A function to get all mark attributes of the current selection. */
getMarkAttrs: (markName: string) => { [attributeName: string]: any };
}
export interface FloatingMenuData extends MenuData {
/** An object for positioning the menu. */
menu: MenuDisplayData;
}
/**
* A data object passed to a menu bubble to help it determine its position
* and visibility.
*/
export interface MenuDisplayData {
/** Left position of the cursor. */
left: number;
/** Bottom position of the cursor. */
bottom: number;
/** Whether or not there is an active selection. */
isActive: boolean;
}
/**
* A map containing functions to check if a node/mark is currently selected.
* The name of the node/mark is used as the key.
*/
export interface IsActiveChecker {
[name: string]: () => boolean;
}
}

View File

@ -1294,6 +1294,230 @@
ejs "^2.6.1"
magic-string "^0.25.0"
"@tiptap/core@^2.0.0-beta.41":
version "2.0.0-beta.41"
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.41.tgz#007199818fb158bbc40ef353b59f6740500e1b72"
integrity sha512-TkopvbzEfYMztcAiWpPMvYM9X8jFrzOA29wqCk894bSsiaQQHfs3EESCMEFjxYfXF6wyAZLz0Br4p6SuWKIHrQ==
dependencies:
"@types/prosemirror-commands" "^1.0.4"
"@types/prosemirror-inputrules" "^1.0.4"
"@types/prosemirror-keymap" "^1.0.4"
"@types/prosemirror-model" "^1.13.0"
"@types/prosemirror-schema-list" "^1.0.3"
"@types/prosemirror-state" "^1.2.6"
"@types/prosemirror-transform" "^1.1.2"
"@types/prosemirror-view" "^1.17.1"
prosemirror-commands "^1.1.7"
prosemirror-inputrules "^1.1.3"
prosemirror-keymap "^1.1.3"
prosemirror-model "^1.14.1"
prosemirror-schema-list "^1.1.4"
prosemirror-state "^1.3.4"
prosemirror-transform "^1.3.2"
prosemirror-view "^1.18.2"
"@tiptap/extension-blockquote@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.6.tgz#7670998307e88a0d0edf59558355a9328a6acec7"
integrity sha512-DOtr1Iy+wdyX2lrSX9KF6BaHvi0Sxg5tWfrAVHxPU7tCfxt33Xp6Ym97fyuZLlwUIbrzsy/DqBkdTYQ5v+CPMA==
dependencies:
prosemirror-inputrules "^1.1.3"
"@tiptap/extension-bold@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.6.tgz#347ddb7ad726d369337299b3800367815106de7f"
integrity sha512-hFxVQZcXWBCaCTCG3PJONhvTwoVGq/fJAQuPrYlI18z124Rhx6DeBkPG0FSwQgBeuJyezi4Jz61onkc48jwmSA==
"@tiptap/extension-bubble-menu@^2.0.0-beta.9":
version "2.0.0-beta.9"
resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.9.tgz#bbf6b819c7edd78f1dbc347f3d102f316928c385"
integrity sha512-GGxHwurQ6PediGy2b6q5at73CRznD6M6f1OSSuFVoIm2Q+FQMOECXKqLHpIOuHke6zYJpaAp1SfdX87/Zs5qaQ==
dependencies:
prosemirror-state "^1.3.4"
prosemirror-view "^1.18.2"
tippy.js "^6.3.1"
"@tiptap/extension-bullet-list@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.6.tgz#3830f4a6355f84061929085603f5423ae448d346"
integrity sha512-uO2t1CUc2Puq23c06xJvK9Imh895j1fsTJKJfEiSPDVMGrS3+tGOnQ2f9Fc5IOJITZZzFOpKnxRHC9AS5DySmg==
dependencies:
prosemirror-inputrules "^1.1.3"
"@tiptap/extension-character-count@^2.0.0-beta.5":
version "2.0.0-beta.5"
resolved "https://registry.yarnpkg.com/@tiptap/extension-character-count/-/extension-character-count-2.0.0-beta.5.tgz#a1ad655af90fc0f9770d7bdcf72be57a04dac205"
integrity sha512-zD+K0YrmQL34nIDklMfTDG/cR2sHcj6Pog4EYRPfudBCJTC/lXEEZO6IMoKvbzdh86+UDo1qdwaH1pfoJ91LCw==
"@tiptap/extension-code-block@^2.0.0-beta.8":
version "2.0.0-beta.8"
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.8.tgz#f26d8992be6ea78f34a7db52b0a706293d19922d"
integrity sha512-lSeC98qJ8szMUgp/hFZFMqDfV/boGpMN3kek98BR6dCI8QSHvZWpHrQ8n9dyc8NEGAuvBhP/lu0PSD1TzYwkig==
dependencies:
prosemirror-inputrules "^1.1.3"
"@tiptap/extension-code@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.6.tgz#c35f0a8b1f3fe05b5ec9ced5aea6c9b093073d09"
integrity sha512-i0s3yTSdONUOp0fM/VrdSQfdj0SsqTPyP2ev2Ji1KgzGQ49Rw8gewT6RorHMwvMdv+F5+wE47wI2rcdUjpNwMQ==
"@tiptap/extension-document@^2.0.0-beta.5":
version "2.0.0-beta.5"
resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.5.tgz#595c25879eb39f26cdb58e9b01ff5e48d65b2e4b"
integrity sha512-6GAZ7gA3vzStkASe+Qsd/OqqQ9QnDTjBKpXVxMZZnqutUmWjPau9e0kLEFYoU57f5bJa2w/TCWICSp+o4ka3jg==
"@tiptap/extension-dropcursor@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.6.tgz#9a7569c970010c47424e93f67f907ce7f0c3c429"
integrity sha512-EUmagYkamxuxZprKCXcSrwqUZkOW6edxIb7iyL0RQLYAcJ2jwCe9hJU0G6a8ILDr027W7fXd6LDbrzPMcVK/ug==
dependencies:
"@types/prosemirror-dropcursor" "^1.0.1"
prosemirror-dropcursor "^1.3.4"
"@tiptap/extension-floating-menu@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.6.tgz#617290bd0533412e40c09dde7ecadc4a8c3cf960"
integrity sha512-2j73cDaN+flG8mF/PHd8OrZjaG62r3Kbskzpdsa2Oa6fV3laNg0jMhFzcuBJwFKFa0l8RHB/zMXNpacxCHa9vw==
dependencies:
prosemirror-state "^1.3.4"
prosemirror-view "^1.18.2"
tippy.js "^6.3.1"
"@tiptap/extension-gapcursor@^2.0.0-beta.10":
version "2.0.0-beta.10"
resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.10.tgz#f045d90def63559797576a299f904f539c304fe9"
integrity sha512-q5S3AjDTBi5WHwl1V7iYSk32t3mk/Z/ZYAViLDsqffzurx6KIxq9Yw6Ad1L+h04wXq/rJiFeaMeCnGs4DmWa3w==
dependencies:
"@types/prosemirror-gapcursor" "^1.0.3"
prosemirror-gapcursor "^1.1.5"
"@tiptap/extension-hard-break@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.6.tgz#37bee563b06a528d6b72ea875de7645f97a43656"
integrity sha512-FZ/wpC9YQY50rt85DuPl+Dxe157LtHAhKW08BRAds/o6zrwcBpbg7zzVPxnu1wH1L0ObhyxCjNFXUyKalLnk8g==
"@tiptap/extension-heading@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.6.tgz#077919803ed4d8c729a72cc122cfca851bfaeff3"
integrity sha512-zM5zaWGbJDYDmuHZ+YHTZK2nncDs+tlhfYKTKPK+0iIFCO4iTkvs7ERUO9qdbuQKjHGp28Q3RhS7YORss2bOhA==
dependencies:
prosemirror-inputrules "^1.1.3"
"@tiptap/extension-history@^2.0.0-beta.5":
version "2.0.0-beta.5"
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.5.tgz#bb9b257c110b0ad324407443972a623efa71816d"
integrity sha512-ej0QtStZVm8QInWHEtyduK9WQcYpfPN2EtIkwtPL9HFm9u7xgouBVdj1TqIABV3vJVGL28KKpGVVg8ZuBF4h7g==
dependencies:
"@types/prosemirror-history" "^1.0.2"
prosemirror-history "^1.1.3"
"@tiptap/extension-horizontal-rule@^2.0.0-beta.7":
version "2.0.0-beta.7"
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.7.tgz#6e75336a0316bef1a359de7d1888c8fb97d5e659"
integrity sha512-TOxoVyKL3qF0e+VCQ5B7BpdtspvvY0TdU6/AJVIatPK9rXXXcJTM68k0O4koXgeuu33CSPXWVNwgm3QcxMi3Dg==
dependencies:
prosemirror-state "^1.3.4"
"@tiptap/extension-image@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.6.tgz#fa1201b1fcf2c4a1f8a035b7cc511da6f88fb8f0"
integrity sha512-p1AYHPmcSV0WhKNk7Dqj17qYcuVxDsXz1ivPo2xD7R5vFnPphQZ9Bu1Y8BA2BJmn0eheQi11sz/ZUflnNfX7ew==
"@tiptap/extension-italic@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.6.tgz#497cc5aac4077b27d6c548896601dd240771401a"
integrity sha512-HjB6YCm4oQ04peQ9M2zi4101JSgNfOLTkyfbDhpQv+B61sZtuweJx27SxYDOB34dA+i513orCVZdI6AgSSCEHA==
"@tiptap/extension-link@^2.0.0-beta.8":
version "2.0.0-beta.8"
resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.8.tgz#7d0aba9c12335f43ba94b18034d458c4656c4dcd"
integrity sha512-rBLISgGiQg/mZ0rvFS1/8ylXqqO0kuam20KBc3tnmu6clakwk93MpZ63owNmlJPGQsJVfmPQFRkJypsdRIML3w==
dependencies:
prosemirror-state "^1.3.4"
"@tiptap/extension-list-item@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.6.tgz#69850d2d9242e213a24a7e10baecb0f0933f3cbe"
integrity sha512-zhssny5W2Q7CvB9qZT1Wc7k0V+R7IqCbNBmoijwF9a+uehBpJcxdN1DFB1v0qdmIEdDLU9dnBUfIpWPnLwiAXw==
"@tiptap/extension-mention@^2.0.0-beta.42":
version "2.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.0.0-beta.42.tgz#3cca0edd04d5416d02dc744e7d23669676c16e90"
integrity sha512-NMg7mT6aWcTasvUDErWqLVoDpWLpe7+R7+MoD9B1TYBCcQhnhOOteKMJ4tz43dTbwEUUSAif/BIZdRfMBUJdnA==
dependencies:
"@tiptap/suggestion" "^2.0.0-beta.42"
"@tiptap/extension-ordered-list@^2.0.0-beta.6":
version "2.0.0-beta.6"
resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.6.tgz#ce214854946284c7ff2d458c7f4b3ac6ae33a9b8"
integrity sha512-dUiTO9bV3cuxWedp164KVufW3BzIwY/beQ64aQjnRyA3TPyiPrhp4qvHrxQujm31XPJy4zUY0PO/VafJ+69cGw==
dependencies:
prosemirror-inputrules "^1.1.3"
"@tiptap/extension-paragraph@^2.0.0-beta.7":
version "2.0.0-beta.7"
resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.7.tgz#5dca1524247a57e98a60eb394ae66cd30072b9f4"
integrity sha512-bk9/KNbJ4wAvaAwrPLwp89QtEyef9VxbbaPd2+Q21EArTP2SGPNTWrjARq1Flc41fERo+2A23K5AcbNDBID9DA==
"@tiptap/extension-strike@^2.0.0-beta.7":
version "2.0.0-beta.7"
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.7.tgz#cee0f3c087d2914f8435dc2cc4580c9aec0a42bb"
integrity sha512-GBctBeHSkDW4ivXAUaEBtOgQXJgT2q2iqWuI8kTHCO1z7c/mns4J19U24dx8bPFhJBw++sDDd8yBkLQH2lP/Pw==
"@tiptap/extension-text@^2.0.0-beta.5":
version "2.0.0-beta.5"
resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.5.tgz#cce1f9b22a5e0ad35b081774059b8c2ec6c92ae3"
integrity sha512-WCavPVqi+tndW8tAQ4KBq98ZnkLgKW9nc/T8wE3oKQ+df9YBauIl3OxxMA6At/oK+vlcFfubBpzFRAg9iygRAA==
"@tiptap/extension-underline@^2.0.0-beta.7":
version "2.0.0-beta.7"
resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.0.0-beta.7.tgz#789a109fedea41d5dc136fdcde32395c0646fd65"
integrity sha512-p5y7WFKohnRy/+te7M+EBB9hLOBfbxtWsqPXwFEm3Puq8bj2RNdGVfOruPqlmHpBoCFJgG73RKi0lmqplo1XZg==
"@tiptap/starter-kit@^2.0.0-beta.37":
version "2.0.0-beta.37"
resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.0.0-beta.37.tgz#7653c412c32895c84a26bc017ba23d2955e3ba5d"
integrity sha512-RFT6xLIph1xAbqnQJRG7q9fVTrIhaiqUFocPsuW/HHes2wvreR6ODgKzLRCcTM19YMpsmP8wC6f++itd9JwJFg==
dependencies:
"@tiptap/core" "^2.0.0-beta.41"
"@tiptap/extension-blockquote" "^2.0.0-beta.6"
"@tiptap/extension-bold" "^2.0.0-beta.6"
"@tiptap/extension-bullet-list" "^2.0.0-beta.6"
"@tiptap/extension-code" "^2.0.0-beta.6"
"@tiptap/extension-code-block" "^2.0.0-beta.8"
"@tiptap/extension-document" "^2.0.0-beta.5"
"@tiptap/extension-dropcursor" "^2.0.0-beta.6"
"@tiptap/extension-gapcursor" "^2.0.0-beta.10"
"@tiptap/extension-hard-break" "^2.0.0-beta.6"
"@tiptap/extension-heading" "^2.0.0-beta.6"
"@tiptap/extension-history" "^2.0.0-beta.5"
"@tiptap/extension-horizontal-rule" "^2.0.0-beta.7"
"@tiptap/extension-italic" "^2.0.0-beta.6"
"@tiptap/extension-list-item" "^2.0.0-beta.6"
"@tiptap/extension-ordered-list" "^2.0.0-beta.6"
"@tiptap/extension-paragraph" "^2.0.0-beta.7"
"@tiptap/extension-strike" "^2.0.0-beta.7"
"@tiptap/extension-text" "^2.0.0-beta.5"
"@tiptap/suggestion@^2.0.0-beta.42":
version "2.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.0.0-beta.42.tgz#a2ddf87cf046ac0acd83bffbd26b3d989995fa92"
integrity sha512-+XgZL7HrBT50q792Mc3omA+yDaBjEwRFQE/T2BDKzlAZVqMzFg8Co+LNaNfR94kcDDvfvTLdsSyOg7e+m6FqPA==
dependencies:
"@tiptap/core" "^2.0.0-beta.41"
prosemirror-model "^1.14.1"
prosemirror-state "^1.3.4"
prosemirror-view "^1.18.2"
"@tiptap/vue-2@^2.0.0-beta.21":
version "2.0.0-beta.21"
resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.21.tgz#838257ef91bbd54995aa7d34e4682fc9c69cec6a"
integrity sha512-WTL6iw6cgMkQQ2b++kClQOxsByAUKYLcjO1UsjmrrWnaSDmfMO1ZpkmKKSp1SsuQAk7W0t9aybeyWrDzjxfU3g==
dependencies:
"@tiptap/extension-bubble-menu" "^2.0.0-beta.9"
"@tiptap/extension-floating-menu" "^2.0.0-beta.6"
prosemirror-view "^1.18.2"
"@types/anymatch@*":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
@ -1525,7 +1749,39 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/prosemirror-inputrules@^1.0.2":
"@types/prosemirror-commands@*", "@types/prosemirror-commands@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz#d08551415127d93ae62e7239d30db0b5e7208e22"
integrity sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ==
dependencies:
"@types/prosemirror-model" "*"
"@types/prosemirror-state" "*"
"@types/prosemirror-view" "*"
"@types/prosemirror-dropcursor@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.1.tgz#3ba98dd861ff2a62559e70f453f996a1ef5ec55d"
integrity sha512-nHokhFypOZjknolZBm2XShlR7fx1IUcCiA3S2fBwmAraWu6zv3gboDSwwFpoS9UB2xKc4ismAmBxh2bpL3YNkg==
dependencies:
"@types/prosemirror-state" "*"
"@types/prosemirror-gapcursor@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@types/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.3.tgz#989e98c734e01e2ed4cab39992e60a1b0646cab6"
integrity sha512-kBVjjbMmUk7ZsgpI1NOyY15makulu1skEGr+V9GgY7GQnT9vqjo8/XiNSgSj9s9vRTsTb/KAaTI9KJwWlhbhxQ==
dependencies:
"@types/prosemirror-model" "*"
"@types/prosemirror-state" "*"
"@types/prosemirror-history@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@types/prosemirror-history/-/prosemirror-history-1.0.2.tgz#f90a009a0dcd71393faa69ce705593dec76347a1"
integrity sha512-AcfpWo+HkIuvq/H2zYjIMi2jxa2GWfYaTNiFTB2sigjkpWNM93CIlb7Cimy/4vNH8lVPp0GwLBjYIMRX6zOUyA==
dependencies:
"@types/prosemirror-model" "*"
"@types/prosemirror-state" "*"
"@types/prosemirror-inputrules@^1.0.2", "@types/prosemirror-inputrules@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/prosemirror-inputrules/-/prosemirror-inputrules-1.0.4.tgz#4cb75054d954aa0f6f42099be05eb6c0e6958bae"
integrity sha512-lJIMpOjO47SYozQybUkpV6QmfuQt7GZKHtVrvS+mR5UekA8NMC5HRIVMyaIauJLWhKU6oaNjpVaXdw41kh165g==
@ -1533,14 +1789,33 @@
"@types/prosemirror-model" "*"
"@types/prosemirror-state" "*"
"@types/prosemirror-model@*", "@types/prosemirror-model@^1.7.2":
"@types/prosemirror-keymap@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz#f73c79810e8d0e0a20d153d84f998f02e5afbc0c"
integrity sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg==
dependencies:
"@types/prosemirror-commands" "*"
"@types/prosemirror-model" "*"
"@types/prosemirror-state" "*"
"@types/prosemirror-view" "*"
"@types/prosemirror-model@*", "@types/prosemirror-model@^1.13.0", "@types/prosemirror-model@^1.7.2":
version "1.13.0"
resolved "https://registry.yarnpkg.com/@types/prosemirror-model/-/prosemirror-model-1.13.0.tgz#d05937e918c3cac2cf49630ccab04a65fc5fffd6"
integrity sha512-EIUr2R38Zh9n1eA8BQ1C3NX/XLV9U44DhNVk8x3Sth2RW+wa7jNA82XHMPOoapsOTfmpnh32xaHBOzREiBqdPQ==
dependencies:
"@types/orderedmap" "*"
"@types/prosemirror-state@*", "@types/prosemirror-state@^1.2.4":
"@types/prosemirror-schema-list@^1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz#bdf1893a7915fbdc5c49b3cac9368e96213d70de"
integrity sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA==
dependencies:
"@types/orderedmap" "*"
"@types/prosemirror-model" "*"
"@types/prosemirror-state" "*"
"@types/prosemirror-state@*", "@types/prosemirror-state@^1.2.4", "@types/prosemirror-state@^1.2.6":
version "1.2.6"
resolved "https://registry.yarnpkg.com/@types/prosemirror-state/-/prosemirror-state-1.2.6.tgz#bb0169084239a8393b354c6fda5420fc347d6bab"
integrity sha512-tJo0wC+/cQvbrPDVx01Fnng9Fs41bAMVxgJY1KLOyIsUPN0otUN1KdoQurLMmHNHTvIna9ZXxjZD//xJKLYfJw==
@ -1549,14 +1824,14 @@
"@types/prosemirror-transform" "*"
"@types/prosemirror-view" "*"
"@types/prosemirror-transform@*":
"@types/prosemirror-transform@*", "@types/prosemirror-transform@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@types/prosemirror-transform/-/prosemirror-transform-1.1.2.tgz#fe883c19a5a9f1882346a294efd09d55c6764c7a"
integrity sha512-Ozyvs5Dquc49gaFysmC4gNhv6E65r569HSzw4RXdZgIljZ5Y9K4kHFlDvsWBBDH19+1178X9LMmM9J620O6Bug==
dependencies:
"@types/prosemirror-model" "*"
"@types/prosemirror-view@*", "@types/prosemirror-view@^1.11.4":
"@types/prosemirror-view@*", "@types/prosemirror-view@^1.11.4", "@types/prosemirror-view@^1.17.1":
version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/prosemirror-view/-/prosemirror-view-1.17.1.tgz#0895df5a57ae6e68d4f3f8020d9be4ef52192980"
integrity sha512-PNiGGc6BffxHQzMR09UUilsBR8xFPDsKiPIXb4K/g56voPIvqq1pqySnWFfSR50Vo4ZL0tss3VBLWiiiKzVahQ==
@ -2156,9 +2431,9 @@
integrity sha512-LIZMuJk38pk9U9Ur4YzHjlIyMuxPlACdBIHH9/nGYVTsaGKOSnSuELiE8vS9wa+dJpIYspYUOqk+L1Q4pgHQHQ==
"@vue/test-utils@^1.1.0":
version "1.1.4"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.1.4.tgz#a9acb32ea1fa4535b2e1ce5ca100bceb4fade2db"
integrity sha512-9BeL8IqGvJKy553lq/07rhYURQkpS/k+j19rJ/4eDpGJk7z872M0YrBWFhjS14yMKlvYVYOCfWnVIXyrAx0xNw==
version "1.2.0"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.2.0.tgz#3bc8c17ed549157275f0aec6b95da40887f7297f"
integrity sha512-poBTLqeJYNq1TXVhtVfnY8vELUVOFdJY8KZZoUuaAkIqPTWsxonU1M8nMWpZT+xEMrM+49+YcuEqtMHVD9Q9gw==
dependencies:
dom-event-types "^1.0.0"
lodash "^4.17.15"
@ -4101,9 +4376,9 @@ core-js@^2.4.0, core-js@^2.5.0:
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-js@^3.6.4:
version "3.11.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.0.tgz#05dac6aa70c0a4ad842261f8957b961d36eb8926"
integrity sha512-bd79DPpx+1Ilh9+30aT5O1sgpQd4Ttg8oqkqi51ZzhedMM1omD2e6IOF48Z/DzDCZ2svp49tN/3vneTK6ZBkXw==
version "3.11.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.11.1.tgz#f920392bf8ed63a0ec8e4e729857bfa3d121c525"
integrity sha512-k93Isqg7e4txZWMGNYwevZL9MiogLk8pd1PtwrmFmi8IBq4GXqUaVW/a33Llt6amSI36uSjd0GWwc9pTT9ALlQ==
core-js@^3.6.5:
version "3.10.1"
@ -5608,13 +5883,6 @@ fastq@^1.6.0:
dependencies:
reusify "^1.0.4"
fault@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13"
integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==
dependencies:
format "^0.2.0"
faye-websocket@^0.11.3:
version "0.11.3"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e"
@ -5912,11 +6180,6 @@ form-data@~2.3.2:
combined-stream "^1.0.6"
mime-types "^2.1.12"
format@^0.2.0:
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"
@ -6250,9 +6513,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
graphql-tag@^2.10.3:
version "2.11.0"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.11.0.tgz#1deb53a01c46a7eb401d6cb59dec86fa1cccbffd"
integrity sha512-VmsD5pJqWJnQZMUeRwrDhfgoyqcfwEkvtpANqcoUG8/tOLkwNgU9mzub/Mc78OJMhHjx7gfAMTxzdG43VGg3bA==
version "2.12.4"
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.4.tgz#d34066688a4f09e72d6f4663c74211e9b4b7c4bf"
integrity sha512-VV1U4O+9x99EkNpNmCUV5RZwq6MnK4+pGbRYWG+lA/m3uo7TSqJF81OkcOP148gFP6fzdl7JWYBrwWVTS9jXww==
dependencies:
tslib "^2.1.0"
graphql-tag@^2.12.0:
version "2.12.3"
@ -6411,7 +6676,7 @@ 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@^10.7.1, highlight.js@~10.7.0:
highlight.js@^10.7.1:
version "10.7.2"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.2.tgz#89319b861edc66c48854ed1e6da21ea89f847360"
integrity sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg==
@ -7717,7 +7982,18 @@ js-base64@^2.1.9:
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
js-beautify@^1.6.12, js-beautify@^1.6.14:
js-beautify@^1.6.12:
version "1.13.13"
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.13.13.tgz#756907d1728f329f2b84c42efd56ad17514620bf"
integrity sha512-oH+nc0U5mOAqX8M5JO1J0Pw/7Q35sAdOsM5W3i87pir9Ntx6P/5Gx1xLNoK+MGyvHk4rqqRCE4Oq58H6xl2W7A==
dependencies:
config-chain "^1.1.12"
editorconfig "^0.15.3"
glob "^7.1.3"
mkdirp "^1.0.4"
nopt "^5.0.0"
js-beautify@^1.6.14:
version "1.13.11"
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.13.11.tgz#3fc59d74d4fcb03268a559220da26f5d8a2d5246"
integrity sha512-+3CW1fQqkV7aXIvprevNYfSrKrASQf02IstAZCVSNh+/IS5ciaOtE7erfjyowdMYZZmP2A7SMFkcJ28qCl84+A==
@ -8294,14 +8570,6 @@ lower-case@^1.1.1:
resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
lowlight@^1.17.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888"
integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==
dependencies:
fault "^1.0.0"
highlight.js "~10.7.0"
lru-cache@^4.0.1, lru-cache@^4.1.2, lru-cache@^4.1.5:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@ -9190,6 +9458,11 @@ os-tmpdir@~1.0.2:
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
p-debounce@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/p-debounce/-/p-debounce-4.0.0.tgz#348e3f44489baa9435cc7d807f17b3bb2fb16b24"
integrity sha512-4Ispi9I9qYGO4lueiLDhe4q4iK5ERK8reLsuzH6BPaXn53EGaua8H66PXIFGrW897hwjXp+pVLrm/DLxN0RF0A==
p-each-series@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71"
@ -10114,14 +10387,7 @@ prop-types@^15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"
prosemirror-collab@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.2.2.tgz#8d2c0e82779cfef5d051154bd0836428bd6d9c4a"
integrity sha512-tBnHKMLgy5Qmx9MYVcLfs3pAyjtcqYYDd9kp3y+LSiQzkhMQDfZSV3NXWe4Gsly32adSef173BvObwfoSQL5MA==
dependencies:
prosemirror-state "^1.0.0"
prosemirror-commands@^1.1.4:
prosemirror-commands@^1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.1.7.tgz#5b31ae0fe82835d36d22c780641c0b651f27dd03"
integrity sha512-tuQr8q5euDjE+WAHWmu1JMLYWsPfUDH80QLLpnQrPYOPysO26FZyyHwEvA0+hUzvF8fOt1oMj0+/YM9UsPkZiA==
@ -10130,7 +10396,7 @@ prosemirror-commands@^1.1.4:
prosemirror-state "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-dropcursor@^1.3.2:
prosemirror-dropcursor@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.3.4.tgz#a7f799ff9ecb520d3e1dbb3cb39d27ce41066618"
integrity sha512-eVmpMG5+fmvANT3xDzRirmG240rB/piI31ExIfW0Mkvo5/cYC/lm1fFMAOzjO22uc5OQXiodRqOnyE05+g3UqA==
@ -10158,7 +10424,7 @@ prosemirror-history@^1.1.3:
prosemirror-transform "^1.0.0"
rope-sequence "^1.3.0"
prosemirror-inputrules@^1.1.2, prosemirror-inputrules@^1.1.3:
prosemirror-inputrules@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.1.3.tgz#93f9199ca02473259c30d7e352e4c14022d54638"
integrity sha512-ZaHCLyBtvbyIHv0f5p6boQTIJjlD6o2NPZiEaZWT2DA+j591zS29QQEMT4lBqwcLW3qRSf7ZvoKNbf05YrsStw==
@ -10166,7 +10432,7 @@ prosemirror-inputrules@^1.1.2, prosemirror-inputrules@^1.1.3:
prosemirror-state "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.1.4:
prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.3:
version "1.1.4"
resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.1.4.tgz#8b481bf8389a5ac40d38dbd67ec3da2c7eac6a6d"
integrity sha512-Al8cVUOnDFL4gcI5IDlG6xbZ0aOD/i3B17VT+1JbHWDguCgt/lBHVTHUBcKvvbSg6+q/W4Nj1Fu6bwZSca3xjg==
@ -10174,10 +10440,10 @@ prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.1.4:
prosemirror-state "^1.0.0"
w3c-keyname "^2.2.0"
prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.13.1, prosemirror-model@^1.8.1:
version "1.14.0"
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.14.0.tgz#44042a16942dfc5dcd79daf6ec37b0efcfef53c8"
integrity sha512-+9J7YE2qD2lsRgaI5aF7u6LynBoHxb/8sW1gaMKRAhK+yeQ+motBIaxb2GxRWSadDWMOq5haAImSTBo6jDkv2A==
prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.14.1.tgz#d784c67f95a5d66b853e82ff9a87a50353ef9cd5"
integrity sha512-vZcbI+24VloFefKZkDnMaEpipL/vSKKPdFiik4KOnTzq3e6AO7+CAOixZ2G/SsfRaYC965XvnOIEbhIQdgki7w==
dependencies:
orderedmap "^1.1.0"
@ -10189,7 +10455,7 @@ prosemirror-schema-list@^1.1.4:
prosemirror-model "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, prosemirror-state@^1.3.3:
prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.3.4.tgz#4c6b52628216e753fc901c6d2bfd84ce109e8952"
integrity sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA==
@ -10197,28 +10463,17 @@ prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, pr
prosemirror-model "^1.0.0"
prosemirror-transform "^1.0.0"
prosemirror-tables@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.1.1.tgz#ad66300cc49500455cf1243bb129c9e7d883321e"
integrity sha512-LmCz4jrlqQZRsYRDzCRYf/pQ5CUcSOyqZlAj5kv67ZWBH1SVLP2U9WJEvQfimWgeRlIz0y0PQVqO1arRm1+woA==
dependencies:
prosemirror-keymap "^1.1.2"
prosemirror-model "^1.8.1"
prosemirror-state "^1.3.1"
prosemirror-transform "^1.2.1"
prosemirror-view "^1.13.3"
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.2.8:
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.3.2.tgz#5620ebe7379e6fae4f34ecc881886cb22ce96579"
integrity sha512-/G6d/u9Mf6Bv3H1XR8VxhpjmUO75LYmnvj+s3ZfZpakU1hnQbsvCEybml1B3f2IWUAAQRFkbO1PnsbFhLZsYsw==
dependencies:
prosemirror-model "^1.0.0"
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.16.5:
version "1.18.3"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.18.3.tgz#cfc70169cb300e9503d97362463ea870efffd3ef"
integrity sha512-B0zlzjBI0cHadpghyvAA+JgqLGbkNU9Vxywqkfaa+AdmOZUZImBKH6ufhpK+AEZn97WWgSIkr/MT9RmGpaboAA==
prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.18.2:
version "1.18.4"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.18.4.tgz#179141df117cf414434ade08115f2e233d135f6d"
integrity sha512-6oi62XRK5WxhMX1Amjk5uMsWILUEcFbFF75i09BzpAdI+5glhs7heCaRvKOj4v3YRJ7LJVkOXS9xvjetlE3+pA==
dependencies:
prosemirror-model "^1.1.0"
prosemirror-state "^1.0.0"
@ -10968,9 +11223,9 @@ sass-loader@^8.0.2:
semver "^6.3.0"
sass@^1.29.0:
version "1.32.11"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.11.tgz#b236b3ea55c76602c2ef2bd0445f0db581baa218"
integrity sha512-O9tRcob/fegUVSIV1ihLLZcftIOh0AF1VpKgusUfLqnb2jQ0GLDwI5ivv1FYWivGv8eZ/AwntTyTzjcHu0c/qw==
version "1.32.12"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.32.12.tgz#a2a47ad0f1c168222db5206444a30c12457abb9f"
integrity sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA==
dependencies:
chokidar ">=3.0.0 <4.0.0"
@ -11973,68 +12228,13 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
tippy.js@^6.2.3:
tippy.js@^6.2.3, tippy.js@^6.3.1:
version "6.3.1"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.1.tgz#3788a007be7015eee0fd589a66b98fb3f8f10181"
integrity sha512-JnFncCq+rF1dTURupoJ4yPie5Cof978inW6/4S6kmWV7LL9YOSEVMifED3KdrVPEG+Z/TFH2CDNJcQEfaeuQww==
dependencies:
"@popperjs/core" "^2.8.3"
tiptap-commands@^1.17.1:
version "1.17.1"
resolved "https://registry.yarnpkg.com/tiptap-commands/-/tiptap-commands-1.17.1.tgz#a8974a26d87db57b2fd4fc56a552520c69e43a4a"
integrity sha512-CyGvMD/c6fNer5LThWGtrVMXHAqHn93ivGQpqJ58x3HNZFuoIiF9QTWXAiWbY/4QrG0ANYHKCSe9n5afickTqw==
dependencies:
prosemirror-commands "^1.1.4"
prosemirror-inputrules "^1.1.2"
prosemirror-model "^1.13.1"
prosemirror-schema-list "^1.1.4"
prosemirror-state "^1.3.3"
prosemirror-tables "^1.1.1"
tiptap-utils "^1.13.1"
tiptap-extensions@^1.34.0:
version "1.35.2"
resolved "https://registry.yarnpkg.com/tiptap-extensions/-/tiptap-extensions-1.35.2.tgz#83dd6ee703ae8c83b58c7608f97253fcc4f1a94c"
integrity sha512-TIMbHVJe0/3aVeTeCmqGbatDkfxduPYFOffNCmuKR+h6oQNzTu6rLVhRzoNqktfxIoi/b44SiDPorTjSN72dCw==
dependencies:
lowlight "^1.17.0"
prosemirror-collab "^1.2.2"
prosemirror-history "^1.1.3"
prosemirror-model "^1.13.1"
prosemirror-state "^1.3.3"
prosemirror-tables "^1.1.1"
prosemirror-transform "^1.2.8"
prosemirror-view "^1.16.5"
tiptap "^1.32.2"
tiptap-commands "^1.17.1"
tiptap-utils "^1.13.1"
tiptap-utils@^1.13.1:
version "1.13.1"
resolved "https://registry.yarnpkg.com/tiptap-utils/-/tiptap-utils-1.13.1.tgz#f2150ded432465d66aa03a5ab333803415cddd20"
integrity sha512-RoCvMfkdu7fp9u7nsRr1OgsYU8RFjoHKHEKpx075rJ9X0t+j5Vxah9n6QzTTr4yjvcavq22WO2flFacm36zYtA==
dependencies:
prosemirror-model "^1.13.1"
prosemirror-state "^1.3.3"
prosemirror-tables "^1.1.1"
tiptap@^1.32.0, tiptap@^1.32.2:
version "1.32.2"
resolved "https://registry.yarnpkg.com/tiptap/-/tiptap-1.32.2.tgz#cd6259e853652bfc6860758ff44ebb695d5edd1c"
integrity sha512-5IwVj8nGo8y5V3jbdtoEd7xNUsi8Q0N6WV2Nfs70olqz3fldXkiImBrDhZJ4Anx8vhyP6PIBttrg0prFVmwIvw==
dependencies:
prosemirror-commands "^1.1.4"
prosemirror-dropcursor "^1.3.2"
prosemirror-gapcursor "^1.1.5"
prosemirror-inputrules "^1.1.3"
prosemirror-keymap "^1.1.4"
prosemirror-model "^1.13.1"
prosemirror-state "^1.3.3"
prosemirror-view "^1.16.5"
tiptap-commands "^1.17.1"
tiptap-utils "^1.13.1"
tmp@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877"
@ -12701,9 +12901,9 @@ vue-i18n-extract@^1.0.2:
js-yaml "^3.14.0"
vue-i18n@^8.14.0:
version "8.24.3"
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.24.3.tgz#2233ae11ec59e8204df58a28fc41afe9754e3b41"
integrity sha512-uKAYzGbwGIJndY7JwhQwIGi1uyvErWkBfFwooOtjcNnIfMbAR49ad5dT/MiykrJ9pCcgvnocFjFsNLtTzyW+rg==
version "8.24.4"
resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-8.24.4.tgz#b158614c1df7db183d9cadddbb73e1d540269492"
integrity sha512-RZE94WUAGxEiBAANxQ0pptbRwDkNKNSXl3fnJslpFOxVMF6UkUtMDSuYGuW2blDrVgweIXVpethOVkYoNNT9xw==
vue-jest@^3.0.5:
version "3.0.7"

View File

@ -101,8 +101,12 @@ defmodule Mobilizon.Federation.ActivityPub do
{:existing, entity} ->
handle_existing_entity(url, entity, options)
{:error, e} ->
Logger.warn("Something failed while fetching url #{url} #{inspect(e)}")
{:error, e}
e ->
Logger.warn("Something failed while fetching url #{inspect(e)}")
Logger.warn("Something failed while fetching url #{url} #{inspect(e)}")
{:error, e}
end
end

View File

@ -48,7 +48,8 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
@doc """
Create an actor locally by its URL (AP ID)
"""
@spec make_actor_from_url(String.t(), boolean()) :: {:ok, %Actor{}} | {:error, any()}
@spec make_actor_from_url(String.t(), boolean()) ::
{:ok, %Actor{}} | {:error, :actor_deleted} | {:error, :http_error} | {:error, any()}
def make_actor_from_url(url, preload \\ false) do
if are_same_origin?(url, Endpoint.url()) do
{:error, "Can't make a local actor from URL"}
@ -62,6 +63,9 @@ defmodule Mobilizon.Federation.ActivityPub.Actor do
Logger.info("Actor was deleted")
{:error, :actor_deleted}
{:error, :http_error} ->
{:error, :http_error}
{:error, e} ->
Logger.warn("Failed to make actor from url")
{:error, e}

View File

@ -60,6 +60,12 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
:ok <- fetch_collection(events_url, on_behalf_of) do
:ok
else
{:error, :actor_deleted} ->
{:error, :actor_deleted}
{:error, :http_error} ->
{:error, :http_error}
{:error, err} ->
Logger.error("Error while refreshing a group")
@ -68,6 +74,7 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
)
Logger.debug(inspect(err))
{:error, err}
err ->
Logger.error("Error while refreshing a group")
@ -77,6 +84,7 @@ defmodule Mobilizon.Federation.ActivityPub.Refresher do
)
Logger.debug(inspect(err))
err
end
end

View File

@ -111,8 +111,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
{:ok, activity, event}
else
{:existing_event, %Event{} = event} -> {:ok, nil, event}
{:error, _, _} -> :error
{:error, _} -> :error
_ -> :error
end
end

View File

@ -46,7 +46,7 @@ defmodule Mobilizon.GraphQL.API.Search do
actor_type: [result_type],
radius: Map.get(args, :radius),
location: Map.get(args, :location),
minimum_visibility: :public
minimum_visibility: Map.get(args, :minimum_visibility, :public)
],
page,
limit

View File

@ -9,7 +9,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Search do
Search persons
"""
def search_persons(_parent, %{page: page, limit: limit} = args, _resolution) do
Search.search_actors(args, page, limit, :Person)
Search.search_actors(Map.put(args, :minimum_visibility, :private), page, limit, :Person)
end
@doc """

View File

@ -500,6 +500,10 @@ defmodule Mobilizon.Actors do
defp filter_suspended(query, true), do: where(query, [a], a.suspended)
defp filter_suspended(query, false), do: where(query, [a], not a.suspended)
@spec filter_out_anonymous_actor_id(Ecto.Query.t(), integer() | String.t()) :: Ecto.Query.t()
defp filter_out_anonymous_actor_id(query, anonymous_actor_id),
do: where(query, [a], a.id != ^anonymous_actor_id)
@doc """
Returns the list of local actors by their username.
"""
@ -527,12 +531,15 @@ defmodule Mobilizon.Actors do
page \\ nil,
limit \\ nil
) do
anonymous_actor_id = Mobilizon.Config.anonymous_actor_id()
Actor
|> actor_by_username_or_name_query(term)
|> actors_for_location(Keyword.get(options, :location), Keyword.get(options, :radius))
|> filter_by_types(Keyword.get(options, :actor_type, :Group))
|> filter_by_minimum_visibility(Keyword.get(options, :minimum_visibility, :public))
|> filter_suspended(false)
|> filter_out_anonymous_actor_id(anonymous_actor_id)
|> Page.build_page(page, limit)
end

View File

@ -126,6 +126,7 @@ defmodule Mobilizon.Discussions.Comment do
|> put_assoc(:media, Map.get(attrs, :media, []))
|> put_tags(attrs)
|> put_mentions(attrs)
|> unique_constraint(:url, name: :comments_url_index)
end
@spec maybe_generate_uuid(Ecto.Changeset.t()) :: Ecto.Changeset.t()

View File

@ -36,7 +36,7 @@ defmodule Mobilizon.Events.Tag do
|> TitleSlug.maybe_generate_slug()
|> validate_required(@required_attrs)
|> TitleSlug.unique_constraint()
|> validate_length(:title, min: 2, max: 20)
|> validate_length(:slug, min: 2, max: 20)
|> validate_length(:title, min: 2, max: 40)
|> validate_length(:slug, min: 2, max: 40)
end
end

View File

@ -1,7 +1,7 @@
defmodule Mobilizon.Mixfile do
use Mix.Project
@version "1.1.2"
@version "1.1.3"
def project do
[

View File

@ -51,7 +51,7 @@
"excoveralls": {:hex, :excoveralls, "0.14.0", "4b562d2acd87def01a3d1621e40037fdbf99f495ed3a8570dfcf1ab24e15f76d", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "94f17478b0cca020bcd85ce7eafea82d2856f7ed022be777734a2f864d36091a"},
"exgravatar": {:hex, :exgravatar, "2.0.2", "638412896170409da114f98947d3f8d4f38e851b0e329c1cc4cd324d5e2ea081", [:mix], [], "hexpm", "f3deb5baa6fcf354a965d794ee73a956d95f1f79f41bddf69800c713cfb014a1"},
"exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"},
"exvcr": {:hex, :exvcr, "0.12.2", "e8fc0beeb62924d3b755b2718a161b13cb4ed53311378e5e587606c15190c8ed", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "63776555a1bd003ff60635aead47461ced1ff985c66427421ad344e317ba983c"},
"exvcr": {:hex, :exvcr, "0.12.3", "eca9e0dc8727eed65621c334d34a9640760b40f748a871728cbdbe534d336c11", [:mix], [{:exactor, "~> 2.2", [hex: :exactor, repo: "hexpm", optional: false]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:httpoison, "~> 1.0", [hex: :httpoison, repo: "hexpm", optional: true]}, {:httpotion, "~> 3.1", [hex: :httpotion, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:meck, "~> 0.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm", "668bd08fad65bb21d4c9bb46f1747e5e01b5734d6387fa792ce0f2eb81b17b2b"},
"fast_html": {:hex, :fast_html, "2.0.4", "4910ee49f2f6b19692e3bf30bf97f1b6b7dac489cd6b0f34cd0fe3042c56ba30", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "3bb49d541dfc02ad5e425904f53376d758c09f89e521afc7d2b174b3227761ea"},
"fast_sanitize": {:hex, :fast_sanitize, "0.2.2", "3cbbaebaea6043865dfb5b4ecb0f1af066ad410a51470e353714b10c42007b81", [:mix], [{:fast_html, "~> 2.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "69f204db9250afa94a0d559d9110139850f57de2b081719fbafa1e9a89e94466"},
"file_info": {:hex, :file_info, "0.0.4", "2e0e77f211e833f38ead22cb29ce53761d457d80b3ffe0ffe0eb93880b0963b2", [:mix], [{:mimetype_parser, "~> 0.1.2", [hex: :mimetype_parser, repo: "hexpm", optional: false]}], "hexpm", "50e7ad01c2c8b9339010675fe4dc4a113b8d6ca7eddce24d1d74fd0e762781a5"},

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff