Fix syntax errors, add screenshot

This commit is contained in:
Glitchii 2021-06-28 13:34:01 +01:00
commit b434833dfc
5 changed files with 1034 additions and 352 deletions

View file

@ -2,7 +2,7 @@
Visualize embed or message content from JSON input or provided GUI editor. Visualize embed or message content from JSON input or provided GUI editor.
This can be used for bot embed commands commands. Not everyone understands JSON, thus GUI. This can be used for bot embed commands. Not everyone understands JSON, thus GUI.
You can look into the [project boards](https://github.com/Glitchii/embedbuilder/projects/3) if you want to see what is being worked on or want to contribute. You can look into the [project boards](https://github.com/Glitchii/embedbuilder/projects/3) if you want to see what is being worked on or want to contribute.
<br> <br>
<br> <br>

View file

@ -115,8 +115,7 @@ window.onload = () => {
return error(`URL should have a protocol. Did you mean <span class="inline full short">http://${makeShort(re[2], 30, 600).replace(' ', '')}</span>?`); return error(`URL should have a protocol. Did you mean <span class="inline full short">http://${makeShort(re[2], 30, 600).replace(' ', '')}</span>?`);
} }
return true; return true;
}, }, markup = (txt, opts) => {
markup = (txt, opts) => {
txt = txt txt = txt
.replace(/\&#60;:[^:]+:(\d+)\&#62;/g, '<img class="emoji" src="https://cdn.discordapp.com/emojis/$1.png"/>') .replace(/\&#60;:[^:]+:(\d+)\&#62;/g, '<img class="emoji" src="https://cdn.discordapp.com/emojis/$1.png"/>')
.replace(/\&#60;a:[^:]+:(\d+)\&#62;/g, '<img class="emoji" src="https://cdn.discordapp.com/emojis/$1.gif"/>') .replace(/\&#60;a:[^:]+:(\d+)\&#62;/g, '<img class="emoji" src="https://cdn.discordapp.com/emojis/$1.gif"/>')
@ -158,381 +157,381 @@ window.onload = () => {
el.style.display = displayType || "unset"; el.style.display = displayType || "unset";
}, hide = el => el.style.removeProperty('display'), }, hide = el => el.style.removeProperty('display'),
imgSrc = (elm, src, remove) => remove ? elm.style.removeProperty('content') : elm.style.content = `url(${src})`, imgSrc = (elm, src, remove) => remove ? elm.style.removeProperty('content') : elm.style.content = `url(${src})`,
toObj = jsonString => JSON.parse(jsonString.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (x, y) => y ? "" : x)), toObj = jsonString => JSON.parse(jsonString.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (x, y) => y ? "" : x));
buildGui = (object, opts) => { buildGui = (object, opts) => {
gui.innerHTML = ` gui.innerHTML = `
<div class="item content"><p class="ttle">Message content</p></div> <div class="item content"><p class="ttle">Message content</p></div>
<div class="edit"> <div class="edit">
<textarea class="editContent" placeholder="Message content" maxlength="2000" autocomplete="off">${encodeHTML(object.content || '')}</textarea> <textarea class="editContent" placeholder="Message content" maxlength="2000" autocomplete="off">${encodeHTML(object.content || '')}</textarea>
</div> </div>
<div class="item author rows2"><p class="ttle">Author</p></div> <div class="item author rows2"><p class="ttle">Author</p></div>
<div class="edit"> <div class="edit">
<div class="linkName"> <div class="linkName">
<div class="editIcon"> <div class="editIcon">
<span class="imgParent" ${object.embed?.author?.icon_url ? 'style="content: url(' + encodeHTML(object.embed.author.icon_url) + ')"' : ''}></span> <span class="imgParent" ${object.embed?.author?.icon_url ? 'style="content: url(' + encodeHTML(object.embed.author.icon_url) + ')"' : ''}></span>
<input class="editAuthorLink" type="text" value="${encodeHTML(object.embed?.author?.icon_url || '')}" placeholder="Icon URL" autocomplete="off"/> <input class="editAuthorLink" type="text" value="${encodeHTML(object.embed?.author?.icon_url || '')}" placeholder="Icon URL" autocomplete="off"/>
</div>
<div class="editName">
<input class="editAuthorName" type="text" value="${encodeHTML(object.embed?.author?.name || '')}" placeholder="Author name" autocomplete="off" />
</div>
</div> </div>
<form method="post" enctype="multipart/form-data"> <div class="editName">
<input class="browserAuthorLink" type="file" name="file" id="file2" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" /> <input class="editAuthorName" type="text" value="${encodeHTML(object.embed?.author?.name || '')}" placeholder="Author name" autocomplete="off" />
<button type="submit"></button> </div>
<label for="file2"> </div>
<div class="browse"> <form method="post" enctype="multipart/form-data">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve"> <input class="browserAuthorLink" type="file" name="file" id="file2" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" />
<g> <button type="submit"></button>
<path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path> <label for="file2">
<path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path> <div class="browse">
</g> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve">
</svg> <g>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve"> <path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path>
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6"> <path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform> </g>
</circle> </svg>
<circle fill="#fff" stroke="none" cx="30" cy="50" r="6"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform> <circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
</circle> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6"> </circle>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform> <circle fill="#fff" stroke="none" cx="30" cy="50" r="6">
</circle> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform>
</circle>
</svg>
</svg> </svg>
</svg> </svg>
</svg> <p></p>
<p></p> </div>
</div> </label>
</label> </form>
</form> </div>
</div> </div>
</div> </div>
</div> <div class="item title inlineField">
<div class="item title inlineField"> <p class="ttle">Title</p>
<p class="ttle">Title</p> <input class="editTitle" type="text" placeholder="Title" autocomplete="off" maxlength="256" value="${encodeHTML(object.embed?.title || '')}">
<input class="editTitle" type="text" placeholder="Title" autocomplete="off" maxlength="256" value="${encodeHTML(object.embed?.title || '')}"> </div>
</div> <div class="item description"><p class="ttle">Description</p></div>
<div class="item description"><p class="ttle">Description</p></div> <div class="edit">
<div class="edit"> <textarea class="editDescription" placeholder="Embed description" maxlength="2048" autocomplete="off">${encodeHTML(object.embed?.description || '')}</textarea>
<textarea class="editDescription" placeholder="Embed description" maxlength="2048" autocomplete="off">${encodeHTML(object.embed?.description || '')}</textarea> </div>
</div> <div class="item fields"><p class="ttle">Fields</p></div>
<div class="item fields"><p class="ttle">Fields</p></div> <div class="edit"></div>
<div class="edit"></div> <div class="item thumbnail largeImg"><p class="ttle">Thumbnail</p></div>
<div class="item thumbnail largeImg"><p class="ttle">Thumbnail</p></div> <div class="edit">
<div class="edit"> <div class="linkName">
<div class="linkName"> <div class="editIcon">
<div class="editIcon"> <span class="imgParent" ${object.embed?.thumbnail?.url ? 'style="content: url(' + encodeHTML(object.embed.thumbnail.url) + ')"' : ''}></span>
<span class="imgParent" ${object.embed?.thumbnail?.url ? 'style="content: url(' + encodeHTML(object.embed.thumbnail.url) + ')"' : ''}></span> <div class="txtCol">
<div class="txtCol"> <input class="editThumbnailLink" type="text" value="${encodeHTML(object.embed?.thumbnail?.url || '')}" placeholder="Thumbnail URL" autocomplete="off" />
<input class="editThumbnailLink" type="text" value="${encodeHTML(object.embed?.thumbnail?.url || '')}" placeholder="Thumbnail URL" autocomplete="off" /> <form method="post" enctype="multipart/form-data">
<form method="post" enctype="multipart/form-data"> <input class="browseThumbLink" type="file" name="file" id="file3" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" />
<input class="browseThumbLink" type="file" name="file" id="file3" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" /> <button type="submit"></button>
<button type="submit"></button> <label for="file3">
<label for="file3"> <div class="browse">
<div class="browse"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve"> <g>
<g> <path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path>
<path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path> <path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path>
<path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path> </g>
</g> </svg>
</svg> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve"> <circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6"> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform> </circle>
</circle> <circle fill="#fff" stroke="none" cx="30" cy="50" r="6">
<circle fill="#fff" stroke="none" cx="30" cy="50" r="6"> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform> </circle>
</circle> <circle fill="#fff" stroke="none" cx="54" cy="50" r="6">
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6"> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform> </circle>
</circle> </svg>
</svg> <p></p>
<p></p> </div>
</div> </label>
</label> </form>
</form>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="item image largeImg"><p class="ttle">Image</p></div> </div>
<div class="edit"> <div class="item image largeImg"><p class="ttle">Image</p></div>
<div class="linkName"> <div class="edit">
<div class="editIcon"> <div class="linkName">
<span class="imgParent" ${object.embed?.image?.url ? 'style="content: url(' + encodeHTML(object.embed.image.url) + ')"' : ''}></span> <div class="editIcon">
<div class="txtCol"> <span class="imgParent" ${object.embed?.image?.url ? 'style="content: url(' + encodeHTML(object.embed.image.url) + ')"' : ''}></span>
<input class="editImageLink" type="text" value="${encodeHTML(object.embed?.image?.url || '')}" placeholder="Image URL" autocomplete="off" /> <div class="txtCol">
<form method="post" enctype="multipart/form-data"> <input class="editImageLink" type="text" value="${encodeHTML(object.embed?.image?.url || '')}" placeholder="Image URL" autocomplete="off" />
<input class="browseImageLink" type="file" name="file" id="file4" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" /> <form method="post" enctype="multipart/form-data">
<button type="submit"></button> <input class="browseImageLink" type="file" name="file" id="file4" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" />
<label for="file4"> <button type="submit"></button>
<div class="browse"> <label for="file4">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve"> <div class="browse">
<g> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve">
<path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path> <g>
<path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path> <path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path>
</g> <path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path>
</svg> </g>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve"> </svg>
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform> <circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
</circle> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform>
<circle fill="#fff" stroke="none" cx="30" cy="50" r="6"> </circle>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform> <circle fill="#fff" stroke="none" cx="30" cy="50" r="6">
</circle> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6"> </circle>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform> <circle fill="#fff" stroke="none" cx="54" cy="50" r="6">
</circle> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform>
</svg> </circle>
<p></p> </svg>
</div> <p></p>
</label> </div>
</form> </label>
</div> </form>
</div> </div>
</div> </div>
</div> </div>
<div class="item footer rows2"><p class="ttle">Footer</p></div> </div>
<div class="edit"> <div class="item footer rows2"><p class="ttle">Footer</p></div>
<div class="linkName"> <div class="edit">
<div class="editIcon"> <div class="linkName">
<span class="imgParent" ${object.embed?.footer?.icon_url ? 'style="content: url(' + encodeHTML(object.embed.footer.icon_url) + ')"' : ''}></span> <div class="editIcon">
<input class="editFooterLink" type="text" value="${encodeHTML(object.embed?.footer?.icon_url || '')}" placeholder="Icon URL" autocomplete="off"/> <span class="imgParent" ${object.embed?.footer?.icon_url ? 'style="content: url(' + encodeHTML(object.embed.footer.icon_url) + ')"' : ''}></span>
</div> <input class="editFooterLink" type="text" value="${encodeHTML(object.embed?.footer?.icon_url || '')}" placeholder="Icon URL" autocomplete="off"/>
<div class="editName">
<input class="editFooterText" type="text" maxlength="2048" value="${encodeHTML(object.embed?.footer?.text || '')}" placeholder="Footer text" autocomplete="off" />
</div>
</div> </div>
<form method="post" enctype="multipart/form-data"> <div class="editName">
<input class="browserFooterLink" type="file" name="file" id="file" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" /> <input class="editFooterText" type="text" maxlength="2048" value="${encodeHTML(object.embed?.footer?.text || '')}" placeholder="Footer text" autocomplete="off" />
<button type="submit"></button> </div>
<label for="file"> </div>
<div class="browse"> <form method="post" enctype="multipart/form-data">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve"> <input class="browserFooterLink" type="file" name="file" id="file" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" />
<g> <button type="submit"></button>
<path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path> <label for="file">
<path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path> <div class="browse">
</g> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve">
</svg> <g>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve"> <path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path>
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6"> <path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform> </g>
</circle> </svg>
<circle fill="#fff" stroke="none" cx="30" cy="50" r="6"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform> <circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
</circle> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6"> </circle>
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform> <circle fill="#fff" stroke="none" cx="30" cy="50" r="6">
</circle> <animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform>
</circle>
</svg>
</svg> </svg>
</svg> </svg>
</svg> <p></p>
<p></p> </div>
</div> </label>
</label> </form>
</form> </div>`;
</div>`;
let fieldsEditor = gui.querySelector('.fields ~ .edit'), addField = ` let fieldsEditor = gui.querySelector('.fields ~ .edit'), addField = `
<div class="addField"> <div class="addField">
<p>New Field</p> <p>New Field</p>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" x="0" y="0" viewBox="0 0 477.867 477.867" xml:space="preserve"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" x="0" y="0" viewBox="0 0 477.867 477.867" xml:space="preserve">
<g>
<g xmlns="http://www.w3.org/2000/svg">
<g>
<path d="M392.533,0h-307.2C38.228,0.056,0.056,38.228,0,85.333v307.2c0.056,47.105,38.228,85.277,85.333,85.333h307.2 c47.105-0.056,85.277-38.228,85.333-85.333v-307.2C477.81,38.228,439.638,0.056,392.533,0z M443.733,392.533 c0,28.277-22.923,51.2-51.2,51.2h-307.2c-28.277,0-51.2-22.923-51.2-51.2v-307.2c0-28.277,22.923-51.2,51.2-51.2h307.2 c28.277,0,51.2,22.923,51.2,51.2V392.533z" fill="#ffffff" data-original="#000000"
></path>
</g>
</g>
<g xmlns="http://www.w3.org/2000/svg">
<g>
<path d="M324.267,221.867H256V153.6c0-9.426-7.641-17.067-17.067-17.067s-17.067,7.641-17.067,17.067v68.267H153.6 c-9.426,0-17.067,7.641-17.067,17.067S144.174,256,153.6,256h68.267v68.267c0,9.426,7.641,17.067,17.067,17.067 S256,333.692,256,324.267V256h68.267c9.426,0,17.067-7.641,17.067-17.067S333.692,221.867,324.267,221.867z" fill="#ffffff" data-original="#000000"></path>
</g>
</g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
</g>
</svg>
</div>`;
if (object.embed?.fields) fieldsEditor.innerHTML = object.embed.fields.filter(f => f && typeof f === 'object').map(f => `
<div class="field">
<div class="fieldNumber"></div>
<div class="fieldInner">
<div class="designerFieldName">
<input type="text" placeholder="Field name" autocomplete="off" maxlength="256" value="${encodeHTML(f.name)}">
</div>
<div class="designerFieldValue">
<textarea placeholder="Field value" autocomplete="off" maxlength="1024">${encodeHTML(f.value)}</textarea>
</div>
</div>
<div class="inlineCheck">
<label>
<input type="checkbox" autocomplete="off" ${f.inline ? 'checked' : ''}>
<span>Inline</span>
</label>
</div>
<div class="removeBtn">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 329.26933 329" xml:space="preserve">
<g> <g>
<g xmlns="http://www.w3.org/2000/svg"> <path xmlns="http://www.w3.org/2000/svg" d="m194.800781 164.769531 128.210938-128.214843c8.34375-8.339844 8.34375-21.824219 0-30.164063-8.339844-8.339844-21.824219-8.339844-30.164063 0l-128.214844 128.214844-128.210937-128.214844c-8.34375-8.339844-21.824219-8.339844-30.164063 0-8.34375 8.339844-8.34375 21.824219 0 30.164063l128.210938 128.214843-128.210938 128.214844c-8.34375 8.339844-8.34375 21.824219 0 30.164063 4.15625 4.160156 9.621094 6.25 15.082032 6.25 5.460937 0 10.921875-2.089844 15.082031-6.25l128.210937-128.214844 128.214844 128.214844c4.160156 4.160156 9.621094 6.25 15.082032 6.25 5.460937 0 10.921874-2.089844 15.082031-6.25 8.34375-8.339844 8.34375-21.824219 0-30.164063zm0 0" fill="#ffffff" data-original="#000000"/>
<g>
<path d="M392.533,0h-307.2C38.228,0.056,0.056,38.228,0,85.333v307.2c0.056,47.105,38.228,85.277,85.333,85.333h307.2 c47.105-0.056,85.277-38.228,85.333-85.333v-307.2C477.81,38.228,439.638,0.056,392.533,0z M443.733,392.533 c0,28.277-22.923,51.2-51.2,51.2h-307.2c-28.277,0-51.2-22.923-51.2-51.2v-307.2c0-28.277,22.923-51.2,51.2-51.2h307.2 c28.277,0,51.2,22.923,51.2,51.2V392.533z" fill="#ffffff" data-original="#000000"
></path>
</g>
</g>
<g xmlns="http://www.w3.org/2000/svg">
<g>
<path d="M324.267,221.867H256V153.6c0-9.426-7.641-17.067-17.067-17.067s-17.067,7.641-17.067,17.067v68.267H153.6 c-9.426,0-17.067,7.641-17.067,17.067S144.174,256,153.6,256h68.267v68.267c0,9.426,7.641,17.067,17.067,17.067 S256,333.692,256,324.267V256h68.267c9.426,0,17.067-7.641,17.067-17.067S333.692,221.867,324.267,221.867z" fill="#ffffff" data-original="#000000"></path>
</g>
</g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
</g> </g>
</svg> </svg>
</div>`; <span>Remove</span>
if (object.embed?.fields) fieldsEditor.innerHTML = object.embed.fields.filter(f => f && typeof f === 'object').map(f => ` </div>
<div class="field"> </div>`).join('\n') + addField;
<div class="fieldNumber"></div> else fieldsEditor.innerHTML = addField;
<div class="fieldInner">
<div class="designerFieldName">
<input type="text" placeholder="Field name" autocomplete="off" maxlength="256" value="${encodeHTML(f.name)}">
</div>
<div class="designerFieldValue">
<textarea placeholder="Field value" autocomplete="off" maxlength="1024">${encodeHTML(f.value)}</textarea>
</div>
</div>
<div class="inlineCheck">
<label>
<input type="checkbox" autocomplete="off" ${f.inline ? 'checked' : ''}>
<span>Inline</span>
</label>
</div>
<div class="removeBtn">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 329.26933 329" xml:space="preserve">
<g>
<path xmlns="http://www.w3.org/2000/svg" d="m194.800781 164.769531 128.210938-128.214843c8.34375-8.339844 8.34375-21.824219 0-30.164063-8.339844-8.339844-21.824219-8.339844-30.164063 0l-128.214844 128.214844-128.210937-128.214844c-8.34375-8.339844-21.824219-8.339844-30.164063 0-8.34375 8.339844-8.34375 21.824219 0 30.164063l128.210938 128.214843-128.210938 128.214844c-8.34375 8.339844-8.34375 21.824219 0 30.164063 4.15625 4.160156 9.621094 6.25 15.082032 6.25 5.460937 0 10.921875-2.089844 15.082031-6.25l128.210937-128.214844 128.214844 128.214844c4.160156 4.160156 9.621094 6.25 15.082032 6.25 5.460937 0 10.921874-2.089844 15.082031-6.25 8.34375-8.339844 8.34375-21.824219 0-30.164063zm0 0" fill="#ffffff" data-original="#000000"/>
</g>
</svg>
<span>Remove</span>
</div>
</div>`).join('\n') + addField;
else fieldsEditor.innerHTML = addField;
gui.querySelectorAll('.removeBtn').forEach(e => { gui.querySelectorAll('.removeBtn').forEach(e => {
e.addEventListener('click', el => { e.addEventListener('click', el => {
fields = gui.querySelector('.fields ~ .edit'); fields = gui.querySelector('.fields ~ .edit');
let field = el.target.closest('.field'); let field = el.target.closest('.field');
if (field) {
let i = Array.from(fields.children).indexOf(field), jsonField = object.embed.fields[i];
if (jsonField) {
object.embed.fields.splice(i, 1);
field.remove();
update(object);
}
}
})
})
document.querySelectorAll('.gui > .item').forEach(e => {
e.addEventListener('click', el => {
let elm = (el.target.closest('.top>.gui>.item') || el.target);
if (elm.classList.contains('active')) window.getSelection().anchorNode !== elm && elm.classList.remove('active');
else {
let inlineField = elm.closest('.inlineField'),
input = elm.nextElementSibling.querySelector('input[type="text"]'),
txt = elm.nextElementSibling.querySelector('textarea');
elm.classList.add('active');
if (inlineField) inlineField.querySelector('.ttle~input').focus();
else if (input) {
input.focus();
input.selectionStart = input.selectionEnd = input.value.length;
} else if (txt) txt.focus();
elm.classList.contains('fields') && elm.scrollIntoView({ behavior: "smooth", block: "center" });
}
})
})
content = gui.querySelector('.editContent');
title = gui.querySelector('.editTitle');
authorName = gui.querySelector('.editAuthorName');
authorLink = gui.querySelector('.editAuthorLink');
desc = gui.querySelector('.editDescription');
thumbLink = gui.querySelector('.editThumbnailLink');
imgLink = gui.querySelector('.editImageLink');
footerText = gui.querySelector('.editFooterText');
footerLink = gui.querySelector('.editFooterLink');
fields = gui.querySelector('.fields ~ .edit');
document.querySelector('.addField').addEventListener('click', () => {
!json.embed && (json.embed = {});
let arr = json.embed.fields || [];
if (arr.length >= 25) return error('Cannot have more than 25 fields', 5000);
arr.push({ name: "Field name", value: "Field value", inline: false });
json.embed.fields = arr;
update(json);
buildGui(json, { newField: true, activate: document.querySelectorAll('.gui > .item.active') });
})
gui.querySelectorAll('textarea, input').forEach(e => e.addEventListener('input', el => {
let value = el.target.value, field = el.target.closest('.field');
if (field) { if (field) {
let jsonField = json.embed.fields[Array.from(fields.children).indexOf(field)]; let i = Array.from(fields.children).indexOf(field), jsonField = object.embed.fields[i];
if (jsonField) { if (jsonField) {
if (el.target.type === 'text') jsonField.name = value; object.embed.fields.splice(i, 1);
else if (el.target.type === 'textarea') jsonField.value = value; field.remove();
else jsonField.inline = el.target.checked; update(object);
} else {
let obj = {}
if (el.target.type === 'text') obj.name = value;
else if (el.target.type === 'textarea') obj.value = value;
else obj.inline = el.target.checked;
json.embed.fields.push(obj);
} }
}
})
})
document.querySelectorAll('.gui > .item').forEach(e => {
e.addEventListener('click', el => {
let elm = (el.target.closest('.top>.gui>.item') || el.target);
if (elm.classList.contains('active')) window.getSelection().anchorNode !== elm && elm.classList.remove('active');
else {
let inlineField = elm.closest('.inlineField'),
input = elm.nextElementSibling.querySelector('input[type="text"]'),
txt = elm.nextElementSibling.querySelector('textarea');
elm.classList.add('active');
if (inlineField) inlineField.querySelector('.ttle~input').focus();
else if (input) {
input.focus();
input.selectionStart = input.selectionEnd = input.value.length;
} else if (txt) txt.focus();
elm.classList.contains('fields') && elm.scrollIntoView({ behavior: "smooth", block: "center" });
}
})
})
content = gui.querySelector('.editContent');
title = gui.querySelector('.editTitle');
authorName = gui.querySelector('.editAuthorName');
authorLink = gui.querySelector('.editAuthorLink');
desc = gui.querySelector('.editDescription');
thumbLink = gui.querySelector('.editThumbnailLink');
imgLink = gui.querySelector('.editImageLink');
footerText = gui.querySelector('.editFooterText');
footerLink = gui.querySelector('.editFooterLink');
fields = gui.querySelector('.fields ~ .edit');
document.querySelector('.addField').addEventListener('click', () => {
!json.embed && (json.embed = {});
let arr = json.embed.fields || [];
if (arr.length >= 25) return error('Cannot have more than 25 fields', 5000);
arr.push({ name: "Field name", value: "Field value", inline: false });
json.embed.fields = arr;
update(json);
buildGui(json, { newField: true, activate: document.querySelectorAll('.gui > .item.active') });
})
gui.querySelectorAll('textarea, input').forEach(e => e.addEventListener('input', el => {
let value = el.target.value, field = el.target.closest('.field');
if (field) {
let jsonField = json.embed.fields[Array.from(fields.children).indexOf(field)];
if (jsonField) {
if (el.target.type === 'text') jsonField.name = value;
else if (el.target.type === 'textarea') jsonField.value = value;
else jsonField.inline = el.target.checked;
} else { } else {
json.embed ??= {}; let obj = {}
switch (el.target) { if (el.target.type === 'text') obj.name = value;
case content: json.content = value; break; else if (el.target.type === 'textarea') obj.value = value;
case title: json.embed.title = value; break; else obj.inline = el.target.checked;
case authorName: json.embed.author ??= {}, json.embed.author.name = value; break; json.embed.fields.push(obj);
case authorLink: json.embed.author ??= {}, json.embed.author.icon_url = value, imgSrc(el.target.previousElementSibling, value); break; }
case desc: json.embed.description = value; break; } else {
case thumbLink: json.embed.thumbnail ??= {}, json.embed.thumbnail.url = value, imgSrc(el.target.closest('.editIcon').querySelector('.imgParent'), value); break; json.embed ??= {};
case imgLink: json.embed.image ??= {}, json.embed.image.url = value, imgSrc(el.target.closest('.editIcon').querySelector('.imgParent'), value); break; switch (el.target) {
case footerText: json.embed.footer ??= {}, json.embed.footer.text = value; break; case content: json.content = value; break;
case footerLink: json.embed.footer ??= {}, json.embed.footer.icon_url = value, imgSrc(el.target.previousElementSibling, value); break; case title: json.embed.title = value; break;
} case authorName: json.embed.author ??= {}, json.embed.author.name = value; break;
case authorLink: json.embed.author ??= {}, json.embed.author.icon_url = value, imgSrc(el.target.previousElementSibling, value); break;
case desc: json.embed.description = value; break;
case thumbLink: json.embed.thumbnail ??= {}, json.embed.thumbnail.url = value, imgSrc(el.target.closest('.editIcon').querySelector('.imgParent'), value); break;
case imgLink: json.embed.image ??= {}, json.embed.image.url = value, imgSrc(el.target.closest('.editIcon').querySelector('.imgParent'), value); break;
case footerText: json.embed.footer ??= {}, json.embed.footer.text = value; break;
case footerLink: json.embed.footer ??= {}, json.embed.footer.icon_url = value, imgSrc(el.target.previousElementSibling, value); break;
} }
update(json);
}))
if (opts?.activate) {
let elements = opts.activate;
Array.from(elements).map(el => el.className).map(clss => '.' + clss.split(' ').slice(0, 2).join('.'))
.forEach(clss => document.querySelectorAll(clss)
.forEach(e => e.classList.add('active')))
} else['.item.author', '.item.description'].forEach(clss => document.querySelector(clss).classList.add('active'));
if (opts?.newField) {
let last = fields.children[fields.childElementCount - 2], el = last.querySelector('.designerFieldName > input');
el.setSelectionRange(el.value.length, el.value.length); el.focus();
last.scrollIntoView({ behavior: "smooth", block: "center" });
} }
update(json);
}))
let files = document.querySelectorAll('input[type="file"]'); if (opts?.activate) {
files.forEach(f => f.addEventListener('change', e => { let elements = opts.activate;
if (f.files) { Array.from(elements).map(el => el.className).map(clss => '.' + clss.split(' ').slice(0, 2).join('.'))
e.target.nextElementSibling.click(); .forEach(clss => document.querySelectorAll(clss)
e.target.closest('.edit').querySelector('.browse').classList.add('loading'); .forEach(e => e.classList.add('active')))
} } else['.item.author', '.item.description'].forEach(clss => document.querySelector(clss).classList.add('active'));
}))
document.querySelectorAll('form').forEach(form => form.addEventListener('submit', e => { if (opts?.newField) {
e.preventDefault(); let last = fields.children[fields.childElementCount - 2], el = last.querySelector('.designerFieldName > input');
let formData = new FormData(e.target); el.setSelectionRange(el.value.length, el.value.length); el.focus();
formData.append('file', files.files); last.scrollIntoView({ behavior: "smooth", block: "center" });
formData.append('datetime', '10m');
fetch('https://tempfile.site/api/files', {
method: 'POST',
body: formData,
})
.then(res => res.json())
.then(res => {
let browse = e.target.closest('.edit').querySelector('.browse');
browse.classList.remove('loading');
if (!res.ok) {
console.log(res.error);
browse.classList.add('error');
return setTimeout(() => browse.classList.remove('error'), 5000)
}
imgSrc(e.target.previousElementSibling.querySelector('.editIcon > .imgParent') || e.target.closest('.editIcon').querySelector('.imgParent'), res.link);
let input = e.target.previousElementSibling.querySelector('.editIcon > input') || e.target.previousElementSibling;
input.value = res.link;
if (input === authorLink) ((json.embed ??= {}).author ??= {}).icon_url = res.link;
else if (input === thumbLink) ((json.embed ??= {}).thumbnail ??= {}).url = res.link;
else if (input === imgLink) ((json.embed ??= {}).image ??= {}).url = res.link;
else ((json.embed ??= {}).footer ??= {}).url = res.link;
update(json);
console.info(`Image (${res.link}) will be deleted in 10 minutes. To delete it now, go to ${res.link.replace('/files', '/del')} and enter this code: ${res.authkey}`);
}).catch(err => error(`Request to tempfile.site failed with error: ${err}`, 5000))
}))
} }
let files = document.querySelectorAll('input[type="file"]');
files.forEach(f => f.addEventListener('change', e => {
if (f.files) {
e.target.nextElementSibling.click();
e.target.closest('.edit').querySelector('.browse').classList.add('loading');
}
}))
document.querySelectorAll('form').forEach(form => form.addEventListener('submit', e => {
e.preventDefault();
let formData = new FormData(e.target);
formData.append('file', files.files);
formData.append('datetime', '10m');
fetch('https://tempfile.site/api/files', {
method: 'POST',
body: formData,
})
.then(res => res.json())
.then(res => {
let browse = e.target.closest('.edit').querySelector('.browse');
browse.classList.remove('loading');
if (!res.ok) {
console.log(res.error);
browse.classList.add('error');
return setTimeout(() => browse.classList.remove('error'), 5000)
}
imgSrc(e.target.previousElementSibling.querySelector('.editIcon > .imgParent') || e.target.closest('.editIcon').querySelector('.imgParent'), res.link);
let input = e.target.previousElementSibling.querySelector('.editIcon > input') || e.target.previousElementSibling;
input.value = res.link;
if (input === authorLink) ((json.embed ??= {}).author ??= {}).icon_url = res.link;
else if (input === thumbLink) ((json.embed ??= {}).thumbnail ??= {}).url = res.link;
else if (input === imgLink) ((json.embed ??= {}).image ??= {}).url = res.link;
else ((json.embed ??= {}).footer ??= {}).url = res.link;
update(json);
console.info(`Image (${res.link}) will be deleted in 10 minutes. To delete it now, go to ${res.link.replace('/files', '/del')} and enter this code: ${res.authkey}`);
}).catch(err => error(`Request to tempfile.site failed with error: ${err}`, 5000))
}))
}
buildGui(json); buildGui(json);
fields = gui.querySelector('.fields ~ .edit'); fields = gui.querySelector('.fields ~ .edit');
update = data => { update = data => {

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

675
comp.js Normal file
View file

@ -0,0 +1,675 @@
// Want to use or contribute to this? https://github.com/Glitchii/embedbuilder
// If you found an issue, please report it, make a P.R, or use the discussion page. Thanks
var activeFields, colNum = 1, num = 0,
toRGB = (hex, reversed, integer) => {
if (reversed) return '#' + hex.match(/[\d]+/g).map(x => parseInt(x).toString(16).padStart(2, '0')).join('');
if (integer) return parseInt(hex.match(/[\d]+/g).map(x => parseInt(x).toString(16).padStart(2, '0')).join(''), 16);
if (hex.includes(',')) return hex.match(/[\d]+/g);
hex = hex.replace('#', '').match(/.{1,2}/g)
return [parseInt(hex[0], 16), parseInt(hex[1], 16), parseInt(hex[2], 16), 1];
}, json = {
content: "You can~~not~~ do `this`.```py\nAnd this.\nprint('Hi')```\n*italics* or _italics_ __*underline italics*__\n**bold** __**underline bold**__\n***bold italics*** __***underline bold italics***__\n__underline__ ~~Strikethrough~~",
embed: {
title: "Hello ~~people~~ world :wave:",
description: "You can use [links](https://discord.com) or emojis :smile: 😎\n```\nAnd also code blocks\n```",
color: 4321431,
timestamp: new Date().toISOString(),
url: "https://discord.com",
author: {
name: "Author name",
url: "https://discord.com",
icon_url: "https://unsplash.it/100"
},
thumbnail: {
url: "https://unsplash.it/200"
},
image: {
url: "https://unsplash.it/380/200"
},
footer: {
text: "Footer text",
icon_url: "https://unsplash.it/100"
},
fields: [
{
name: "Field 1, *lorem* **ipsum**, ~~dolor~~",
value: "Field value"
},
{
name: "Field 2",
value: "You can use custom emojis <:Kekwlaugh:722088222766923847>. <:GangstaBlob:742256196295065661>",
inline: false
},
{
name: "Inline field",
value: "Fields can be inline",
inline: true
},
{
name: "Inline field",
value: "*Lorem ipsum*",
inline: true
},
{
name: "Inline field",
value: "value",
inline: true
},
{
name: "Another field",
value: "> Nope, didn't forget about code blocks",
inline: false
}
]
}
};
window.onload = () => {
document.querySelectorAll('img.clickable')
.forEach(e => e.addEventListener('click', el => window.open(el.target.src)));
let editorHolder = document.querySelector('.editorHolder'),
guiParent = document.querySelector('.top'),
embedContent = document.querySelector('.messageContent'),
embedCont = document.querySelector('.messageContent + .container'),
gui = guiParent.querySelector('.gui:first-of-type');
window.editor = CodeMirror(elt => editorHolder.parentNode.replaceChild(elt, editorHolder), {
value: JSON.stringify(json, null, 4),
extraKeys: { Tab: cm => cm.replaceSelection(" ", "end") },
gutters: ["CodeMirror-foldgutter", "CodeMirror-lint-markers"],
scrollbarStyle: "overlay",
mode: "application/json",
theme: 'material-darker',
matchBrackets: true,
foldGutter: true,
lint: true,
});
editor.focus();
let notif = document.querySelector('.notification'),
url = (url) => /^(https?:)?\/\//g.exec(url) ? url : '//' + url,
makeShort = (txt, length, mediaWidth) => {
if (mediaWidth && window.matchMedia(`(max-width:${mediaWidth}px)`).matches)
return txt.length > (length - 3) ? txt.substring(0, length - 3) + '...' : txt;
return txt;
}, error = (msg, time) => {
notif.innerHTML = msg, notif.style.display = 'block';
time && setTimeout(() => notif.animate({ opacity: '0', bottom: '-50px', offset: 1 }, { easing: 'ease', duration: 500 })
.onfinish = () => notif.style.removeProperty('display'), time);
return false;
}, allGood = e => {
let str = JSON.stringify(e, null, 4), re = /("(?:icon_)?url": *")((?!\w+?:\/\/).+)"/g.exec(str);
if (e.timestamp && new Date(e.timestamp).toString() === "Invalid Date") return error('Timestamp is invalid');
if (re) { // If a URL is found without a protocol
if (!/\w+:|\/\/|^\//g.exec(re[2]) && re[2].includes('.')) {
let activeInput = document.querySelector('input[class$="link" i]:focus')
if (activeInput) {
lastPos = activeInput.selectionStart + 7;
authorLink.value = `http://${re[2]}`;
update(JSON.parse(str.replace(re[0], `${re[1]}http://${re[2]}"`)));
activeInput.setSelectionRange(lastPos, lastPos)
return true;
}
}
return error(`URL should have a protocol. Did you mean <span class="inline full short">http://${makeShort(re[2], 30, 600).replace(' ', '')}</span>?`);
}
return true;
}, markup = (txt, opts) => {
txt = txt
.replace(/\&#60;:[^:]+:(\d+)\&#62;/g, '<img class="emoji" src="https://cdn.discordapp.com/emojis/$1.png"/>')
.replace(/\&#60;a:[^:]+:(\d+)\&#62;/g, '<img class="emoji" src="https://cdn.discordapp.com/emojis/$1.gif"/>')
.replace(/~~(.+?)~~/g, '<s>$1</s>')
.replace(/\*\*\*(.+?)\*\*\*/g, '<em><strong>$1</strong></em>')
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
.replace(/__(.+?)__/g, '<u>$1</u>')
.replace(/\*(.+?)\*/g, '<em>$1</em>')
.replace(/_(.+?)_/g, '<em>$1</em>')
if (opts.inlineBlock) txt = txt.replace(/\`([^\`]+?)\`|\`\`([^\`]+?)\`\`|\`\`\`((?:\n|.)+?)\`\`\`/g, (m, x, y, z) => x ? `<code class="inline">${x}</code>` : y ? `<code class="inline">${y}</code>` : z ? `<code class="inline">${z}</code>` : m);
else txt = txt.replace(/\`\`\`(\w{1,15})?\n((?:\n|.)+?)\`\`\`|\`\`(.+?)\`\`(?!\`)|\`([^\`]+?)\`/g, (m, w, x, y, z) => w && x ? `<pre><code class="${w}">${x}</code></pre>` : x ? `<pre><code class="hljs nohighlight">${x}</code></pre>` : y || z ? `<code class="inline">${y || z}</code>` : m);
if (opts.inEmbed) txt = txt.replace(/\[([^\[\]]+)\]\((.+?)\)/g, `<a title="$1" target="_blank" class="anchor" href="$2">$1</a>`);
if (opts.replaceEmojis) txt = txt.replace(/(?<!code(?: \w+=".+")?>[^>]+)(?<!\/[^\s"]+?):((?!\/)\w+):/g, (match, x) => x && emojis[x] ? emojis[x] : match);
txt = txt
.replace(/(?<=\n|^)\s*&#62;\s+([^\n]+)/g, '<div class="blockquote"><div class="blockquoteDivider"></div><blockquote>$1</blockquote></div>')
.replace(/\n/g, '<br>');
return txt;
},
embed = document.querySelector('.embedGrid'),
msgEmbed = document.querySelector('.msgEmbed'),
embedTitle = document.querySelector('.embedTitle'),
embedDescription = document.querySelector('.embedDescription'),
embedAuthor = document.querySelector('.embedAuthor'),
embedFooter = document.querySelector('.embedFooter'),
embedImage = document.querySelector('.embedImage'),
embedThumbnail = document.querySelector('.embedThumbnail'),
embedFields = embed.querySelector('.embedFields'),
encodeHTML = str => str.replace(/[\u00A0-\u9999<>\&]/g, i => '&#' + i.charCodeAt(0) + ';'),
tstamp = stringISO => {
let date = stringISO ? new Date(stringISO) : new Date(),
dateArray = date.toLocaleString('en-US', { hour: 'numeric', hour12: true, minute: 'numeric' }),
today = new Date(),
yesterday = new Date(new Date().setDate(today.getDate() - 1));
return today.toDateString() === date.toDateString() ? `Today at ${dateArray}` :
yesterday.toDateString() === date.toDateString() ? `Yesterday at ${dateArray}` :
`${String(date.getMonth() + 1).padStart(2, '0')}/${String(date.getDate()).padStart(2, '0')}/${date.getFullYear()}`;
}, display = (el, data, displayType) => {
if (data) el.innerHTML = data;
el.style.display = displayType || "unset";
}, hide = el => el.style.removeProperty('display'),
imgSrc = (elm, src, remove) => remove ? elm.style.removeProperty('content') : elm.style.content = `url(${src})`,
toObj = jsonString => JSON.parse(jsonString.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (x, y) => y ? "" : x));
buildGui = (object, opts) => {
gui.innerHTML = `
<div class="item content"><p class="ttle">Message content</p></div>
<div class="edit">
<textarea class="editContent" placeholder="Message content" maxlength="2000" autocomplete="off">${encodeHTML(object.content || '')}</textarea>
</div>
<div class="item author rows2"><p class="ttle">Author</p></div>
<div class="edit">
<div class="linkName">
<div class="editIcon">
<span class="imgParent" ${object.embed?.author?.icon_url ? 'style="content: url(' + encodeHTML(object.embed.author.icon_url) + ')"' : ''}></span>
<input class="editAuthorLink" type="text" value="${encodeHTML(object.embed?.author?.icon_url || '')}" placeholder="Icon URL" autocomplete="off"/>
</div>
<div class="editName">
<input class="editAuthorName" type="text" value="${encodeHTML(object.embed?.author?.name || '')}" placeholder="Author name" autocomplete="off" />
</div>
</div>
<form method="post" enctype="multipart/form-data">
<input class="browserAuthorLink" type="file" name="file" id="file2" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" />
<button type="submit"></button>
<label for="file2">
<div class="browse">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve">
<g>
<path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path>
<path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path>
</g>
</svg>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="30" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform>
</circle>
</svg>
</svg>
</svg>
<p></p>
</div>
</label>
</form>
</div>
</div>
</div>
<div class="item title inlineField">
<p class="ttle">Title</p>
<input class="editTitle" type="text" placeholder="Title" autocomplete="off" maxlength="256" value="${encodeHTML(object.embed?.title || '')}">
</div>
<div class="item description"><p class="ttle">Description</p></div>
<div class="edit">
<textarea class="editDescription" placeholder="Embed description" maxlength="2048" autocomplete="off">${encodeHTML(object.embed?.description || '')}</textarea>
</div>
<div class="item fields"><p class="ttle">Fields</p></div>
<div class="edit"></div>
<div class="item thumbnail largeImg"><p class="ttle">Thumbnail</p></div>
<div class="edit">
<div class="linkName">
<div class="editIcon">
<span class="imgParent" ${object.embed?.thumbnail?.url ? 'style="content: url(' + encodeHTML(object.embed.thumbnail.url) + ')"' : ''}></span>
<div class="txtCol">
<input class="editThumbnailLink" type="text" value="${encodeHTML(object.embed?.thumbnail?.url || '')}" placeholder="Thumbnail URL" autocomplete="off" />
<form method="post" enctype="multipart/form-data">
<input class="browseThumbLink" type="file" name="file" id="file3" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" />
<button type="submit"></button>
<label for="file3">
<div class="browse">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve">
<g>
<path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path>
<path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path>
</g>
</svg>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="30" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform>
</circle>
</svg>
<p></p>
</div>
</label>
</form>
</div>
</div>
</div>
</div>
<div class="item image largeImg"><p class="ttle">Image</p></div>
<div class="edit">
<div class="linkName">
<div class="editIcon">
<span class="imgParent" ${object.embed?.image?.url ? 'style="content: url(' + encodeHTML(object.embed.image.url) + ')"' : ''}></span>
<div class="txtCol">
<input class="editImageLink" type="text" value="${encodeHTML(object.embed?.image?.url || '')}" placeholder="Image URL" autocomplete="off" />
<form method="post" enctype="multipart/form-data">
<input class="browseImageLink" type="file" name="file" id="file4" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" />
<button type="submit"></button>
<label for="file4">
<div class="browse">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve">
<g>
<path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path>
<path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path>
</g>
</svg>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="30" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform>
</circle>
</svg>
<p></p>
</div>
</label>
</form>
</div>
</div>
</div>
</div>
<div class="item footer rows2"><p class="ttle">Footer</p></div>
<div class="edit">
<div class="linkName">
<div class="editIcon">
<span class="imgParent" ${object.embed?.footer?.icon_url ? 'style="content: url(' + encodeHTML(object.embed.footer.icon_url) + ')"' : ''}></span>
<input class="editFooterLink" type="text" value="${encodeHTML(object.embed?.footer?.icon_url || '')}" placeholder="Icon URL" autocomplete="off"/>
</div>
<div class="editName">
<input class="editFooterText" type="text" maxlength="2048" value="${encodeHTML(object.embed?.footer?.text || '')}" placeholder="Footer text" autocomplete="off" />
</div>
</div>
<form method="post" enctype="multipart/form-data">
<input class="browserFooterLink" type="file" name="file" id="file" accept="image/png,image/gif,image/jpeg,image/webp" autocomplete="off" />
<button type="submit"></button>
<label for="file">
<div class="browse">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 64 64" xml:space="preserve">
<g>
<path xmlns="http://www.w3.org/2000/svg" d="m23.414 21.414 6.586-6.586v29.172c0 1.104.896 2 2 2s2-.896 2-2v-29.172l6.586 6.586c.39.391.902.586 1.414.586s1.024-.195 1.414-.586c.781-.781.781-2.047 0-2.828l-10-10c-.78-.781-2.048-.781-2.828 0l-10 10c-.781.781-.781 2.047 0 2.828.78.781 2.048.781 2.828 0z" fill="#ffffff" data-original="#000000"></path>
<path xmlns="http://www.w3.org/2000/svg" d="m50 40c-1.104 0-2 .896-2 2v8c0 1.103-.897 2-2 2h-28c-1.103 0-2-.897-2-2v-8c0-1.104-.896-2-2-2s-2 .896-2 2v8c0 3.309 2.691 6 6 6h28c3.309 0 6-2.691 6-6v-8c0-1.104-.896-2-2-2z" fill="#ffffff" data-original="#000000"></path>
</g>
</svg>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve">
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="30" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"></animateTransform>
</circle>
<circle fill="#fff" stroke="none" cx="54" cy="50" r="6">
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"></animateTransform>
</circle>
</svg>
</svg>
</svg>
<p></p>
</div>
</label>
</form>
</div>`;
let fieldsEditor = gui.querySelector('.fields ~ .edit'), addField = `
<div class="addField">
<p>New Field</p>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" x="0" y="0" viewBox="0 0 477.867 477.867" xml:space="preserve">
<g>
<g xmlns="http://www.w3.org/2000/svg">
<g>
<path d="M392.533,0h-307.2C38.228,0.056,0.056,38.228,0,85.333v307.2c0.056,47.105,38.228,85.277,85.333,85.333h307.2 c47.105-0.056,85.277-38.228,85.333-85.333v-307.2C477.81,38.228,439.638,0.056,392.533,0z M443.733,392.533 c0,28.277-22.923,51.2-51.2,51.2h-307.2c-28.277,0-51.2-22.923-51.2-51.2v-307.2c0-28.277,22.923-51.2,51.2-51.2h307.2 c28.277,0,51.2,22.923,51.2,51.2V392.533z" fill="#ffffff" data-original="#000000"
></path>
</g>
</g>
<g xmlns="http://www.w3.org/2000/svg">
<g>
<path d="M324.267,221.867H256V153.6c0-9.426-7.641-17.067-17.067-17.067s-17.067,7.641-17.067,17.067v68.267H153.6 c-9.426,0-17.067,7.641-17.067,17.067S144.174,256,153.6,256h68.267v68.267c0,9.426,7.641,17.067,17.067,17.067 S256,333.692,256,324.267V256h68.267c9.426,0,17.067-7.641,17.067-17.067S333.692,221.867,324.267,221.867z" fill="#ffffff" data-original="#000000"></path>
</g>
</g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
<g xmlns="http://www.w3.org/2000/svg"></g>
</g>
</svg>
</div>`;
if (object.embed?.fields) fieldsEditor.innerHTML = object.embed.fields.filter(f => f && typeof f === 'object').map(f => `
<div class="field">
<div class="fieldNumber"></div>
<div class="fieldInner">
<div class="designerFieldName">
<input type="text" placeholder="Field name" autocomplete="off" maxlength="256" value="${encodeHTML(f.name)}">
</div>
<div class="designerFieldValue">
<textarea placeholder="Field value" autocomplete="off" maxlength="1024">${encodeHTML(f.value)}</textarea>
</div>
</div>
<div class="inlineCheck">
<label>
<input type="checkbox" autocomplete="off" ${f.inline ? 'checked' : ''}>
<span>Inline</span>
</label>
</div>
<div class="removeBtn">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" version="1.1" width="512" height="512" x="0" y="0" viewBox="0 0 329.26933 329" xml:space="preserve">
<g>
<path xmlns="http://www.w3.org/2000/svg" d="m194.800781 164.769531 128.210938-128.214843c8.34375-8.339844 8.34375-21.824219 0-30.164063-8.339844-8.339844-21.824219-8.339844-30.164063 0l-128.214844 128.214844-128.210937-128.214844c-8.34375-8.339844-21.824219-8.339844-30.164063 0-8.34375 8.339844-8.34375 21.824219 0 30.164063l128.210938 128.214843-128.210938 128.214844c-8.34375 8.339844-8.34375 21.824219 0 30.164063 4.15625 4.160156 9.621094 6.25 15.082032 6.25 5.460937 0 10.921875-2.089844 15.082031-6.25l128.210937-128.214844 128.214844 128.214844c4.160156 4.160156 9.621094 6.25 15.082032 6.25 5.460937 0 10.921874-2.089844 15.082031-6.25 8.34375-8.339844 8.34375-21.824219 0-30.164063zm0 0" fill="#ffffff" data-original="#000000"/>
</g>
</svg>
<span>Remove</span>
</div>
</div>`).join('\n') + addField;
else fieldsEditor.innerHTML = addField;
gui.querySelectorAll('.removeBtn').forEach(e => {
e.addEventListener('click', el => {
fields = gui.querySelector('.fields ~ .edit');
let field = el.target.closest('.field');
if (field) {
let i = Array.from(fields.children).indexOf(field), jsonField = object.embed.fields[i];
if (jsonField) {
object.embed.fields.splice(i, 1);
field.remove();
update(object);
}
}
})
})
document.querySelectorAll('.gui > .item').forEach(e => {
e.addEventListener('click', el => {
let elm = (el.target.closest('.top>.gui>.item') || el.target);
if (elm.classList.contains('active')) window.getSelection().anchorNode !== elm && elm.classList.remove('active');
else {
let inlineField = elm.closest('.inlineField'),
input = elm.nextElementSibling.querySelector('input[type="text"]'),
txt = elm.nextElementSibling.querySelector('textarea');
elm.classList.add('active');
if (inlineField) inlineField.querySelector('.ttle~input').focus();
else if (input) {
input.focus();
input.selectionStart = input.selectionEnd = input.value.length;
} else if (txt) txt.focus();
elm.classList.contains('fields') && elm.scrollIntoView({ behavior: "smooth", block: "center" });
}
})
})
content = gui.querySelector('.editContent');
title = gui.querySelector('.editTitle');
authorName = gui.querySelector('.editAuthorName');
authorLink = gui.querySelector('.editAuthorLink');
desc = gui.querySelector('.editDescription');
thumbLink = gui.querySelector('.editThumbnailLink');
imgLink = gui.querySelector('.editImageLink');
footerText = gui.querySelector('.editFooterText');
footerLink = gui.querySelector('.editFooterLink');
fields = gui.querySelector('.fields ~ .edit');
document.querySelector('.addField').addEventListener('click', () => {
!json.embed && (json.embed = {});
let arr = json.embed.fields || [];
if (arr.length >= 25) return error('Cannot have more than 25 fields', 5000);
arr.push({ name: "Field name", value: "Field value", inline: false });
json.embed.fields = arr;
update(json);
buildGui(json, { newField: true, activate: document.querySelectorAll('.gui > .item.active') });
})
gui.querySelectorAll('textarea, input').forEach(e => e.addEventListener('input', el => {
let value = el.target.value, field = el.target.closest('.field');
if (field) {
let jsonField = json.embed.fields[Array.from(fields.children).indexOf(field)];
if (jsonField) {
if (el.target.type === 'text') jsonField.name = value;
else if (el.target.type === 'textarea') jsonField.value = value;
else jsonField.inline = el.target.checked;
} else {
let obj = {}
if (el.target.type === 'text') obj.name = value;
else if (el.target.type === 'textarea') obj.value = value;
else obj.inline = el.target.checked;
json.embed.fields.push(obj);
}
} else {
json.embed ??= {};
switch (el.target) {
case content: json.content = value; break;
case title: json.embed.title = value; break;
case authorName: json.embed.author ??= {}, json.embed.author.name = value; break;
case authorLink: json.embed.author ??= {}, json.embed.author.icon_url = value, imgSrc(el.target.previousElementSibling, value); break;
case desc: json.embed.description = value; break;
case thumbLink: json.embed.thumbnail ??= {}, json.embed.thumbnail.url = value, imgSrc(el.target.closest('.editIcon').querySelector('.imgParent'), value); break;
case imgLink: json.embed.image ??= {}, json.embed.image.url = value, imgSrc(el.target.closest('.editIcon').querySelector('.imgParent'), value); break;
case footerText: json.embed.footer ??= {}, json.embed.footer.text = value; break;
case footerLink: json.embed.footer ??= {}, json.embed.footer.icon_url = value, imgSrc(el.target.previousElementSibling, value); break;
}
}
update(json);
}))
if (opts?.activate) {
let elements = opts.activate;
Array.from(elements).map(el => el.className).map(clss => '.' + clss.split(' ').slice(0, 2).join('.'))
.forEach(clss => document.querySelectorAll(clss)
.forEach(e => e.classList.add('active')))
} else['.item.author', '.item.description'].forEach(clss => document.querySelector(clss).classList.add('active'));
if (opts?.newField) {
let last = fields.children[fields.childElementCount - 2], el = last.querySelector('.designerFieldName > input');
el.setSelectionRange(el.value.length, el.value.length); el.focus();
last.scrollIntoView({ behavior: "smooth", block: "center" });
}
let files = document.querySelectorAll('input[type="file"]');
files.forEach(f => f.addEventListener('change', e => {
if (f.files) {
e.target.nextElementSibling.click();
e.target.closest('.edit').querySelector('.browse').classList.add('loading');
}
}))
document.querySelectorAll('form').forEach(form => form.addEventListener('submit', e => {
e.preventDefault();
let formData = new FormData(e.target);
formData.append('file', files.files);
formData.append('datetime', '10m');
fetch('https://tempfile.site/api/files', {
method: 'POST',
body: formData,
})
.then(res => res.json())
.then(res => {
let browse = e.target.closest('.edit').querySelector('.browse');
browse.classList.remove('loading');
if (!res.ok) {
console.log(res.error);
browse.classList.add('error');
return setTimeout(() => browse.classList.remove('error'), 5000)
}
imgSrc(e.target.previousElementSibling.querySelector('.editIcon > .imgParent') || e.target.closest('.editIcon').querySelector('.imgParent'), res.link);
let input = e.target.previousElementSibling.querySelector('.editIcon > input') || e.target.previousElementSibling;
input.value = res.link;
if (input === authorLink) ((json.embed ??= {}).author ??= {}).icon_url = res.link;
else if (input === thumbLink) ((json.embed ??= {}).thumbnail ??= {}).url = res.link;
else if (input === imgLink) ((json.embed ??= {}).image ??= {}).url = res.link;
else ((json.embed ??= {}).footer ??= {}).url = res.link;
update(json);
console.info(`Image (${res.link}) will be deleted in 10 minutes. To delete it now, go to ${res.link.replace('/files', '/del')} and enter this code: ${res.authkey}`);
}).catch(err => error(`Request to tempfile.site failed with error: ${err}`, 5000))
}))
}
buildGui(json);
fields = gui.querySelector('.fields ~ .edit');
update = data => {
try {
if (!data.content) embedContent.classList.add('empty');
else {
embedContent.innerHTML = markup(encodeHTML(data.content), { replaceEmojis: true });
embedContent.classList.remove('empty');
}
if (data.embed && Object.keys(data.embed).length) {
let e = data.embed;
if (!allGood(e)) return;
if (e.title) display(embedTitle, markup(`${e.url ? '<a class="anchor" target="_blank" href="' + encodeHTML(url(e.url)) + '">' + encodeHTML(e.title) + '</a>' : encodeHTML(e.title)}`, { replaceEmojis: true, inlineBlock: true }));
else hide(embedTitle);
if (e.description) display(embedDescription, markup(encodeHTML(e.description), { inEmbed: true, replaceEmojis: true }));
else hide(embedDescription);
if (e.color) embed.closest('.embed').style.borderColor = encodeHTML(typeof e.color === 'number' ? '#' + e.color.toString(16).padStart(6, "0") : e.color);
else embed.closest('.embed').style.removeProperty('border-color');
if (e.author && e.author.name) display(embedAuthor, `
${e.author.icon_url ? '<img class="embedAuthorIcon" src="' + encodeHTML(url(e.author.icon_url)) + '">' : ''}
${e.author.url ? '<a class="embedAuthorNameLink embedLink embedAuthorName" href="' + encodeHTML(url(e.author.url)) + '" target="_blank">' + encodeHTML(e.author.name) + '</a>' : '<span class="embedAuthorName">' + encodeHTML(e.author.name) + '</span>'}`, 'flex');
else hide(embedAuthor);
if (e.thumbnail && e.thumbnail.url) embedThumbnail.src = encodeHTML(e.thumbnail.url), embedThumbnail.style.display = 'block';
else hide(embedThumbnail);
if (e.image && e.image.url) embedImage.src = encodeHTML(e.image.url), embedImage.style.display = 'block';
else hide(embedImage);
if (e.footer && e.footer.text) display(embedFooter, `
${e.footer.icon_url ? '<img class="embedFooterIcon" src="' + encodeHTML(url(e.footer.icon_url)) + '">' : ''}<span class="embedFooterText">
${encodeHTML(e.footer.text)}
${e.timestamp ? '<span class="embedFooterSeparator">•</span>' + encodeHTML(tstamp(e.timestamp)) : ''}</span></div>`, 'flex');
else if (e.timestamp) display(embedFooter, `<span class="embedFooterText">${encodeHTML(tstamp(e.timestamp))}</span></div>`, 'flex');
else hide(embedFooter);
if (e.fields) {
embedFields.innerHTML = '';
e.fields.forEach(f => {
if (f.name && f.value) {
if (!f.inline) {
let el = embedFields.insertBefore(document.createElement('div'), null);
el.outerHTML = `
<div class="embedField" style="grid-column: 1 / 13;">
<div class="embedFieldName">${markup(encodeHTML(f.name), { inEmbed: true, replaceEmojis: true, inlineBlock: true })}</div>
<div class="embedFieldValue">${markup(encodeHTML(f.value), { inEmbed: true, replaceEmojis: true })}</div>
</div>`;
} else {
el = embedFields.insertBefore(document.createElement('div'), null);
el.outerHTML = `
<div class="embedField ${num}" style="grid-column: ${colNum} / ${colNum + 4};">
<div class="embedFieldName">${markup(encodeHTML(f.name), { inEmbed: true, replaceEmojis: true, inlineBlock: true })}</div>
<div class="embedFieldValue">${markup(encodeHTML(f.value), { inEmbed: true, replaceEmojis: true })}</div>
</div>`;
colNum = (colNum === 9 ? 1 : colNum + 4);
num++;
}
}
});
colNum = 1;
let len = e.fields.filter(f => f.inline).length;
if (len === 2 || (len > 3 && len % 2 !== 0)) {
let children = Array.from(embedFields.children), arr = children.filter(x => x === children[len] || x === children[len - 1]);
arr[0] && (arr[0].style.gridColumn = '1 / 7');
arr[1] && (arr[1].style.gridColumn = '7 / 13');
}
display(embedFields, undefined, 'grid');
} else hide(embedFields);
embedCont.classList.remove('empty');
document.querySelectorAll('.markup pre > code').forEach((block) => hljs.highlightBlock(block));
notif.animate({ opacity: '0', bottom: '-50px', offset: 1 }, { easing: 'ease', duration: 500 }).onfinish = () => notif.style.removeProperty('display');
twemoji.parse(msgEmbed);
} else embedCont.classList.add('empty');
} catch (e) {
error(e);
}
}
editor.on('change', editor => {
try { update(toObj(editor.getValue())); }
catch (e) {
if (editor.getValue()) return;
embedCont.classList.add('empty');
embedContent.innerHTML = '';
}
});
let picker = new CP(document.querySelector('.picker'), state = { parent: document.querySelector('.cTop') });
picker.fire('change', toRGB('#41f097'));
let colRight = document.querySelector('.colRight'), removePicker = () => colRight.classList.remove('picking');
document.querySelector('.colBack').addEventListener('click', e => {
picker.self.remove(); removePicker();
})
picker.on('enter', () => colRight.classList.add('picking'))
picker.on('exit', removePicker);
document.querySelectorAll('.colr').forEach(e => e.addEventListener('click', el => {
el = el.target.closest('.colr') || el.target;
embed.closest('.embed').style.borderColor = el.style.backgroundColor;
json.embed && (json.embed.color = toRGB(el.style.backgroundColor, false, true));
picker.source.style.removeProperty('background');
}))
setTimeout(() => {
picker.on('change', function (r, g, b, a) {
embed.closest('.embed').style.borderColor = this.color(r, g, b);
json.embed && (json.embed.color = parseInt(this.color(r, g, b).slice(1), 16));
picker.source.style.background = this.color(r, g, b);
})
}, 1000)
document.querySelector('.timeText').innerText = tstamp();
document.querySelectorAll('.markup pre > code').forEach((block) => hljs.highlightBlock(block));
!window.navigator.userAgent.match(/Firefox\/[\d\.]+$/g) && // Firefox pushes the text up a little
document.querySelector('.botText').style.removeProperty('top');
document.querySelector('.opt.gui').addEventListener('click', () => {
json = toObj(editor.getValue() || '{}');
buildGui(json, { activate: activeFields });
document.body.classList.add('gui');
activeFields = null;
})
document.querySelector('.opt.json').addEventListener('click', () => {
editor.setValue(JSON.stringify(json, null, 4));
editor.refresh();
document.body.classList.remove('gui');
editor.focus();
activeFields = document.querySelectorAll('.gui > .item.active');
})
document.querySelector('.clear').addEventListener('click', () => {
json = {};
embed.style.removeProperty('border-color');
picker.source.style.removeProperty('background');
update(json); buildGui(json); editor.setValue(JSON.stringify(json, null, 4));
document.querySelectorAll('.gui>.item').forEach(e => e.classList.add('active'));
content.focus();
})
let colrs = document.querySelector('.colrs');
document.querySelector('.pickerToggle').addEventListener('click', () => colrs.classList.toggle('display'));
update(json);
};

View file

@ -3,6 +3,14 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Build and preview Discord embeds outside Discord.">
<meta property="og:site_name" content="EmbedBuilder">
<meta property="og:title" content="EmbedBuilder">
<meta property="og:description" content="Build and preview Discord embeds outside Discord.">
<meta property="og:url" content="/">
<meta property="og:type" content="website" />
<meta property="og:image" content="/assets/media/screenshot2.png">
<meta name="twitter:card" content="/assets/media/screenshot2.png">
<link rel="icon" href="data:;base64,iVBORw0KGgo=" /> <link rel="icon" href="data:;base64,iVBORw0KGgo=" />
<title>Embed Builder</title> <title>Embed Builder</title>
<link rel="stylesheet" href="./assets/css/index.css" /> <link rel="stylesheet" href="./assets/css/index.css" />