Selaa lähdekoodia

blog create, blog list

fengchang 1 vuosi sitten
vanhempi
commit
99fa7bf518

+ 2 - 0
hichina-main-front-mobile-first/package.json

@@ -14,9 +14,11 @@
   },
   "dependencies": {
     "@quasar/extras": "^1.0.0",
+    "@vueup/vue-quill": "^1.2.0",
     "axios": "^1.4.0",
     "core-js": "^3.6.5",
     "quasar": "^2.6.0",
+    "quill-image-uploader": "^1.3.0",
     "unhead": "^1.1.30",
     "vue": "^3.0.0",
     "vue-image-crop-upload": "^3.0.3",

+ 8 - 3
hichina-main-front-mobile-first/src/layouts/MainLayout.vue

@@ -82,7 +82,12 @@
           />
         </div>
         <div v-if="currentUser != ''" class="row">
-          <q-btn v-if="$q.screen.gt.xs" round flat>
+          <q-btn
+            v-if="$q.screen.gt.xs"
+            round
+            flat
+            @click="goPage('/user-info')"
+          >
             <q-avatar size="36px">
               <img :src="currentProfileImage" />
             </q-avatar>
@@ -97,8 +102,8 @@
               transition-hide="flip-left"
             >
               <q-list dense class="text-grey-9 text-caption">
-                <q-item clickable>
-                  <q-item-section>My Content</q-item-section>
+                <q-item clickable @click="goPage('/my-blogs')">
+                  <q-item-section>My Blogs</q-item-section>
                 </q-item>
                 <q-item clickable @click="goPage('/user-info')">
                   <q-item-section>Edit Profile</q-item-section>

+ 142 - 0
hichina-main-front-mobile-first/src/pages/BlogCreatePage.vue

@@ -0,0 +1,142 @@
+<template>
+  <q-page>
+    <div class="row justify-center">
+      <div class="col-10">
+        <div class="col-12 q-mt-xl">
+          <q-input rounded outlined v-model="title" label="Blog title" />
+        </div>
+        <div class="col-12 q-mt-xl">
+          <QuillEditor
+            theme="snow"
+            v-model:content="content"
+            contentType="html"
+            toolbar="full"
+            :modules="combineModule"
+          />
+        </div>
+        <div class="col-12 q-mt-xl row q-mb-xl">
+          <div class="col-6 row justify-center">
+            <q-btn
+              @click="postBlog(false)"
+              color="grey-4"
+              text-color="primary"
+              glossy
+              unelevated
+              icon="publish"
+              label="Publish"
+            />
+          </div>
+          <div class="col-6 row justify-center">
+            <q-btn
+              @click="postBlog(true)"
+              color="grey-4"
+              text-color="primary"
+              glossy
+              unelevated
+              icon="drafts"
+              label="Draft"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  </q-page>
+</template>
+
+<script>
+import { ref, onMounted, getCurrentInstance } from "vue";
+import { QuillEditor } from "@vueup/vue-quill";
+import "@vueup/vue-quill/dist/vue-quill.snow.css";
+import ImageUploader from "quill-image-uploader";
+import { useQuasar } from "quasar";
+import { api } from "boot/axios";
+export default {
+  name: "BlogCreatePage",
+  components: {
+    QuillEditor,
+  },
+  setup() {
+    const instance = getCurrentInstance();
+    const app = getCurrentInstance().appContext.app;
+    const gp = app.config.globalProperties;
+    const $q = useQuasar();
+
+    const content = ref("");
+    const title = ref("");
+    const imageUploadModule = {
+      name: "imageUploader",
+      module: ImageUploader,
+      options: {
+        upload: (file) => {
+          return new Promise((resolve, reject) => {
+            const formData = new FormData();
+            formData.append("imageFile", file);
+            formData.append("expectedType", "blogImage");
+
+            api
+              .post("/api/v1/image/upload", formData)
+              .then((res) => {
+                resolve(res.data.data);
+              })
+              .catch((err) => {
+                reject("Upload failed");
+                console.error("Error:", err);
+              });
+          });
+        },
+      },
+    };
+
+    const combineModule = [imageUploadModule];
+    function whoami() {
+      api
+        .get("/api/v1/user/whoami")
+        .then(function (response) {
+          console.log("current user in setup: " + response.data);
+        })
+        .catch(function (error) {
+          console.log("currently not logged in setup: " + error);
+          gp.$goPage("/auth/login");
+        });
+    }
+
+    function postBlog(shouldDraft) {
+      if (
+        content.value == null ||
+        content.value.length < 1 ||
+        title.value == null ||
+        title.value.length < 1
+      ) {
+        gp.$generalNotify($q, false, "Title or content cannot be empty");
+        return;
+      }
+
+      const params = {};
+      params.draft = shouldDraft;
+      params.title = title.value;
+      params.content = content.value;
+      params.headImageUrl = "";
+
+      api
+        .post("/api/v1/blog", params)
+        .then((res) => {
+          console.log(res.data.data.blogId);
+          gp.$goPage("/blog-detail/" + res.data.data.blogId);
+        })
+        .catch((err) => {
+          console.error("Error:", err);
+        });
+    }
+
+    onMounted(() => {
+      whoami();
+    });
+    return {
+      content,
+      combineModule,
+      postBlog,
+      title,
+    };
+  },
+};
+</script>

+ 7 - 1
hichina-main-front-mobile-first/src/pages/BlogPage.vue

@@ -40,7 +40,13 @@
       </q-carousel>
     </div>
     <div class="row justify-center q-pa-md">
-      <q-btn rounded color="primary" size="xl" label="Write your blog" />
+      <q-btn
+        rounded
+        color="primary"
+        size="xl"
+        @click="goPage('/blog-create')"
+        label="Write your blog"
+      />
     </div>
     <div class="row q-pa-md">
       <div class="q-gutter-y-md col-12 col-md-8">

+ 129 - 0
hichina-main-front-mobile-first/src/pages/MyBlogsPage.vue

@@ -0,0 +1,129 @@
+<template>
+  <q-page>
+    <div class="row justify-center">
+      <div class="col-10 row">
+        <div class="col-12 text-h5 q-pa-md text-weight-bold text-center">
+          My Blog List
+        </div>
+        <div
+          class="q-mt-xl row col-12"
+          v-for="(item, index) in bloglist"
+          :key="index"
+        >
+          Created: {{ item.createdTime }}
+          <div class="col-12 row" style="border: 1px solid gray">
+            <div class="col-6 text-h6" style="border: 1px solid gray">
+              <a :href="'./blog-detail/' + item.blogId">{{ item.title }}</a>
+            </div>
+            <div class="col-1" style="border: 1px solid gray; min-width: 70px">
+              {{ item.draft ? "Draft" : "Published" }}
+            </div>
+            <div
+              class="col-5 row no-wrap justify-center"
+              style="border: 1px solid gray"
+            >
+              <q-btn rounded dense color="primary" icon="edit" />
+              <q-btn
+                rounded
+                dense
+                color="red"
+                icon="delete"
+                @click="deleteBLog(item.blogId)"
+              />
+            </div>
+          </div>
+        </div>
+        <div class="q-pa-lg flex flex-center">
+          <q-pagination v-model="currentPage" :max="totalPages" />
+        </div>
+      </div></div
+  ></q-page>
+</template>
+
+<script>
+import { ref, onMounted, getCurrentInstance } from "vue";
+import { useQuasar } from "quasar";
+import { api } from "boot/axios";
+export default {
+  name: "MyBlogsPage",
+  setup() {
+    const instance = getCurrentInstance();
+    const app = getCurrentInstance().appContext.app;
+    const gp = app.config.globalProperties;
+    const $q = useQuasar();
+
+    const pageSize = ref(100);
+    const blogCurrentPage = ref(1);
+    const bloglist = ref([]);
+    const totalCnt = ref(0);
+    const totalPages = ref(1);
+    const currentPage = ref(1);
+
+    function deleteBLog(blogId) {
+      api
+        .delete("/api/v1/blog/" + blogId)
+        .then((res) => {
+          gp.$generalNotify($q, true, "Succeed deleting blog");
+          loadMyBlogs();
+        })
+        .catch((err) => {
+          gp.$generalNotify($q, false, "Fail deleting blog" + err);
+        });
+    }
+
+    function loadMyBlogs() {
+      var params = {};
+      params.pageSize = pageSize.value;
+      params.page = blogCurrentPage.value;
+      (params.query = ""),
+        api
+          .get("/api/v1/blog/mybloglist", {
+            params: params,
+          })
+          .then(function (response) {
+            console.log("Got my blogs summary: ");
+            console.log(response.data.data);
+            bloglist.value = response.data.data.data;
+            totalCnt.value = response.data.data.total;
+            pageSize.value = response.data.data.pageSize;
+            blogCurrentPage.value = response.data.data.currentPage;
+
+            let divFloor = Math.floor(totalCnt.value / pageSize.value);
+            if (totalCnt.value % pageSize.value > 0) {
+              divFloor += 1;
+            }
+            totalPages.value = divFloor;
+          })
+          .catch(function (error) {
+            console.log("failed to load my blogs: " + error);
+          });
+    }
+
+    function whoami() {
+      api
+        .get("/api/v1/user/whoami")
+        .then(function (response) {
+          console.log("current user in user page: " + response.data);
+        })
+        .catch(function (error) {
+          console.log("currently not logged in setup: " + error);
+          gp.$goPage("/auth/login");
+        });
+    }
+
+    onMounted(() => {
+      whoami();
+      loadMyBlogs();
+    });
+
+    return {
+      pageSize,
+      bloglist,
+      totalCnt,
+      currentPage,
+      totalPages,
+      deleteBLog,
+    };
+  },
+};
+</script>

+ 12 - 0
hichina-main-front-mobile-first/src/router/routes.js

@@ -66,11 +66,23 @@ const routes = [
     component: () => import("layouts/MainLayout.vue"),
     children: [{ path: "", component: () => import("pages/ContactPage.vue") }],
   },
+  {
+    path: "/my-blogs",
+    component: () => import("layouts/MainLayout.vue"),
+    children: [{ path: "", component: () => import("pages/MyBlogsPage.vue") }],
+  },
   {
     path: "/user-info",
     component: () => import("layouts/MainLayout.vue"),
     children: [{ path: "", component: () => import("pages/UserInfoPage.vue") }],
   },
+  {
+    path: "/blog-create",
+    component: () => import("layouts/MainLayout.vue"),
+    children: [
+      { path: "", component: () => import("pages/BlogCreatePage.vue") },
+    ],
+  },
   {
     path: "/regsuccess",
     component: () => import("layouts/MainLayout.vue"),

+ 149 - 2
hichina-main-front-mobile-first/yarn.lock

@@ -1744,6 +1744,14 @@
   resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.4.tgz#06e83c5027f464eef861c329be81454bc8b70780"
   integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==
 
+"@vueup/vue-quill@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@vueup/vue-quill/-/vue-quill-1.2.0.tgz#cd0d93559256d069f639723dd91c044e8162c72a"
+  integrity sha512-kd5QPSHMDpycklojPXno2Kw2JSiKMYduKYQckTm1RJoVDA557MnyUXgcuuDpry4HY/Rny9nGNcK+m3AHk94wag==
+  dependencies:
+    quill "^1.3.7"
+    quill-delta "^4.2.2"
+
 "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5":
   version "1.11.6"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24"
@@ -2392,6 +2400,11 @@ clone@^1.0.2:
   resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
   integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
 
+clone@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
+  integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
+
 color-convert@^1.9.0:
   version "1.9.3"
   resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
@@ -2750,6 +2763,18 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
   dependencies:
     ms "2.1.2"
 
+deep-equal@^1.0.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
+  integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==
+  dependencies:
+    is-arguments "^1.0.4"
+    is-date-object "^1.0.1"
+    is-regex "^1.0.4"
+    object-is "^1.0.1"
+    object-keys "^1.1.1"
+    regexp.prototype.flags "^1.2.0"
+
 deep-is@^0.1.3:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
@@ -2784,7 +2809,7 @@ define-lazy-prop@^2.0.0:
   resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
   integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
 
-define-properties@^1.1.4:
+define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5"
   integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==
@@ -3139,6 +3164,11 @@ etag@~1.8.1:
   resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
   integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
 
+eventemitter3@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
+  integrity sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==
+
 eventemitter3@^4.0.0:
   version "4.0.7"
   resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
@@ -3201,6 +3231,11 @@ express@4.18.2, express@^4.17.3:
     utils-merge "1.0.1"
     vary "~1.1.2"
 
+extend@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+  integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
 external-editor@^3.0.3:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
@@ -3215,6 +3250,16 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
   resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
   integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
 
+fast-diff@1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154"
+  integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==
+
+fast-diff@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
+  integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
+
 fast-glob@3.2.12, fast-glob@^3.2.11:
   version "3.2.12"
   resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
@@ -3437,6 +3482,11 @@ function-bind@^1.1.1:
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
   integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
 
+functions-have-names@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
+  integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+
 gensync@^1.0.0-beta.2:
   version "1.0.0-beta.2"
   resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@@ -3566,11 +3616,18 @@ has-proto@^1.0.1:
   resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
   integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
 
-has-symbols@^1.0.3:
+has-symbols@^1.0.2, has-symbols@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
   integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
 
+has-tostringtag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
+  integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
+  dependencies:
+    has-symbols "^1.0.2"
+
 has@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@@ -3799,6 +3856,14 @@ ipaddr.js@^2.0.1:
   resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f"
   integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==
 
+is-arguments@^1.0.4:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
+  integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
+  dependencies:
+    call-bind "^1.0.2"
+    has-tostringtag "^1.0.0"
+
 is-arrayish@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -3818,6 +3883,13 @@ is-core-module@^2.11.0:
   dependencies:
     has "^1.0.3"
 
+is-date-object@^1.0.1:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
+  integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
+  dependencies:
+    has-tostringtag "^1.0.0"
+
 is-docker@^2.0.0, is-docker@^2.1.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
@@ -3872,6 +3944,14 @@ is-plain-object@^2.0.4:
   dependencies:
     isobject "^3.0.1"
 
+is-regex@^1.0.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
+  integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
+  dependencies:
+    call-bind "^1.0.2"
+    has-tostringtag "^1.0.0"
+
 is-stream@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
@@ -4112,6 +4192,11 @@ locate-path@^6.0.0:
   dependencies:
     p-locate "^5.0.0"
 
+lodash.clonedeep@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
+  integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
+
 lodash.debounce@^4.0.8:
   version "4.0.8"
   resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -4132,6 +4217,11 @@ lodash.flatten@^4.4.0:
   resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
   integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==
 
+lodash.isequal@^4.5.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+  integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
+
 lodash.isplainobject@^4.0.6:
   version "4.0.6"
   resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
@@ -4455,6 +4545,14 @@ object-inspect@^1.9.0:
   resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
   integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
 
+object-is@^1.0.1:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
+  integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.1.3"
+
 object-keys@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@@ -4619,6 +4717,11 @@ param-case@^3.0.4:
     dot-case "^3.0.4"
     tslib "^2.0.3"
 
+parchment@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/parchment/-/parchment-1.1.4.tgz#aeded7ab938fe921d4c34bc339ce1168bc2ffde5"
+  integrity sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==
+
 parent-module@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -5034,6 +5137,41 @@ queue-microtask@^1.2.2:
   resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
   integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
 
+quill-delta@^3.6.2:
+  version "3.6.3"
+  resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032"
+  integrity sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==
+  dependencies:
+    deep-equal "^1.0.1"
+    extend "^3.0.2"
+    fast-diff "1.1.2"
+
+quill-delta@^4.2.2:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-4.2.2.tgz#015397d046e0a3bed087cd8a51f98c11a1b8f351"
+  integrity sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg==
+  dependencies:
+    fast-diff "1.2.0"
+    lodash.clonedeep "^4.5.0"
+    lodash.isequal "^4.5.0"
+
+quill-image-uploader@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/quill-image-uploader/-/quill-image-uploader-1.3.0.tgz#cf5396e3bf792c350c946be2e592eea2a0b14c8f"
+  integrity sha512-vO43GEn93rGThje/MlotkQE9OV5nOKBZ4oKhn71L/EjrM/J2P/8iDDVd9GEwlsGsbskeJqPLopsSQ4HlVVIn6A==
+
+quill@^1.3.7:
+  version "1.3.7"
+  resolved "https://registry.yarnpkg.com/quill/-/quill-1.3.7.tgz#da5b2f3a2c470e932340cdbf3668c9f21f9286e8"
+  integrity sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==
+  dependencies:
+    clone "^2.1.1"
+    deep-equal "^1.0.1"
+    eventemitter3 "^2.0.3"
+    extend "^3.0.2"
+    parchment "^1.1.4"
+    quill-delta "^3.6.2"
+
 randombytes@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@@ -5121,6 +5259,15 @@ regenerator-transform@^0.15.1:
   dependencies:
     "@babel/runtime" "^7.8.4"
 
+regexp.prototype.flags@^1.2.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb"
+  integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==
+  dependencies:
+    call-bind "^1.0.2"
+    define-properties "^1.2.0"
+    functions-have-names "^1.2.3"
+
 regexpu-core@^5.3.1:
   version "5.3.2"
   resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b"