252 lines
7.6 KiB
TypeScript
252 lines
7.6 KiB
TypeScript
$(document).on("mousedown",function (e) {
|
|
if($(e.target).parents("#contextMenu").length == 0 && $(e.target).parents(".modal").length == 0){
|
|
$(".modal:visible").last().find(".close").trigger("click");
|
|
}
|
|
});
|
|
|
|
type BodyCreator = (() => JQuery | JQuery[] | string) | string | JQuery | JQuery[];
|
|
const ModalFunctions = {
|
|
divify: function (val: JQuery) {
|
|
if(val.length > 1) return $.spawn("div").append(val);
|
|
return val;
|
|
},
|
|
|
|
jqueriefy: function(val: BodyCreator) : JQuery {
|
|
if($.isFunction(val)) val = val();
|
|
if($.isArray(val)) {
|
|
let result = $.spawn("div");
|
|
for(let element of val)
|
|
this.jqueriefy(element).appendTo(result);
|
|
return result;
|
|
}
|
|
switch (typeof val){
|
|
case "string": return $("<div>" + val + "</div>");
|
|
case "object": return val as JQuery;
|
|
case "undefined":
|
|
console.warn("Got undefined type!");
|
|
return $.spawn("div");
|
|
default:
|
|
console.error("Invalid type " + typeof val);
|
|
return $();
|
|
}
|
|
},
|
|
|
|
warpProperties(data: ModalProperties | any) : ModalProperties {
|
|
if(data instanceof ModalProperties) return data;
|
|
else {
|
|
let props = new ModalProperties();
|
|
for(let key in data)
|
|
props[key] = data[key];
|
|
return props;
|
|
}
|
|
}
|
|
};
|
|
|
|
class ModalProperties {
|
|
header: BodyCreator = () => "HEADER";
|
|
body: BodyCreator = () => "BODY";
|
|
footer: BodyCreator = () => "FOOTER";
|
|
|
|
closeListener: (() => void) | (() => void)[] = () => {};
|
|
registerCloseListener(listener: () => void) : this {
|
|
if(this.closeListener) {
|
|
if($.isArray(this.closeListener))
|
|
this.closeListener.push(listener);
|
|
else
|
|
this.closeListener = [this.closeListener, listener];
|
|
} else this.closeListener = listener;
|
|
return this;
|
|
}
|
|
width: number | string = "60%";
|
|
height: number | string = "auto";
|
|
|
|
closeable: boolean = true;
|
|
|
|
triggerClose(){
|
|
if($.isArray(this.closeListener))
|
|
for(let listener of this.closeListener)
|
|
listener();
|
|
else
|
|
this.closeListener();
|
|
}
|
|
}
|
|
|
|
class Modal extends EventTarget {
|
|
private _htmlTag: JQuery;
|
|
properties: ModalProperties;
|
|
shown: boolean;
|
|
|
|
close_listener: (() => any)[] = [];
|
|
|
|
constructor(props: ModalProperties) {
|
|
super();
|
|
|
|
this.properties = props;
|
|
this.shown = false;
|
|
}
|
|
|
|
get htmlTag() : JQuery {
|
|
if(!this._htmlTag) this._create();
|
|
return this._htmlTag;
|
|
}
|
|
|
|
private _create() {
|
|
let modal = $.spawn("div");
|
|
modal.addClass("modal");
|
|
|
|
let content = $.spawn("div");
|
|
content.addClass("modal-content");
|
|
if(this.properties.width)
|
|
content.css("width", this.properties.width);
|
|
if(this.properties.height)
|
|
content.css("height", this.properties.height);
|
|
|
|
let header = ModalFunctions.divify(ModalFunctions.jqueriefy(this.properties.header)).addClass("modal-header");
|
|
if(this.properties.closeable) header.append("<span class=\"close\">×</span>");
|
|
|
|
let body = ModalFunctions.divify(ModalFunctions.jqueriefy(this.properties.body)).addClass("modal-body");
|
|
let footer = ModalFunctions.divify(ModalFunctions.jqueriefy(this.properties.footer)).addClass("modal-footer");
|
|
|
|
content.append(header);
|
|
content.append(body);
|
|
content.append(footer);
|
|
|
|
modal.append(content);
|
|
|
|
modal.find(".close").click(function () {
|
|
if(this.properties.closeable)
|
|
this.close();
|
|
}.bind(this));
|
|
|
|
this._htmlTag = modal;
|
|
}
|
|
|
|
open() {
|
|
this.shown = true;
|
|
this.htmlTag.appendTo($("body"));
|
|
this.htmlTag.show();
|
|
}
|
|
|
|
close() {
|
|
if(!this.shown) return;
|
|
|
|
this.shown = false;
|
|
const _this = this;
|
|
this.htmlTag.animate({opacity: 0}, () => {
|
|
_this.htmlTag.detach();
|
|
});
|
|
this.properties.triggerClose();
|
|
for(const listener of this.close_listener)
|
|
listener();
|
|
}
|
|
}
|
|
|
|
function createModal(data: ModalProperties | any) : Modal {
|
|
return new Modal(ModalFunctions.warpProperties(data));
|
|
}
|
|
|
|
class InputModalProperties extends ModalProperties {
|
|
maxLength: number;
|
|
}
|
|
|
|
function createInputModal(headMessage: BodyCreator, question: BodyCreator, validator: (input: string) => boolean, callback: (flag: boolean | string) => void, props: InputModalProperties | any = {}) : Modal {
|
|
props = ModalFunctions.warpProperties(props);
|
|
|
|
let head = $.spawn("div");
|
|
head.css("border-bottom", "grey solid");
|
|
head.css("border-width", "1px");
|
|
ModalFunctions.jqueriefy(headMessage).appendTo(head);
|
|
|
|
|
|
let body = $.spawn("div");
|
|
ModalFunctions.divify(ModalFunctions.jqueriefy(question)).appendTo(body);
|
|
let input = $.spawn("input");
|
|
input.css("width", "100%");
|
|
input.appendTo(body);
|
|
console.log(input);
|
|
|
|
let footer = $.spawn("div");
|
|
footer.addClass("modal-button-group");
|
|
footer.css("margin-top", "5px");
|
|
|
|
let buttonCancel = $.spawn("button");
|
|
buttonCancel.text("Cancel");
|
|
|
|
let buttonOk = $.spawn("button");
|
|
buttonOk.text("Ok");
|
|
|
|
footer.append(buttonCancel);
|
|
footer.append(buttonOk);
|
|
|
|
input.on("keydown", function (event) {
|
|
if(event.keyCode == JQuery.Key.Enter) {
|
|
buttonOk.trigger("click");
|
|
}
|
|
});
|
|
|
|
let updateValidation = function () {
|
|
let text = input.val().toString();
|
|
let flag = (!props.maxLength || text.length <= props.maxLength) && validator(text);
|
|
if(flag) {
|
|
input.removeClass("invalid_input");
|
|
buttonOk.removeAttr("disabled");
|
|
} else {
|
|
if(!input.hasClass("invalid_input"))
|
|
input.addClass("invalid_input");
|
|
buttonOk.attr("disabled", "true");
|
|
}
|
|
};
|
|
input.on("keyup", updateValidation);
|
|
|
|
let callbackCalled = false;
|
|
let wrappedCallback = function (flag: boolean | string) {
|
|
if(callbackCalled) return;
|
|
callbackCalled = true;
|
|
callback(flag);
|
|
};
|
|
|
|
let modal;
|
|
buttonOk.on("click", () => {
|
|
wrappedCallback(input.val().toString());
|
|
modal.close();
|
|
});
|
|
buttonCancel.on("click", () => {
|
|
wrappedCallback(false);
|
|
modal.close();
|
|
});
|
|
|
|
props.header = head;
|
|
props.body = body;
|
|
props.footer = footer;
|
|
props.closeListener = () => wrappedCallback(false);
|
|
modal = createModal(props);
|
|
return modal;
|
|
}
|
|
|
|
function createErrorModal(header: BodyCreator, message: BodyCreator, props: ModalProperties | any = { footer: "" }) {
|
|
props = ModalFunctions.warpProperties(props);
|
|
|
|
let head = $.spawn("div");
|
|
head.addClass("modal-head-error");
|
|
ModalFunctions.divify(ModalFunctions.jqueriefy(header)).appendTo(head);
|
|
props.header = head;
|
|
|
|
props.body = $.spawn("div").append(ModalFunctions.divify(ModalFunctions.jqueriefy(message)));
|
|
props.footer = ModalFunctions.divify(ModalFunctions.jqueriefy(""));
|
|
|
|
return createModal(props);
|
|
}
|
|
|
|
function createInfoModal(header: BodyCreator, message: BodyCreator, props: ModalProperties | any = { footer: "" }) {
|
|
props = ModalFunctions.warpProperties(props);
|
|
|
|
let head = $.spawn("div");
|
|
head.addClass("modal-head-info");
|
|
ModalFunctions.divify(ModalFunctions.jqueriefy(header)).appendTo(head);
|
|
props.header = head;
|
|
|
|
props.body = ModalFunctions.divify(ModalFunctions.jqueriefy(message));
|
|
props.footer = ModalFunctions.divify(ModalFunctions.jqueriefy(""));
|
|
|
|
return createModal(props);
|
|
} |