ibms-dome/Frontend/js/yourteam/plugins/yt-notice/yt-notice.js

289 lines
8.1 KiB
JavaScript

/**
* YourTeam Notice 訊息彈出小視窗 (on base bootstrap v4 toast)
*
* 使用方式:
* <div id="noticeBlock" style="position: fixed; top: 70px; right: 0px; padding: 20px; transition: 0.2s; z-index: 50000; height:100%; ">
</div>
*
* <script>
* $("#noticeBlock").YTNotice("add", { option... });
* </script>
* */
class YTNotice {
constructor(option = {}) {
this.id = option.id ?? null;
this.title = option.title ?? "";
this.content = option.content ?? "";
this.type = option.type ?? null;
this.hasCloseBtn = option.hasCloseBtn ?? true;
this.keepTime = 0;
this.timeText = option.timeText ?? "剛剛";
this.iconClass = option.iconClass ?? "";
this.container = "";
this.eIcon = "";
this.eTitle = "";
this.eTimeAgo = "";
this.eCloseBtn = "";
this.eContent = "";
this.init();
}
init = function () {
this.setNoticeId();
this.setIconClass();
this.setContainer();
if (this.title) {
this.setTitle(this.title);
}
if (this.content) {
this.setContent(this.content);
}
if (this.timeText) {
this.setTimeAgo(this.timeText);
}
$(this.container)[0]._ytNotice = this;
}
setNoticeId = function () {
if (this.id == null) {
this.id = YT.Math.Random(10000000, 99999999);
}
}
setContainer = function () {
this.container = $(`<div class="toast fade" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
<div class="toast-header">
</div>
<div class="toast-body">
</div>
</div>`);
this.setIcon(this.iconClass);
this.eTitle = $(`<strong class="mr-auto notice-title"></strong>`);
this.eTimeAgo = $(`<small class="text-muted notice-ago ml-4"></small>`);
this.eCloseBtn = $(`<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close"><span aria-hidden="true">&times;</span></button>`);
this.eContent = $(`<div class="notice-content"></div>`);
if (this.type != null) {
this.container.find(".toast-header").append(this.eIcon);
this.eIcon.addClass("text-" + this.type);
}
this.container.find(".toast-header").append(this.eTitle);
this.container.find(".toast-header").append(this.eTimeAgo);
if (this.hasCloseBtn) {
this.container.find(".toast-header").append(this.eCloseBtn);
}
this.container.find(".toast-body").append(this.eContent);
}
setIconClass = function () {
if (this.type == "success") {
this.iconClass = `fas fa-check`;
} else if (this.type == "warning") {
this.iconClass = `fas fa-exclamation-triangle`;
} else if (this.type == "danger") {
this.iconClass = `fas fa-times`;
}
}
setIcon = function (iconClass) {
this.eIcon = $(`<i class="mr-2"></i>`);
this.eIcon.addClass(iconClass);
}
setTitle = function (title = "") {
this.eTitle.html(title);
}
setTimeAgo = function (timeAgo = "") {
this.eTimeAgo.text(timeAgo);
}
setContent = function (content = "") {
this.eContent.html(content);
}
}
class YTNoticeBlock {
constructor(option = {}) {
this.element = option.element;
this.offsetBottom = 200;
this.noticeArr = [];
this.eScroll = $(`<div class="yt-notice-block-scrollbody"></div>`);
this.noticeContainer = "";
this.scrollY = option.scrollY ?? true;
this.init();
}
init = function () {
this.drawInitScroll();
this.drawElement();
if (this.scrollY) {
this.noticeContainer = this.eScroll;
} else {
this.noticeContainer = this.element;
}
this.updEleObj();
}
drawInitScroll = function () {
if (this.scrollY) {
$(this.eScroll).css("height", "100%");
$(this.eScroll).css("overflow-y", "auto");
$(this.element).append(this.eScroll);
}
}
drawElement = function () {
$(this.element).addClass("yt-notice-block");
}
showOneNotice = function (obj = null,append = "prepend") {
if (obj) {
if (append == "prepend") {
$(this.noticeContainer).prepend(obj.container);
} else if (append == "append") {
$(this.noticeContainer).append(obj.container);
}
$(obj.container).toast("show");
}
}
hideOneNotice = function (obj = null) {
if (obj) {
let toast = "";
if (obj.is("div.toast")) {
toast = obj;
} else {
toast = obj.container;
}
$(toast).toast('dispose');
setTimeout(() => {
$(toast).remove();
let tarNoticeId = $(toast)[0]._ytNotice.id
let tarNoticeIdx = this.noticeArr.findIndex(x => x.obj.id == tarNoticeId);
if (tarNoticeIdx != -1) {
this.noticeArr[tarNoticeIdx].canShow = false;
}
this.showNotices();
}, 100)
}
this.updEleObj();
}
checkCanShow = function (notice = null) {
let lastNoticeOffset = $(this.noticeContainer).find(".toast").last().offset();
if ($(this.noticeContainer).find(".toast").last().length == 0) {
return true;
}
if ($(notice.obj.container).is(":visible")) {
return false;
}
if (!notice.canShow) {
return false;
}
if (lastNoticeOffset.top + this.offsetBottom > $(window).height()) {
return false;
} else {
return true;
}
}
showNotices = function () {
$.each(this.noticeArr, (idx, notice) => {
if (this.checkCanShow(notice)) {
this.showOneNotice(notice.obj,"append");
}
})
}
pushNotice = function (option = {}) {
if (this.noticeArr.findIndex(x => x.obj.id == option.id) == -1) {
let notice = new YTNotice(option);
this.noticeArr.push({ obj: notice, time: (new Date()).getTime(), canShow: true });
this.setEvent(notice);
}
this.updEleObj();
}
updEleObj = function () {
$(this.element)[0]._noticeBlock = this;
}
setEvent = function (notice) {
let _this = this;
$(notice.container).on("hidden.bs.toast", function () {
setTimeout(() => {
$(notice.container).remove();
let tarNoticeId = $(notice.container)[0]._ytNotice.id
let tarNoticeIdx = _this.noticeArr.findIndex(x => x.obj.id == tarNoticeId);
if (tarNoticeIdx != -1) {
_this.noticeArr[tarNoticeIdx].canShow = false;
}
_this.showNotices();
}, 100)
})
}
}
$.fn.YTNotice = function (method = "init", ...args) {
let _this = this;
if (method == "init") {
initNoticeBlock();
}
let noticeBlock = _this[0]._noticeBlock;
if (!noticeBlock) {
initNoticeBlock();
noticeBlock = _this[0]._noticeBlock;
}
if (method == "add") {
noticeBlock.pushNotice(args[0] ?? {});
noticeBlock.showNotices();
} else if (method == "add_many") {
args[0].forEach((arg, idx) => {
noticeBlock.pushNotice(arg);
})
noticeBlock.showNotices();
} else if (method == "hide") {
if (args.length == 0) {
noticeBlock = $(_this).parents(".yt-notice-block")[0]._noticeBlock;
noticeBlock.hideOneNotice(this);
}
}
function initNoticeBlock() {
let option = {};
option.element = _this;
let noticeBlock = new YTNoticeBlock(option);
}
}