Add media library button to EasyMDE (#1508)

* Adds Media Library access to EasyMDE editor
* Chooses VueJS as front end framework for #1508 
* Closes #1320
This commit is contained in:
Kevin Chung
2020-06-24 18:18:11 -04:00
committed by GitHub
parent aa225f8e15
commit 74084d7d9a
27 changed files with 689 additions and 373 deletions

View File

@@ -27,7 +27,7 @@ def pages_preview():
data = request.form.to_dict()
schema = PageSchema()
page = schema.load(data)
return render_template("page.html", content=build_html(page.data["content"]))
return render_template("page.html", content=build_html(page.data.content))
@admin.route("/admin/pages/<int:page_id>")

View File

@@ -0,0 +1,332 @@
<template>
<div id="media-modal" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<div class="container">
<div class="row">
<div class="col-md-12">
<h3 class="text-center">Media Library</h3>
</div>
</div>
</div>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="modal-header">
<div class="container">
<div class="row mh-100">
<div class="col-md-6" id="media-library-list">
<div
class="media-item-wrapper"
v-for="file in files"
:key="file.id"
>
<a
href="javascript:void(0)"
@click="
selectFile(file);
return false;
"
>
<i
v-bind:class="getIconClass(file.location)"
aria-hidden="true"
></i>
<small class="media-item-title">{{
file.location.split("/").pop()
}}</small>
</a>
</div>
</div>
<div class="col-md-6" id="media-library-details">
<h4 class="text-center">Media Details</h4>
<div id="media-item">
<div class="text-center" id="media-icon">
<div v-if="this.selectedFile">
<div
v-if="
getIconClass(this.selectedFile.location) ===
'far fa-file-image'
"
>
<img
v-bind:src="buildSelectedFileUrl()"
style="max-width: 100%; max-height: 100%; object-fit: contain;"
/>
</div>
<div v-else>
<i
v-bind:class="
`${getIconClass(
this.selectedFile.location
)} fa-4x`
"
aria-hidden="true"
></i>
</div>
</div>
</div>
<br />
<div
class="text-center"
id="media-filename"
v-if="this.selectedFile"
>
<a v-bind:href="buildSelectedFileUrl()" target="_blank">
{{ this.selectedFile.location.split("/").pop() }}
</a>
</div>
<br />
<div class="form-group">
<div v-if="this.selectedFile">
Link:
<input
class="form-control"
type="text"
id="media-link"
v-bind:value="buildSelectedFileUrl()"
readonly
/>
</div>
<div v-else>
Link:
<input
class="form-control"
type="text"
id="media-link"
readonly
/>
</div>
</div>
<div class="form-group text-center">
<div class="row">
<div class="col-md-6">
<button
@click="insertSelectedFile"
class="btn btn-success w-100"
id="media-insert"
data-toggle="tooltip"
data-placement="top"
title="Insert link into editor"
>
Insert
</button>
</div>
<div class="col-md-3">
<button
@click="downloadSelectedFile"
class="btn btn-primary w-100"
id="media-download"
data-toggle="tooltip"
data-placement="top"
title="Download file"
>
<i class="fas fa-download"></i>
</button>
</div>
<div class="col-md-3">
<button
@click="deleteSelectedFile"
class="btn btn-danger w-100"
id="media-delete"
data-toggle="tooltip"
data-placement="top"
title="Delete file"
>
<i class="far fa-trash-alt"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<form id="media-library-upload" enctype="multipart/form-data">
<div class="form-group">
<label for="media-files">
Upload Files
</label>
<input
type="file"
name="file"
id="media-files"
class="form-control-file"
multiple
/>
<sub class="help-block">
Attach multiple files using Control+Click or Cmd+Click.
</sub>
</div>
<input type="hidden" value="page" name="type" />
</form>
</div>
<div class="modal-footer">
<div class="float-right">
<button
@click="uploadChosenFiles"
type="submit"
class="btn btn-primary media-upload-button"
>
Upload
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import CTFd from "core/CTFd";
import { ezQuery, ezToast } from "core/ezq";
import { default as helpers } from "core/helpers";
function get_page_files() {
return CTFd.fetch("/api/v1/files?type=page", {
credentials: "same-origin"
}).then(function(response) {
return response.json();
});
}
export default {
props: {
editor: Object
},
data: function() {
return {
files: [],
selectedFile: null
};
},
methods: {
getPageFiles: function() {
get_page_files().then(response => {
this.files = response.data;
return this.files;
});
},
uploadChosenFiles: function() {
// TODO: We should reduce the need to interact with the DOM directly.
// This looks jank and we should be able to remove it.
let form = document.querySelector("#media-library-upload");
helpers.files.upload(form, {}, _data => {
this.getPageFiles();
});
},
selectFile: function(file) {
this.selectedFile = file;
return this.selectedFile;
},
buildSelectedFileUrl: function() {
return CTFd.config.urlRoot + "/files/" + this.selectedFile.location;
},
deleteSelectedFile: function() {
var file_id = this.selectedFile.id;
if (confirm("Are you sure you want to delete this file?")) {
CTFd.fetch("/api/v1/files/" + file_id, {
method: "DELETE"
}).then(response => {
if (response.status === 200) {
response.json().then(object => {
if (object.success) {
this.getPageFiles();
this.selectedFile = null;
}
});
}
});
}
},
insertSelectedFile: function() {
let editor = this.$props.editor;
if (editor.hasOwnProperty("codemirror")) {
editor = editor.codemirror;
}
let doc = editor.getDoc();
let cursor = doc.getCursor();
let url = this.buildSelectedFileUrl();
let img =
this.getIconClass(this.selectedFile.location) === "far fa-file-image";
let filename = url.split("/").pop();
link = "[{0}]({1})".format(filename, url);
if (img) {
link = "!" + link;
}
doc.replaceRange(link, cursor);
},
downloadSelectedFile: function() {
var link = this.buildSelectedFileUrl();
window.open(link, "_blank");
},
getIconClass: function(filename) {
var mapping = {
// Image Files
png: "far fa-file-image",
jpg: "far fa-file-image",
jpeg: "far fa-file-image",
gif: "far fa-file-image",
bmp: "far fa-file-image",
svg: "far fa-file-image",
// Text Files
txt: "far fa-file-alt",
// Video Files
mov: "far fa-file-video",
mp4: "far fa-file-video",
wmv: "far fa-file-video",
flv: "far fa-file-video",
mkv: "far fa-file-video",
avi: "far fa-file-video",
// PDF Files
pdf: "far fa-file-pdf",
// Audio Files
mp3: "far fa-file-sound",
wav: "far fa-file-sound",
aac: "far fa-file-sound",
// Archive Files
zip: "far fa-file-archive",
gz: "far fa-file-archive",
tar: "far fa-file-archive",
"7z": "far fa-file-archive",
rar: "far fa-file-archive",
// Code Files
py: "far fa-file-code",
c: "far fa-file-code",
cpp: "far fa-file-code",
html: "far fa-file-code",
js: "far fa-file-code",
rb: "far fa-file-code",
go: "far fa-file-code"
};
var ext = filename.split(".").pop();
return mapping[ext] || "far fa-file";
}
},
created() {
return this.getPageFiles();
}
};
</script>

View File

@@ -1,155 +1,11 @@
import "./main";
import { showMediaLibrary } from "../styles";
import "core/utils";
import $ from "jquery";
import CTFd from "core/CTFd";
import { default as helpers } from "core/helpers";
import CodeMirror from "codemirror";
import "codemirror/mode/htmlmixed/htmlmixed.js";
import { ezQuery, ezToast } from "core/ezq";
function get_filetype_icon_class(filename) {
var mapping = {
// Image Files
png: "fa-file-image",
jpg: "fa-file-image",
jpeg: "fa-file-image",
gif: "fa-file-image",
bmp: "fa-file-image",
svg: "fa-file-image",
// Text Files
txt: "fa-file-alt",
// Video Files
mov: "fa-file-video",
mp4: "fa-file-video",
wmv: "fa-file-video",
flv: "fa-file-video",
mkv: "fa-file-video",
avi: "fa-file-video",
// PDF Files
pdf: "fa-file-pdf",
// Audio Files
mp3: "fa-file-sound",
wav: "fa-file-sound",
aac: "fa-file-sound",
// Archive Files
zip: "fa-file-archive",
gz: "fa-file-archive",
tar: "fa-file-archive",
"7z": "fa-file-archive",
rar: "fa-file-archive",
// Code Files
py: "fa-file-code",
c: "fa-file-code",
cpp: "fa-file-code",
html: "fa-file-code",
js: "fa-file-code",
rb: "fa-file-code",
go: "fa-file-code"
};
var ext = filename.split(".").pop();
return mapping[ext];
}
function get_page_files() {
return CTFd.fetch("/api/v1/files?type=page", {
credentials: "same-origin"
}).then(function(response) {
return response.json();
});
}
function show_files(data) {
var list = $("#media-library-list");
list.empty();
for (var i = 0; i < data.length; i++) {
var f = data[i];
var fname = f.location.split("/").pop();
var ext = get_filetype_icon_class(f.location);
var wrapper = $("<div>").attr("class", "media-item-wrapper");
var link = $("<a>");
link.attr("href", "##");
if (ext === undefined) {
link.append(
'<i class="far fa-file" aria-hidden="true"></i> '.format(ext)
);
} else {
link.append('<i class="far {0}" aria-hidden="true"></i> '.format(ext));
}
link.append(
$("<small>")
.attr("class", "media-item-title")
.text(fname)
);
link.click(function(_e) {
var media_div = $(this).parent();
var icon = $(this).find("i")[0];
var f_loc = media_div.attr("data-location");
var fname = media_div.attr("data-filename");
var f_id = media_div.attr("data-id");
$("#media-delete").attr("data-id", f_id);
$("#media-link").val(f_loc);
$("#media-filename").html(
$("<a>")
.attr("href", f_loc)
.attr("target", "_blank")
.text(fname)
);
$("#media-icon").empty();
if ($(icon).hasClass("fa-file-image")) {
$("#media-icon").append(
$("<img>")
.attr("src", f_loc)
.css({
"max-width": "100%",
"max-height": "100%",
"object-fit": "contain"
})
);
} else {
// icon is empty so we need to pull outerHTML
var copy_icon = $(icon).clone();
$(copy_icon).addClass("fa-4x");
$("#media-icon").append(copy_icon);
}
$("#media-item").show();
});
wrapper.append(link);
wrapper.attr("data-location", CTFd.config.urlRoot + "/files/" + f.location);
wrapper.attr("data-id", f.id);
wrapper.attr("data-filename", fname);
list.append(wrapper);
}
}
function refresh_files(cb) {
get_page_files().then(function(response) {
var data = response.data;
show_files(data);
if (cb) {
cb();
}
});
}
function insert_at_cursor(editor, text) {
var doc = editor.getDoc();
var cursor = doc.getCursor();
doc.replaceRange(text, cursor);
}
import { ezToast } from "core/ezq";
function submit_form() {
// Save the CodeMirror data to the Textarea
@@ -196,12 +52,6 @@ function preview_page() {
$("#page-edit").submit();
}
function upload_media() {
helpers.files.upload($("#media-library-upload"), {}, function(_data) {
refresh_files();
});
}
$(() => {
window.editor = CodeMirror.fromTextArea(
document.getElementById("admin-pages-editor"),
@@ -213,55 +63,8 @@ $(() => {
}
);
$("#media-insert").click(function(_e) {
var tag = "";
try {
tag = $("#media-icon")
.children()[0]
.nodeName.toLowerCase();
} catch (err) {
tag = "";
}
var link = $("#media-link").val();
var fname = $("#media-filename").text();
var entry = null;
if (tag === "img") {
entry = "![{0}]({1})".format(fname, link);
} else {
entry = "[{0}]({1})".format(fname, link);
}
insert_at_cursor(window.editor, entry);
});
$("#media-download").click(function(_e) {
var link = $("#media-link").val();
window.open(link, "_blank");
});
$("#media-delete").click(function(_e) {
var file_id = $(this).attr("data-id");
ezQuery({
title: "Delete File?",
body: "Are you sure you want to delete this file?",
success: function() {
CTFd.fetch("/api/v1/files/" + file_id, {
method: "DELETE",
credentials: "same-origin",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
}).then(function(response) {
if (response.status === 200) {
response.json().then(function(object) {
if (object.success) {
refresh_files();
}
});
}
});
}
});
$("#media-button").click(function(_e) {
showMediaLibrary(window.editor);
});
$("#save-page").click(function(e) {
@@ -269,17 +72,6 @@ $(() => {
submit_form();
});
$("#media-button").click(function() {
$("#media-library-list").empty();
refresh_files(function() {
$("#media-modal").modal();
});
});
$(".media-upload-button").click(function() {
upload_media();
});
$(".preview-page").click(function() {
preview_page();
});

View File

@@ -2,6 +2,33 @@ import "bootstrap/dist/js/bootstrap.bundle";
import { makeSortableTables } from "core/utils";
import $ from "jquery";
import EasyMDE from "easymde";
import Vue from "vue/dist/vue.esm.browser";
import MediaLibrary from "./components/files/MediaLibrary.vue";
export function showMediaLibrary(editor) {
const mediaModal = Vue.extend(MediaLibrary);
// Create an empty div and append it to our <main>
let vueContainer = document.createElement("div");
document.querySelector("main").appendChild(vueContainer);
// Create MediaLibrary component and pass it our editor
let m = new mediaModal({
propsData: {
editor: editor
}
// Mount to the empty div
}).$mount(vueContainer);
// Destroy the Vue instance and the media modal when closed
$("#media-modal").on("hidden.bs.modal", function(_e) {
m.$destroy();
$("#media-modal").remove();
});
// Pop the Component modal
$("#media-modal").modal();
}
export function bindMarkdownEditors() {
$("textarea.markdown").each(function(_i, e) {
@@ -19,6 +46,14 @@ export function bindMarkdownEditors() {
"|",
"link",
"image",
{
name: "media",
action: editor => {
showMediaLibrary(editor);
},
className: "fas fa-file-upload",
title: "Media Library"
},
"|",
"preview",
"guide"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,94 +4,6 @@
{% endblock %}
{% block content %}
<div id="media-modal" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<div class="container">
<div class="row">
<div class="col-md-12">
<h3 class="text-center">Media Library</h3>
</div>
</div>
</div>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="modal-header">
<div class="container">
<div class="row mh-100">
<div class="col-md-6" id="media-library-list">
</div>
<div class="col-md-6" id="media-library-details">
<h4 class="text-center">Media Details</h4>
<div id="media-item">
<div class="text-center" id="media-icon">
</div>
<br>
<div class="text-center" id="media-filename">
</div>
<br>
<div class="form-group">
Link: <input class="form-control" type="text" id="media-link" readonly>
</div>
<div class="form-group text-center">
<div class="row">
<div class="col-md-6">
<button class="btn btn-success w-100" id="media-insert"
data-toggle="tooltip" data-placement="top"
title="Insert link into editor">
Insert
</button>
</div>
<div class="col-md-3">
<button class="btn btn-primary w-100" id="media-download"
data-toggle="tooltip" data-placement="top"
title="Download file">
<i class="fas fa-download"></i>
</button>
</div>
<div class="col-md-3">
<button class="btn btn-danger w-100" id="media-delete"
data-toggle="tooltip" data-placement="top"
title="Delete file">
<i class="far fa-trash-alt"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% with form = Forms.pages.PageFilesUploadForm() %}
<form id="media-library-upload" enctype="multipart/form-data">
<div class="form-group">
<b>{{ form.file.label }}</b>
{{ form.file(id="media-files", class="form-control-file") }}
<sub class="help-block">
{{ form.file.description }}
</sub>
</div>
<input type="hidden" value="page" name="type">
</form>
{% endwith %}
</div>
<div class="modal-footer">
<div class="float-right">
<button type="submit" class="btn btn-primary media-upload-button">Upload</button>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row pt-5">
<div class="col-md-12">

View File

@@ -31,7 +31,7 @@
"bootstrap": "~4.3.1",
"bootstrap-multimodal": "~1.0.4",
"codemirror": "~5.42.2",
"css-loader": "~2.1.0",
"css-loader": "^3.6.0",
"easymde": "^2.10.1",
"echarts": "^4.8.0",
"eslint": "~5.12.0",
@@ -54,6 +54,10 @@
"typeface-lato": "~0.0.54",
"typeface-raleway": "~0.0.54",
"uglifyjs-webpack-plugin": "~2.1.1",
"vue": "^2.6.11",
"vue-loader": "15.9.3",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11",
"webpack": "~4.28.1",
"webpack-cli": "~3.2.1",
"webpack-fix-style-only-entries": "~0.3.0",

View File

@@ -6,6 +6,7 @@ const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const RemoveStrictPlugin = require('remove-strict-webpack-plugin')
const WebpackShellPlugin = require('webpack-shell-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const roots = {
'themes/core': {
@@ -132,9 +133,25 @@ function getJSConfig(root, type, entries, mode) {
}
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
css: ['vue-style-loader', {
loader: 'css-loader',
}],
js: [
'babel-loader',
],
},
cacheBusting: true,
},
}
],
},
plugins: [
new VueLoaderPlugin(),
new webpack.NamedModulesPlugin(),
new RemoveStrictPlugin(),
// Identify files that are generated in development but not in production and create stubs to avoid a 404
@@ -191,6 +208,13 @@ function getCSSConfig(root, type, entries, mode) {
}
]
},
// {
// test: /\.css$/,
// use: [
// 'vue-style-loader',
// 'css-loader'
// ]
// },
{
test: /\.(s?)css$/,
use: [

206
yarn.lock
View File

@@ -599,11 +599,32 @@
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.11.2.tgz#8644bc25b19475779a7b7c1fc104bc0a794f4465"
integrity sha512-XiUPoS79r1G7PcpnNtq85TJ7inJWe0v+b5oZJZKb0pGHNIV6+UiNeQWiFGmuQ0aj7GEhnD/v9iqxIsjuRKtEnQ==
"@types/json-schema@^7.0.4":
version "7.0.5"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd"
integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==
"@types/q@^1.5.1":
version "1.5.2"
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8"
integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==
"@vue/component-compiler-utils@^3.1.0":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.1.2.tgz#8213a5ff3202f9f2137fe55370f9e8b9656081c3"
integrity sha512-QLq9z8m79mCinpaEeSURhnNCN6djxpHw0lpP/bodMlt5kALfONpryMthvnrQOlTcIKoF+VoPi+lPHUYeDFPXug==
dependencies:
consolidate "^0.15.1"
hash-sum "^1.0.2"
lru-cache "^4.1.2"
merge-source-map "^1.1.0"
postcss "^7.0.14"
postcss-selector-parser "^6.0.2"
source-map "~0.6.1"
vue-template-es2015-compiler "^1.9.0"
optionalDependencies:
prettier "^1.18.2"
"@webassemblyjs/ast@1.7.11":
version "1.7.11"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace"
@@ -799,6 +820,11 @@ ajv-keywords@^3.1.0:
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d"
integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==
ajv-keywords@^3.4.1:
version "3.5.0"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.0.tgz#5c894537098785926d71e696114a53ce768ed773"
integrity sha512-eyoaac3btgU8eJlvh01En8OCKzRqlLe2G5jDsCr3RiE2uLGMEEB1aaGwVVpwR8M95956tGH6R+9edC++OvzaVw==
ajv@^6.1.0, ajv@^6.5.3, ajv@^6.9.1:
version "6.10.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
@@ -809,7 +835,7 @@ ajv@^6.1.0, ajv@^6.5.3, ajv@^6.9.1:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ajv@^6.5.5:
ajv@^6.12.2, ajv@^6.5.5:
version "6.12.2"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd"
integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==
@@ -1064,6 +1090,11 @@ block-stream@*:
dependencies:
inherits "~2.0.0"
bluebird@^3.1.1:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
bluebird@^3.5.5:
version "3.5.5"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
@@ -1300,7 +1331,7 @@ camelcase@^4.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
camelcase@^5.0.0, camelcase@^5.2.0:
camelcase@^5.0.0, camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
@@ -1616,6 +1647,13 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0:
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
consolidate@^0.15.1:
version "0.15.1"
resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7"
integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==
dependencies:
bluebird "^3.1.1"
constants-browserify@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
@@ -1766,22 +1804,24 @@ css-declaration-sorter@^4.0.1:
postcss "^7.0.1"
timsort "^0.3.0"
css-loader@~2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea"
integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w==
css-loader@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645"
integrity sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==
dependencies:
camelcase "^5.2.0"
icss-utils "^4.1.0"
camelcase "^5.3.1"
cssesc "^3.0.0"
icss-utils "^4.1.1"
loader-utils "^1.2.3"
normalize-path "^3.0.0"
postcss "^7.0.14"
postcss "^7.0.32"
postcss-modules-extract-imports "^2.0.0"
postcss-modules-local-by-default "^2.0.6"
postcss-modules-scope "^2.1.0"
postcss-modules-values "^2.0.0"
postcss-value-parser "^3.3.0"
schema-utils "^1.0.0"
postcss-modules-local-by-default "^3.0.2"
postcss-modules-scope "^2.2.0"
postcss-modules-values "^3.0.0"
postcss-value-parser "^4.1.0"
schema-utils "^2.7.0"
semver "^6.3.0"
css-select-base-adapter@^0.1.1:
version "0.1.1"
@@ -1938,6 +1978,11 @@ date-now@^0.1.4:
resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=
de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=
debug@^2.2.0, debug@^2.3.3:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -2906,6 +2951,11 @@ hash-base@^3.0.0:
inherits "^2.0.1"
safe-buffer "^5.0.1"
hash-sum@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04"
integrity sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=
hash.js@^1.0.0, hash.js@^1.0.3:
version "1.1.7"
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
@@ -2914,6 +2964,11 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
he@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
hex-color-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
@@ -2992,12 +3047,7 @@ iconv-lite@^0.4.24, iconv-lite@^0.4.4:
dependencies:
safer-buffer ">= 2.1.2 < 3"
icss-replace-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
icss-utils@^4.1.0:
icss-utils@^4.0.0, icss-utils@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467"
integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==
@@ -3711,7 +3761,7 @@ lowercase-keys@^1.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
lru-cache@^4.0.1, lru-cache@^4.1.5:
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"
integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
@@ -3833,6 +3883,13 @@ meow@^3.7.0:
redent "^1.0.0"
trim-newlines "^1.0.0"
merge-source-map@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646"
integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==
dependencies:
source-map "^0.6.1"
micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
@@ -4753,29 +4810,30 @@ postcss-modules-extract-imports@^2.0.0:
dependencies:
postcss "^7.0.5"
postcss-modules-local-by-default@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63"
integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA==
postcss-modules-local-by-default@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915"
integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==
dependencies:
postcss "^7.0.6"
postcss-selector-parser "^6.0.0"
postcss-value-parser "^3.3.1"
icss-utils "^4.1.1"
postcss "^7.0.16"
postcss-selector-parser "^6.0.2"
postcss-value-parser "^4.0.0"
postcss-modules-scope@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb"
integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==
postcss-modules-scope@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee"
integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==
dependencies:
postcss "^7.0.6"
postcss-selector-parser "^6.0.0"
postcss-modules-values@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64"
integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w==
postcss-modules-values@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10"
integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==
dependencies:
icss-replace-symbols "^1.1.0"
icss-utils "^4.0.0"
postcss "^7.0.6"
postcss-normalize-charset@^4.0.1:
@@ -4906,7 +4964,7 @@ postcss-selector-parser@^5.0.0-rc.4:
indexes-of "^1.0.1"
uniq "^1.0.1"
postcss-selector-parser@^6.0.0:
postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c"
integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==
@@ -4934,11 +4992,16 @@ postcss-unique-selectors@^4.0.1:
postcss "^7.0.0"
uniqs "^2.0.0"
postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1:
postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.5, postcss@^7.0.6:
version "7.0.17"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f"
@@ -4948,6 +5011,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.5, postcss@^7.0.6:
source-map "^0.6.1"
supports-color "^6.1.0"
postcss@^7.0.16, postcss@^7.0.32:
version "7.0.32"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d"
integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==
dependencies:
chalk "^2.4.2"
source-map "^0.6.1"
supports-color "^6.1.0"
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -4958,6 +5030,11 @@ prepend-http@^1.0.0, prepend-http@^1.0.1:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
prettier@^1.18.2:
version "1.19.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
private@^0.1.6:
version "0.1.8"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
@@ -5505,6 +5582,15 @@ schema-utils@^2.1.0:
ajv "^6.1.0"
ajv-keywords "^3.1.0"
schema-utils@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7"
integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==
dependencies:
"@types/json-schema" "^7.0.4"
ajv "^6.12.2"
ajv-keywords "^3.4.1"
scss-tokenizer@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
@@ -6446,6 +6532,48 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
vue-hot-reload-api@^2.3.0:
version "2.3.4"
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz#532955cc1eb208a3d990b3a9f9a70574657e08f2"
integrity sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==
vue-loader@15.9.3:
version "15.9.3"
resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.3.tgz#0de35d9e555d3ed53969516cac5ce25531299dda"
integrity sha512-Y67VnGGgVLH5Voostx8JBZgPQTlDQeOVBLOEsjc2cXbCYBKexSKEpOA56x0YZofoDOTszrLnIShyOX1p9uCEHA==
dependencies:
"@vue/component-compiler-utils" "^3.1.0"
hash-sum "^1.0.2"
loader-utils "^1.1.0"
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"
vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.2.tgz#dedf349806f25ceb4e64f3ad7c0a44fba735fcf8"
integrity sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==
dependencies:
hash-sum "^1.0.2"
loader-utils "^1.0.2"
vue-template-compiler@^2.6.11:
version "2.6.11"
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.11.tgz#c04704ef8f498b153130018993e56309d4698080"
integrity sha512-KIq15bvQDrcCjpGjrAhx4mUlyyHfdmTaoNfeoATHLAiWB+MU3cx4lOzMwrnUh9cCxy0Lt1T11hAFY6TQgroUAA==
dependencies:
de-indent "^1.0.2"
he "^1.1.0"
vue-template-es2015-compiler@^1.9.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
vue@^2.6.11:
version "2.6.11"
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
watchpack@^1.5.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"