1024 lines
35 KiB
JavaScript
Executable File
1024 lines
35 KiB
JavaScript
Executable File
/*!
|
|
* molybdenum v1.0.250619.1428
|
|
* Copyright 2025 PT Nusa Angkasa Siber
|
|
* Released under the MIT License
|
|
*/
|
|
class molybdenum{
|
|
version = '1.0.250619.1428';
|
|
_alerts = [];
|
|
_confirms = [];
|
|
_loads = [];
|
|
_dialogs = [];
|
|
lastDialog()
|
|
{
|
|
return this._dialogs.at(-1);
|
|
}
|
|
lastLoadScreenId()
|
|
{
|
|
if(this._loads.length > 0)
|
|
{
|
|
return this._loads.at(-1).id;
|
|
}
|
|
return null;
|
|
}
|
|
newElement(name = "div", options = {}){
|
|
const ele = document.createElement(name);
|
|
options.style ? ele.style = options.style : null;
|
|
options.className ? ele.className = options.className : null;
|
|
typeof options.append === 'string' ? ele.append(options.append) : options.append instanceof Element ? ele.append(options.append) : null;
|
|
typeof options.href === 'string' && ele.nodeName === "A" ? ele.setAttribute("href",options.href) : null;
|
|
return ele;
|
|
}
|
|
customElement(name = "div", options = {})
|
|
{
|
|
const par = document.createElement("div");
|
|
par.innerHTML=`<${name}></${name}>`;
|
|
const ele = par.firstChild;
|
|
options.style ? ele.style = options.style : null;
|
|
options.className ? ele.className = options.className : null;
|
|
typeof options.append === 'string' ? ele.append(options.append) : options.append instanceof Element ? ele.append(options.append) : null;
|
|
typeof options.href === 'string' && ele.nodeName === "A" ? ele.setAttribute("href",options.href) : null;
|
|
return ele;
|
|
}
|
|
loadScreen = class {
|
|
static clear()
|
|
{
|
|
$('load-screen').remove();
|
|
moly._loads = [];
|
|
}
|
|
static show(message = "", style = "sonar", target = "body")
|
|
{
|
|
if (target != "body" && ($(target).length != 1 || $(target).prevObject))
|
|
{
|
|
console.error("Target Invalid: " + JSON.stringify($(target)));
|
|
return -1;
|
|
}
|
|
let sid = Date.now() + Math.random().toString(16).slice(2);
|
|
let ls = moly.newElement("load-screen");
|
|
let lm = moly.newElement("load-message");
|
|
lm.append(message);
|
|
if (style == "dots")
|
|
{
|
|
let p = moly.newElement("chat-load")
|
|
ls.append(p);
|
|
p.append(moly.newElement("span"));
|
|
p.append(moly.newElement("span"));
|
|
p.append(moly.newElement("span"));
|
|
}
|
|
else if (style == "bar")
|
|
{
|
|
ls.append(moly.newElement("progress-loop"));
|
|
}
|
|
else
|
|
{
|
|
ls.append(moly.newElement("sonar-ping"));
|
|
}
|
|
ls.append(lm);
|
|
moly._loads.push({id: sid, screen: ls});
|
|
$(target).append(ls);
|
|
return sid;
|
|
}
|
|
static update(id=0, message = "")
|
|
{
|
|
let i = moly._loads.findIndex(e=> e.id == id)
|
|
if(i >= 0 && message.length > 0)
|
|
{
|
|
$(moly._loads[i].screen).children("load-message").html(message);
|
|
}
|
|
}
|
|
static close(id=0)
|
|
{
|
|
let i = moly._loads.findIndex(e=> e.id == id)
|
|
if(i >= 0)
|
|
{
|
|
moly._loads[i].screen.remove();
|
|
moly._loads.splice(i,1);
|
|
}
|
|
}
|
|
}
|
|
dialog = class {
|
|
static clear()
|
|
{
|
|
$('dialog-box').remove();
|
|
moly._dialogs = [];
|
|
}
|
|
static async show({ title = "Dialog Box", content = "", fetching = false, data = {} } = {})
|
|
{
|
|
let dialog =
|
|
{
|
|
id: Date.now() + Math.random().toString(16).slice(2),
|
|
screen: moly.newElement("dialog-screen"),
|
|
box: moly.newElement("dialog-box"),
|
|
titlet: moly.newElement("span"),
|
|
content: moly.newElement("div"),
|
|
beforeResolve: [],
|
|
resolve: undefined,
|
|
data: data
|
|
}
|
|
moly._dialogs.push(dialog);
|
|
dialog.screen.append(dialog.box)
|
|
let titlebar = moly.newElement("dialog-title");
|
|
let closebtn = moly.newElement("a-button");
|
|
let closeicn = moly.newElement("m-icon");
|
|
closebtn.append(closeicn)
|
|
closeicn.append("close");
|
|
closebtn.setAttribute("type","negative");
|
|
dialog.box.append(titlebar);
|
|
$(dialog.box).css("width",data.width);
|
|
$(dialog.box).css("height",data.height);
|
|
titlebar.append(dialog.titlet);
|
|
$(dialog.titlet).html(title);
|
|
titlebar.append(closebtn);
|
|
dialog.box.append(dialog.content);
|
|
dialog.content.setAttribute("id",`db${dialog.id}`);
|
|
dialog.content.style = "overflow-y: auto;"
|
|
$('body').append(dialog.screen);
|
|
setTimeout(()=>{
|
|
$(dialog.box).css("scale",1);
|
|
},5);
|
|
let loadid = moly.loadScreen.show("Memuat Konten...","sonar",`#db${dialog.id}`);
|
|
$(dialog.content).html(fetching ? await fetch(content).then(r => r.text()) : content);
|
|
moly.loadScreen.close(loadid);
|
|
return new Promise((resolve,reject)=>{
|
|
dialog.resolve = function(out)
|
|
{
|
|
moly.dialog.close(dialog.id);
|
|
resolve(out);
|
|
}
|
|
$(closebtn).click(()=>{
|
|
moly.dialog.close(dialog.id);
|
|
resolve(false);
|
|
});
|
|
});
|
|
}
|
|
static close(id="")
|
|
{
|
|
let i = moly._dialogs.findIndex(e => e.id == id); //this.screens.findIndex(e=> e.id == id)
|
|
if(i >= 0)
|
|
{
|
|
$(moly._dialogs[i].box).css("scale",0);
|
|
setTimeout(() => {
|
|
$.each(moly._dialogs[i].beforeResolve, (i,v)=>
|
|
{
|
|
typeof v == "function" ? v() : false;
|
|
});
|
|
moly._dialogs[i].screen.remove();
|
|
moly._dialogs.splice(i,1);
|
|
}, 250);
|
|
}
|
|
}
|
|
static resolve(id = 0, data)
|
|
{
|
|
let i = moly._dialogs.findIndex(e => e.id == id); //this.screens.findIndex(e=> e.id == id)
|
|
if(i >= 0)
|
|
{
|
|
moly._dialogs[i].resolve(data);
|
|
}
|
|
}
|
|
}
|
|
alert = class {
|
|
static show(title = "Perhatian", messageHTML = "", timeOut = 0)
|
|
{
|
|
let alert =
|
|
{
|
|
id: Date.now() + Math.random().toString(16).slice(2),
|
|
screen: moly.newElement("alert-screen"),
|
|
box: moly.newElement("alert-box"),
|
|
title: moly.newElement("alert-title"),
|
|
message: moly.newElement("alert-text"),
|
|
handle: moly.newElement("alert-handle")
|
|
}
|
|
alert.screen.append(alert.box);
|
|
alert.box.append(alert.title);
|
|
alert.box.append(alert.message);
|
|
alert.box.append(alert.handle);
|
|
alert.title.innerText = title;
|
|
alert.message.innerHTML = messageHTML;
|
|
alert.message.setAttribute("title", alert.message.innerText);
|
|
if (timeOut >0 ) {alert.handle.innerText = `Tunggu ${timeOut} detik.`;} else {alert.handle.innerText = "Tutup";}
|
|
moly._alerts.push(alert);
|
|
$('body').append(alert.screen);
|
|
setTimeout(() => {
|
|
$(alert.box).css("scale",1);
|
|
}, 5);
|
|
setTimeout(() => {
|
|
if ( timeOut > 0)
|
|
{
|
|
let ms = timeOut * 1000;
|
|
let intv = setInterval(()=>{
|
|
ms -= 1000;
|
|
if (ms <= 0)
|
|
{
|
|
moly.alert.close(alert.id);
|
|
clearInterval(intv);
|
|
return;
|
|
}
|
|
$(moly._alerts.findLast(()=>true).screen).find("alert-handle")[0].innerText = `Tunggu ${ms/1000} detik`;
|
|
},1000);
|
|
}
|
|
else
|
|
{
|
|
$(alert.handle).click(()=>
|
|
{
|
|
moly.alert.close(alert.id);
|
|
})
|
|
}
|
|
}, 250);
|
|
}
|
|
static close(id = "")
|
|
{
|
|
let ix = moly._alerts.findIndex(e=> e.id == id)
|
|
if (ix >= 0)
|
|
{
|
|
$(moly._alerts[ix].box).css("scale",0);
|
|
setTimeout(()=>{
|
|
moly._alerts[ix].screen.remove();
|
|
moly._alerts.splice(ix,1);
|
|
}, 250);
|
|
}
|
|
}
|
|
}
|
|
confirm = class {
|
|
static show(title = "Anda Yakin?", messageHTML = "", yesLabel = "Yes", noLabel = "No", positiveYes = null, positiveNo = null)
|
|
{
|
|
let confirm =
|
|
{
|
|
id: Date.now() + Math.random().toString(16).slice(2),
|
|
screen: moly.newElement("confirm-screen"),
|
|
box: moly.newElement("confirm-box"),
|
|
title: moly.newElement("confirm-title"),
|
|
message: moly.newElement("confirm-text"),
|
|
handle: moly.newElement("confirm-handle"),
|
|
resolve: undefined
|
|
}
|
|
let yes = moly.newElement("a-button");
|
|
let no = moly.newElement("a-button");
|
|
confirm.screen.append(confirm.box);
|
|
confirm.box.append(confirm.title);
|
|
confirm.box.append(confirm.message);
|
|
confirm.box.append(confirm.handle);
|
|
confirm.title.innerText = title;
|
|
confirm.message.innerHTML = messageHTML;
|
|
confirm.message.setAttribute("title", confirm.message.innerText);
|
|
confirm.handle.append(yes);
|
|
confirm.handle.append(no);
|
|
yes.innerText = yesLabel;
|
|
no.innerText = noLabel;
|
|
if (positiveYes == true)
|
|
{
|
|
yes.setAttribute("type","positive");
|
|
}
|
|
else if (positiveYes == false)
|
|
{
|
|
yes.setAttribute("type","negative");
|
|
}
|
|
else
|
|
{
|
|
yes.setAttribute("type","blend");
|
|
}
|
|
if (positiveNo == true)
|
|
{
|
|
no.setAttribute("type","positive");
|
|
}
|
|
else if (positiveNo == false)
|
|
{
|
|
no.setAttribute("type","negative");
|
|
}
|
|
else
|
|
{
|
|
no.setAttribute("type","blend");
|
|
}
|
|
moly._confirms.push(confirm);
|
|
$('body').append(confirm.screen);
|
|
setTimeout(() => {
|
|
$(confirm.box).css("scale",1);
|
|
}, 5);
|
|
return new Promise((resolve,reject)=>{
|
|
confirm.resolve = function(out)
|
|
{
|
|
moly.confirm.close(confirm.id);
|
|
resolve(out);
|
|
}
|
|
$(no).click(()=>{
|
|
moly.confirm.close(confirm.id);
|
|
resolve(false);
|
|
});
|
|
$(yes).click(()=>{
|
|
moly.confirm.close(confirm.id);
|
|
resolve(true);
|
|
});
|
|
});
|
|
}
|
|
static close(id ="")
|
|
{
|
|
let i = moly._confirms.findIndex(e => e.id == id); //this.screens.findIndex(e=> e.id == id)
|
|
if(i >= 0)
|
|
{
|
|
$(moly._confirms[i].box).css("scale",0);
|
|
setTimeout(() => {
|
|
moly._confirms[i].screen.remove();
|
|
moly._confirms.splice(i,1);
|
|
}, 250);
|
|
}
|
|
}
|
|
}
|
|
file = class {
|
|
static async crc32(file){
|
|
let crc32Table = new Uint32Array(256).map((t, c) => {
|
|
for (let k = 0; k < 8; k++) {
|
|
c = c & 1 ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1);
|
|
}
|
|
return c >>> 0;
|
|
});
|
|
const arrayBuffer = await file.arrayBuffer();
|
|
const buf = new Uint8Array(arrayBuffer);
|
|
let crc = 0 ^ (-1);
|
|
for (let i = 0; i < buf.length; i++) {
|
|
crc = (crc >>> 8) ^ crc32Table[(crc ^ buf[i]) & 0xFF];
|
|
}
|
|
return ((crc ^ (-1)) >>> 0).toString(16).padStart(8, '0').toUpperCase();
|
|
};
|
|
static async serialise(file = new File([],"")){
|
|
let hash = await this.crc32(file);
|
|
const reader = new FileReader();
|
|
return new Promise((resolve, reject) => {
|
|
reader.onload = function(event) {
|
|
const base64Data = event.target.result.split(',')[1];
|
|
const fileData = {
|
|
name: file.name,
|
|
type: file.type,
|
|
data: base64Data,
|
|
crc32: hash
|
|
};
|
|
resolve(fileData);
|
|
};
|
|
reader.onerror = reject;
|
|
reader.readAsDataURL(file);
|
|
});
|
|
};
|
|
static deserialise(fileData){
|
|
const byteCharacters = atob(fileData.data);
|
|
const byteNumbers = new Array(byteCharacters.length);
|
|
|
|
for (let i = 0; i < byteCharacters.length; i++) {
|
|
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
|
}
|
|
|
|
const byteArray = new Uint8Array(byteNumbers);
|
|
const blob = new Blob([byteArray], { type: fileData.type });
|
|
|
|
const file = new File([blob], fileData.name, { type: fileData.type });
|
|
return file;
|
|
}
|
|
}
|
|
AButton = class extends HTMLElement
|
|
{
|
|
static observedAttributes = ["disabled"];
|
|
constructor() {
|
|
super();
|
|
this.attachShadow({ mode: "open" }); // Attach Shadow DOM
|
|
this.shadowRoot.innerHTML = `
|
|
<style>
|
|
:host {
|
|
display: inline;
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
cursor: pointer;
|
|
font-family: 'Source Sans 3';
|
|
color: var(--primary-accent);
|
|
margin-inline-start: .5ch;
|
|
margin-inline-end: .5ch;
|
|
white-space: nowrap;
|
|
text-decoration: none;
|
|
filter: brightness(1);
|
|
transition: filter .35s ease, text-shadow .35s ease;
|
|
}
|
|
:host([disabled]) {
|
|
color: var(--secondary-foreground) !important;
|
|
pointer-events: none;
|
|
}
|
|
:host(:hover){
|
|
filter: brightness(1.25);
|
|
text-shadow: 0 0 .25em var(--semi-primary);
|
|
}
|
|
:host(:active){
|
|
filter: brightness(1.25);
|
|
text-shadow: 0 0 .75em var(--semi-primary);
|
|
}
|
|
:host([type="blend"]), :host([type="peek"])
|
|
{
|
|
color: inherit;
|
|
}
|
|
:host([type="blend"]:hover)
|
|
{
|
|
filter: brightness(4);
|
|
text-shadow: none;
|
|
}
|
|
:host([type="blend"]:active)
|
|
{
|
|
filter: brightness(8);
|
|
text-shadow: none;
|
|
}
|
|
:host([type="negative"])
|
|
{
|
|
color: var(--negative-accent);
|
|
}
|
|
:host([type="negative"]:hover)
|
|
{
|
|
filter: brightness(1.25);
|
|
text-shadow: 0 0 .35em var(--semi-negative);
|
|
}
|
|
:host([type="negative"]:active)
|
|
{
|
|
filter: brightness(1.25);
|
|
text-shadow: 0 0 .65em var(--semi-negative);
|
|
}
|
|
:host([type="peek"])
|
|
{
|
|
text-shadow: none;
|
|
position: absolute !important;
|
|
padding-top: .25em;
|
|
transform: translatex(-3.5ch);
|
|
}
|
|
</style>
|
|
<slot></slot>
|
|
`;
|
|
}
|
|
|
|
get disabled() {
|
|
return this.hasAttribute("disabled");
|
|
}
|
|
|
|
set disabled(value) {
|
|
if (value) {
|
|
this.setAttribute("disabled", "");
|
|
} else {
|
|
this.removeAttribute("disabled");
|
|
}
|
|
}
|
|
}
|
|
FileInput = class extends HTMLElement
|
|
{
|
|
static observedAttributes = ["disabled", "accept", "multiple"];
|
|
constructor() {
|
|
super();
|
|
this.attachShadow({ mode: "open" }); // Attach Shadow DOM
|
|
this.shadowRoot.innerHTML = `
|
|
<style>
|
|
:host
|
|
{
|
|
display: inline-flex;
|
|
width: 25ch;
|
|
height: 1.7em;
|
|
border: 1px solid var(--secondary-foreground);
|
|
user-select: none;
|
|
cursor: pointer;
|
|
text-align: center;
|
|
justify-content: center;
|
|
align-items: center;
|
|
color: var(--secondary-foreground);
|
|
}
|
|
div
|
|
{
|
|
font-size: .8em;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
overflow: hidden;
|
|
width: calc(100%);
|
|
padding-inline-start: .75ch;
|
|
padding-inline-end: .75ch;
|
|
}
|
|
</style>
|
|
`;
|
|
this._input = document.createElement("input");
|
|
this._input.type = "file";
|
|
this._input.setAttribute("hidden","");
|
|
this._handleChange = this._handleChange.bind(this);
|
|
this._handleClick = this._handleClick.bind(this);
|
|
this._label = document.createElement("div");
|
|
}
|
|
connectedCallback()
|
|
{
|
|
this._input.addEventListener("change", this._handleChange);
|
|
this.shadowRoot.appendChild(this._input);
|
|
this.shadowRoot.appendChild(this._label);
|
|
this._label.innerText = "Click to select a file.";
|
|
this.addEventListener("click", this._handleClick);
|
|
if (this.getAttribute("accept"))
|
|
{
|
|
this._input.setAttribute("accept", this.accept);
|
|
this.accept = this.getAttribute("accept");
|
|
}
|
|
if (this.hasAttribute("multiple"))
|
|
{
|
|
this._input.setAttribute("multiple", "");
|
|
this.multiple = this.hasAttribute("multiple");
|
|
this._label.innerText = "Click to select files.";
|
|
}
|
|
}
|
|
disconnectedCallback() {
|
|
this._input.removeEventListener("change", this._handleChange);
|
|
}
|
|
_handleChange(event)
|
|
{
|
|
if (this.hasAttribute("multiple") && this._input.files.length == 1)
|
|
{
|
|
this._label.innerText = `${this._input.files[0].name} selected.`;
|
|
}
|
|
else if (this.hasAttribute("multiple") && this._input.files.length > 1)
|
|
{
|
|
this._label.innerText = `${this._input.files.length} files selected.`
|
|
}
|
|
else if (this.hasAttribute("multiple"))
|
|
{
|
|
this._label.innerText = "Click to select files.";
|
|
}
|
|
else if (this._input.files.length == 1)
|
|
{
|
|
this._label.innerText = `${this._input.files[0].name} selected.`;
|
|
}
|
|
else
|
|
{
|
|
this._label.innerText = "Click to select a file.";
|
|
}
|
|
this.dispatchEvent(new CustomEvent("change", {bubble: true, composed: true, detail: this.files}));
|
|
}
|
|
_handleClick(event)
|
|
{
|
|
this._input.click();
|
|
}
|
|
get disabled() {
|
|
return this.hasAttribute("disabled");
|
|
}
|
|
|
|
set disabled(value) {
|
|
if (value) {
|
|
this.setAttribute("disabled", "");
|
|
} else {
|
|
this.removeAttribute("disabled");
|
|
}
|
|
}
|
|
get files() {
|
|
return this._input.files;
|
|
}
|
|
|
|
set accept(value) {
|
|
if (value) {
|
|
this._input.accept = value;
|
|
this.setAttribute("accept", value); // Keep the attribute in sync
|
|
} else {
|
|
this._input.removeAttribute("accept");
|
|
this.removeAttribute("accept");
|
|
}
|
|
}
|
|
|
|
get accept() {
|
|
return this._input.accept;
|
|
}
|
|
|
|
set multiple(value) {
|
|
if (value) {
|
|
this._input.setAttribute("multiple", "");
|
|
this.setAttribute("multiple", "");
|
|
this._label.innerText = "Click to select files.";
|
|
} else {
|
|
this._input.removeAttribute("multiple");
|
|
this.removeAttribute("multiple");
|
|
this._label.innerText = "Click to select a file.";
|
|
}
|
|
this._input.value = "";
|
|
}
|
|
|
|
get multiple() {
|
|
return this._input.hasAttribute("multiple");
|
|
}
|
|
reset()
|
|
{
|
|
this._input.value = "";
|
|
if (this.hasAttribute("multiple"))
|
|
{
|
|
this._label.innerText = "Click to select files.";
|
|
}
|
|
else
|
|
{
|
|
this._label.innerText = "Click to select a file.";
|
|
}
|
|
return this._input.files.length;
|
|
}
|
|
}
|
|
Group = class extends HTMLElement
|
|
{
|
|
static observedAttributes = ["label", "type", "collapsed", "disabled"];
|
|
constructor()
|
|
{
|
|
super();
|
|
this.attachShadow({mode: "open"});
|
|
this.shadowRoot.innerHTML = `
|
|
<style>
|
|
:host
|
|
{
|
|
display: block;
|
|
padding: .5em .25em .5em .75em;
|
|
margin: .25em;
|
|
margin-top: 1em;
|
|
border-top: 1px solid var(--secondary-foreground);
|
|
}
|
|
:host([type="box"])
|
|
{
|
|
border: 1px solid var(--secondary-foreground);
|
|
}
|
|
:host([collapsed]:not([type="box"]))
|
|
{
|
|
padding: .35em;
|
|
}
|
|
:host([type="box"][collapsed]), :host([type="box"][disabled])
|
|
{
|
|
padding: .32em;
|
|
}
|
|
group-label
|
|
{
|
|
display: inline-block;
|
|
background-color: var(--primary-background);
|
|
position: absolute;
|
|
top: -.85em;
|
|
left: .5ch;
|
|
padding-left: .25ch;
|
|
padding-right: .25ch;
|
|
}
|
|
:host([collapsed]) group-content, :host([disabled]) group-content
|
|
{
|
|
display: none;
|
|
}
|
|
m-inline
|
|
{
|
|
max-width: 1ch;
|
|
width: 1ch;
|
|
overflow: hidden;
|
|
font-family: 'Material Symbols Outlined';
|
|
font-weight: normal;
|
|
font-style: normal;
|
|
font-size: 1.25em;
|
|
line-height: 1;
|
|
letter-spacing: normal;
|
|
text-transform: none;
|
|
display: inline-block;
|
|
white-space: nowrap;
|
|
word-wrap: normal;
|
|
direction: ltr;
|
|
-webkit-font-feature-settings: 'liga';
|
|
font-feature-settings: 'liga';
|
|
-webkit-font-smoothing: antialiased;
|
|
padding-bottom: .1em;
|
|
vertical-align: middle;
|
|
}
|
|
a-button
|
|
{
|
|
margin: 0;
|
|
}
|
|
</style>
|
|
<group-label><a-button><span></span> <m-inline></m-inline></a-button></group-label>
|
|
<group-content><slot></slot></group-content>
|
|
`;
|
|
this._labelButton = $(this.shadowRoot).children("group-label").children("a-button");
|
|
this._labelText = $(this.shadowRoot).children("group-label").children("a-button").children("span");
|
|
this._labelIcon = $(this.shadowRoot).children("group-label").children("a-button").children("m-inline");
|
|
}
|
|
connectedCallback()
|
|
{
|
|
if (this.label && this.label.length > 0)
|
|
{
|
|
$(this.shadowRoot).children("group-label").children("a-button").children("span").text(this.label);
|
|
}
|
|
else
|
|
{
|
|
$(this.shadowRoot).children("group-label").children("a-button").children("span").text("Group Label");
|
|
}
|
|
if (this.collapsed)
|
|
{
|
|
$(this.shadowRoot).children("group-label").children("a-button").children("m-inline").text("expand_more");
|
|
}
|
|
else
|
|
{
|
|
$(this.shadowRoot).children("group-label").children("a-button").children("m-inline").text("expand_less");
|
|
}
|
|
this._labelButton.click(()=>
|
|
{
|
|
this.collapsed = !this.collapsed;
|
|
});
|
|
}
|
|
disconnectedCallback()
|
|
{
|
|
$(this.shadowRoot).children("group-label").children("a-button").off("click");
|
|
}
|
|
attributeChangedCallback(name, oldValue, newValue)
|
|
{
|
|
if (name === "label")
|
|
{
|
|
if (this.label && this.label.length > 0)
|
|
{
|
|
this._labelText.text(this.label);
|
|
}
|
|
else
|
|
{
|
|
this._labelText.text("Group Label");
|
|
}
|
|
}
|
|
else if (name === "collapsed")
|
|
{
|
|
if (this.collapsed)
|
|
{
|
|
this._labelIcon.text("expand_more");
|
|
}
|
|
else
|
|
{
|
|
this._labelIcon.text("expand_less");
|
|
}
|
|
}
|
|
else if (name === "disabled")
|
|
{
|
|
if (this.disabled)
|
|
{
|
|
this._labelIcon.text("expand_more");
|
|
this._labelButton.prop("disabled",true);
|
|
}
|
|
else
|
|
{
|
|
this._labelIcon.text("expand_less");
|
|
this._labelButton.prop("disabled",false);
|
|
}
|
|
}
|
|
}
|
|
get collapsed() {
|
|
return this.hasAttribute("collapsed");
|
|
}
|
|
set collapsed(value) {
|
|
if (value) {
|
|
this.setAttribute("collapsed", "");
|
|
} else {
|
|
this.removeAttribute("collapsed");
|
|
}
|
|
}
|
|
get disabled() {
|
|
return this.hasAttribute("disabled");
|
|
}
|
|
set disabled(value) {
|
|
if (value) {
|
|
this.setAttribute("disabled", "");
|
|
} else {
|
|
this.removeAttribute("disabled");
|
|
}
|
|
}
|
|
get label() {
|
|
return this.getAttribute("label");
|
|
}
|
|
set label(value) {
|
|
this.setAttribute("label", value.toString());
|
|
}
|
|
get type() {
|
|
return this.getAttribute("type");
|
|
}
|
|
set type(value) {
|
|
this.setAttribute("type", value.toString());
|
|
}
|
|
}
|
|
VSpacer = class extends HTMLElement
|
|
{
|
|
static observedAttributes = ["lines"];
|
|
constructor()
|
|
{
|
|
super();
|
|
this.attachShadow({mode: "open"});
|
|
this.shadowRoot.innerHTML = `
|
|
<style>
|
|
:host
|
|
{
|
|
display: block;
|
|
}
|
|
</style>
|
|
<div></div>
|
|
`;
|
|
this._div = $(this.shadowRoot).children("div");
|
|
}
|
|
connectedCallback(){
|
|
this._applyHeight();
|
|
}
|
|
attributeChangedCallback(name, oldValue, newValue)
|
|
{
|
|
if (name === "lines")
|
|
{
|
|
this._applyHeight();
|
|
}
|
|
}
|
|
_applyHeight()
|
|
{
|
|
const height = (!this.lines || isNaN(this.lines)) ? 1 : this.lines
|
|
this._div.css("height",`${height}lh`);
|
|
}
|
|
get lines() {
|
|
return Number(this.getAttribute("lines"));
|
|
}
|
|
set lines(value) {
|
|
if (isNaN(value))
|
|
{
|
|
this.setAttribute("lines", 1);
|
|
}
|
|
else
|
|
{
|
|
this.setAttribute("lines", Number(value));
|
|
}
|
|
}
|
|
}
|
|
MultiLineEllipsis = class extends HTMLElement
|
|
{
|
|
static observedAttributes = ["lines"];
|
|
constructor()
|
|
{
|
|
super();
|
|
this.attachShadow({mode: "open"});
|
|
this.shadowRoot.innerHTML = `
|
|
<style>
|
|
:host
|
|
{
|
|
display: block;
|
|
}
|
|
div
|
|
{
|
|
display: -webkit-box;
|
|
-webkit-box-orient: vertical;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
</style>
|
|
<div><slot></slot></div>
|
|
`;
|
|
this._div = $(this.shadowRoot).children("div");
|
|
this._slot = $(this.shadowRoot).find("slot");
|
|
}
|
|
connectedCallback(){
|
|
this._applyLineClamp();
|
|
this.title = this.innerText;
|
|
this._slot.on("slotchange", ()=>{this.title = this.innerText;});
|
|
}
|
|
attributeChangedCallback(name, oldValue, newValue)
|
|
{
|
|
if (name === "lines")
|
|
{
|
|
this._applyLineClamp();
|
|
}
|
|
}
|
|
_applyLineClamp()
|
|
{
|
|
const lines = (!this.lines || isNaN(this.lines)) ? "1" : this.lines.toString();
|
|
this._div.css({
|
|
"line-clamp": lines,
|
|
"-webkit-line-clamp": lines
|
|
});
|
|
}
|
|
get lines() {
|
|
return Number(this.getAttribute("lines"));
|
|
}
|
|
set lines(value) {
|
|
if (isNaN(value))
|
|
{
|
|
this.setAttribute("lines", 1);
|
|
}
|
|
else
|
|
{
|
|
this.setAttribute("lines", Number(value));
|
|
}
|
|
}
|
|
}
|
|
MidlineEllipsis = class extends HTMLElement
|
|
{
|
|
static observedAttributes = ["chars"];
|
|
constructor()
|
|
{
|
|
super();
|
|
this.attachShadow({mode: "open"});
|
|
this.shadowRoot.innerHTML = `
|
|
<style>
|
|
:host
|
|
{
|
|
display: inline;
|
|
cursor: pointer;
|
|
}
|
|
</style>
|
|
<slot></slot>
|
|
`;
|
|
}
|
|
connectedCallback(){
|
|
this.title = this.innerText;
|
|
this._chars = Number(this.getAttribute("chars"));
|
|
this._chars > 5 ? 1==1 : this.chars = 5;
|
|
this._originalNodes = this.cloneNode(true);
|
|
this._applyEllipsis();
|
|
this.addEventListener("click",()=>{
|
|
moly.alert.show("Konten Lengkap",this._originalNodes.innerHTML);
|
|
})
|
|
}
|
|
disconnectedCallback()
|
|
{
|
|
this.removeEventListener("click");
|
|
}
|
|
_applyEllipsis()
|
|
{
|
|
let sourceNodes = this._originalNodes.cloneNode(true).childNodes;
|
|
let skip = ["a-button","button", "img"];
|
|
let fhalftl = Math.ceil((this.chars-3)/2);
|
|
let lhalftl = Math.floor((this.chars-3)/2);
|
|
let fhalfl = 0;
|
|
let lhalfl = 0;
|
|
let fsearch = true;
|
|
let fpart = moly.newElement("span");
|
|
let lpart = moly.newElement("span");
|
|
let title = "";
|
|
$.each(sourceNodes,(i,v)=>{
|
|
if (skip.includes(v.nodeName.toLowerCase())) return;
|
|
title += v.textContent;
|
|
if(fsearch && v.textContent.length > 0 )
|
|
{
|
|
if (fhalfl + v.textContent.length < fhalftl)
|
|
{
|
|
fpart.append(v.cloneNode(true));
|
|
}
|
|
else
|
|
{
|
|
let remaining = fhalftl - fhalfl ;
|
|
let snode = v.cloneNode(true);
|
|
snode.textContent = snode.textContent.substring(0,remaining);
|
|
if(snode.textContent.length>0) fpart.append(snode);
|
|
fpart.append("...");
|
|
fsearch = false;
|
|
}
|
|
fhalfl += v.textContent.length;
|
|
}
|
|
});
|
|
this.title = title.replace(/\s+/g, ' ').trim();
|
|
for (let i = sourceNodes.length - 1; i >= 0; i--) {
|
|
let v = sourceNodes[i];
|
|
if (skip.includes(v.nodeName.toLowerCase())) continue;
|
|
if(v.textContent.length > 0 )
|
|
{
|
|
if (lhalfl + v.textContent.length < lhalftl)
|
|
{
|
|
lpart.prepend(v.cloneNode(true));
|
|
}
|
|
else
|
|
{
|
|
let remaining = lhalftl - lhalfl;
|
|
let snode = v.cloneNode(true);
|
|
snode.textContent = snode.textContent.substring(snode.textContent.length-remaining);
|
|
if(snode.textContent.length>0) lpart.prepend(snode);
|
|
break;
|
|
}
|
|
lhalfl += v.textContent.length;
|
|
}
|
|
}
|
|
fpart.innerHTML = fpart.innerHTML.trim();
|
|
lpart.innerHTML = lpart.innerHTML.trim()
|
|
$(this).empty().append(...fpart.childNodes,...lpart.childNodes);
|
|
}
|
|
attributeChangedCallback(name, oldValue, newValue)
|
|
{
|
|
if (name === "chars")
|
|
{
|
|
if (this._originalNodes) this._applyEllipsis();
|
|
}
|
|
}
|
|
get chars() {
|
|
let retval;
|
|
this._chars = Number(this.getAttribute("chars"));
|
|
this._chars > 5 ? retval = this._chars : retval = 5;
|
|
return retval;
|
|
}
|
|
set chars(value) {
|
|
if (isNaN(value))
|
|
{
|
|
this._chars = 5
|
|
this.setAttribute("chars", 5);
|
|
}
|
|
else
|
|
{
|
|
this._chars = Number(value);
|
|
this.setAttribute("chars", this._chars > 5 ? this.chars : 5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(async ()=>{
|
|
let time = 0
|
|
while (typeof window.jQuery === "undefined" && time < 10000) {
|
|
await new Promise(resolve => setTimeout(resolve, 50));
|
|
time +=50;
|
|
}
|
|
if (window.jQuery)
|
|
{
|
|
window.moly = new molybdenum();
|
|
customElements.define("a-button",moly.AButton);
|
|
customElements.define("file-input",moly.FileInput);
|
|
customElements.define("group-el",moly.Group);
|
|
customElements.define("v-spacer",moly.VSpacer);
|
|
customElements.define("multi-ellipsis",moly.MultiLineEllipsis);
|
|
customElements.define("midline-ellipsis",moly.MidlineEllipsis);
|
|
}
|
|
})(); |