From 5574747cdea456775901aa40268e645922029eb4 Mon Sep 17 00:00:00 2001 From: gk Date: Fri, 10 Jun 2022 17:31:25 +0800 Subject: [PATCH] =?UTF-8?q?5.0.210=E7=89=88=E6=9C=AC=E5=8F=91=E5=B8=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-xss.yml | 14 + .../main/resources/static/framework/common.js | 311 +++++ .../main/resources/static/framework/theme.js | 1105 +++++++++++++++++ .../resources/static/image/layout-left.svg | 2 + .../resources/static/image/layout-top.svg | 2 + .../src/main/resources/static/libs/aes.min.js | 18 + .../main/resources/static/libs/svg-inject.js | 697 +++++++++++ .../resources/static/libs/svg-inject.min.js | 10 + pom.xml | 2 +- 9 files changed, 2160 insertions(+), 1 deletion(-) create mode 100644 modules/kdayun-app/src/main/resources/application-xss.yml create mode 100644 modules/kdayun-app/src/main/resources/static/framework/common.js create mode 100644 modules/kdayun-app/src/main/resources/static/framework/theme.js create mode 100644 modules/kdayun-app/src/main/resources/static/image/layout-left.svg create mode 100644 modules/kdayun-app/src/main/resources/static/image/layout-top.svg create mode 100644 modules/kdayun-app/src/main/resources/static/libs/aes.min.js create mode 100644 modules/kdayun-app/src/main/resources/static/libs/svg-inject.js create mode 100644 modules/kdayun-app/src/main/resources/static/libs/svg-inject.min.js diff --git a/modules/kdayun-app/src/main/resources/application-xss.yml b/modules/kdayun-app/src/main/resources/application-xss.yml new file mode 100644 index 0000000..2318b32 --- /dev/null +++ b/modules/kdayun-app/src/main/resources/application-xss.yml @@ -0,0 +1,14 @@ +#(安全测评需要开启) +# enabled true 启用/false 不启用; +# includes:需要处理的url标志字符串 逗号隔开 ,默认为空则是全部要处理; +# excludes:不需要处理的url标志字符串 逗号隔开 默认为空; +# urlPatterns: 需要xss过滤器处理的url 逗号隔开 默认是 :/* +# excludeUrl: 某个url无需xss的过滤 +# +security: + xss: +# enabled: true + includes: + excludes: img + urlPatterns: /* + excludeUrl: /manager/coremodeldesign/modify,/manager/coredatasource/post,/manager/coredatasource/processModel \ No newline at end of file diff --git a/modules/kdayun-app/src/main/resources/static/framework/common.js b/modules/kdayun-app/src/main/resources/static/framework/common.js new file mode 100644 index 0000000..a75d3c1 --- /dev/null +++ b/modules/kdayun-app/src/main/resources/static/framework/common.js @@ -0,0 +1,311 @@ + +layui.define(function (exports) { + var $ = layui.$, + layer = layui.layer, + element = layui.element, + setter = layui.setter, + message = new Messenger('index', 'kdayunmanager'); + var common = { + /** + * 抛出一个异常错误信息 + * @param {String} msg + */ + throwError: function (msg) { + throw new Error(msg); + return; + }, + /** + * 弹出一个错误提示 + * @param {String} msg + */ + msgError: function (msg) { + layer.msg(msg, { + icon: 5 + }); + return; + }, + /** + * 给url增加参数 + * @param {*} url url + * @param {*} obj 参数对象 + * @param {*} exclude 排除的属性名的正则表达式 + * @returns 返回url + */ + setUrlParamObj: function (url, obj, exclude) { + for (var pro in obj) { + if (exclude) { + if (!exclude.test(pro)) { + url = common.setUrlParam(url, pro, obj[pro]); + } + } else { + url = common.setUrlParam(url, pro, obj[pro]); + } + } + return url; + }, + /** + * 给url增加参数 + * @param {*} url URL + * @param {*} name 参数名 + * @param {*} value 参数值 + * @returns 返回url + */ + setUrlParam: function (url, name, value) { + var localUrl = url; + if (value != null) { + //增加或修改url参数 + //判断URL是否带有?号 + if (localUrl.indexOf("?") < 0) { + //判断url是否有# + var a = localUrl.indexOf("#"); + if (a < 0) { + return localUrl + "?" + name + "=" + value; + } else { + return localUrl.substring(0, a) + "?" + name + "=" + value + localUrl.substring(a); + } + + } else { + var regex = new RegExp("([\\?&]" + name + "=)[^&#]*"); + if (regex.test(localUrl)) { + return localUrl.replace(regex, "$1" + value); + } + else { + var a = localUrl.indexOf("#"); + if (a < 0) { + return localUrl + "&" + name + "=" + value; + } else { + return localUrl.substring(0, a) + "&" + name + "=" + value + localUrl.substring(a); + } + } + } + } else { + //删除url的参数 + var regex = new RegExp("([\\?&])" + name + "=[^&#]*(&?)"); + if (regex.test(localUrl)) { + return localUrl.replace(regex, function (m, p1, p2) { + if (p1 == "?") { + return p2 == "&" ? "?" : ""; + } else { + return p2; + } + }); + } else { + return localUrl; + } + + } + + }, + tabsPage: {}, + + setPrevAndNext: function () { + var $li = $('.layui-tab-title').children('li') + , sumwidth = 0 + , totalwidth = $('.layui-tab-title').width(); + for (var i = 0; i < $li.length; i++) { + sumwidth = sumwidth + $li.eq(i).outerWidth(); + } + if (sumwidth > totalwidth) { + $('.layadmin-pagetabs').css({ "padding-left": "40px", "padding-right": "80px" }); + $('.layui-icon-prev').show(); + $('.layui-icon-next').show(); + } else { + $('.layadmin-pagetabs').css({ "padding-left": "0px", "padding-right": "40px" }); + $('.layui-icon-prev').hide(); + $('.layui-icon-next').hide(); + } + }, + /** + * 打开tab标签页 + * @param {*} url 页签的URL + * @param {*} text 页签的标题 + * @param {*} resid 资源id + * @param {*} param 传递的参数 + * @param {*} callback 完成回调 + */ + openTabsPage: function (url, text, resid, param, callback) { + //遍历页签选项卡 + var matchTo, tabs = $('#LAY_app_tabsheader>li'), + path = url.replace(/(^http(s*):)|(\?[\s\S]*$)/g, ''), + tempresid = resid ? resid : url; + if (url.indexOf('isnewtab=1') > -1) { + window.open(url, "_blank"); + callback && callback(); + return; + } + + url = common.setUrlParamObj(url, param, /tokenId/) + + tabs.each(function (index) { + var li = $(this), + layid = li.attr('lay-id'); + if (layid === tempresid) { + matchTo = true; + common.tabsPage.index = index; + } + }); + var APP_BODY = '#LAY_app_body', + FILTER_TAB_TBAS = 'layadmin-layout-tabs', + text = text || '新标签页'; + //如果未在选项卡中匹配到,则追加选项卡 + if (!matchTo) { + $(APP_BODY).append([ + '
', + '', + '
' + ].join('')); + common.tabsPage.index = tabs.length; + element.tabAdd(FILTER_TAB_TBAS, { + title: '' + text + '', + id: resid ? resid : url, + attr: path + }); + common.setPrevAndNext(); + $('.layadmin-tabsbody-shade').show(); + } + var $iframe + if (path.indexOf('/coremodelshow') != -1 && resid) { + $iframe = $(APP_BODY).find('iframe[menuid="' + resid + '"]'); + } + else { + $iframe = $(APP_BODY).find('iframe[src="' + url + '"]'); + } + $iframe && !$iframe.attr('loaded') && ($('.layadmin-tabsbody-shade').show()) && $iframe.load(function () { + // $('.layadmin-tabsbody-shade').fadeOut('600'); + $iframe.attr('loaded', 'true') + }); + callback && callback(); + + //执行 {setter.MOD_NAME}.tabsPage 下的事件 + layui.event.call(this, setter.MOD_NAME, 'tabsPage({*})', { + url: tempresid, + text: text + }); + }, + /** + * xss 转义 + * @param {*} html + */ + escape: function (html) { + return String(html || '').replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&') + .replace(//g, '>') + .replace(/'/g, ''').replace(/"/g, '"'); + }, + /** + * 打开Layer页 + * @param {*} pageCoinfg + * @param {*} params + * @param {*} successCallback 页面完成打开回调 + */ + openLayerPage: function (pageCoinfg, params, successCallback) { + var pageId = params.__pageId; + //页面创建加载完成 + pageId && common.onForm(pageId, 'onPageLoad', function (msg) { + let iframes = top.window.document.getElementsByTagName("iframe"); + for (var i = 0; i < iframes.length; i++) { + var iframe = iframes[i]; + if (iframe.contentWindow.location.href.indexOf('=' + pageId) != -1) { + common.sendTo(pageId, 'onSuccess') + break; + } + } + }) + var p = $.extend(pageCoinfg, { + type: 2, + area: pageCoinfg.area || ['420px', '240px'], + success: () => { + successCallback && successCallback(); + } + , yes: () => { + pageId && common.sendTo(pageId, 'onYes') + } + , no: () => { + pageId && common.sendTo(pageId, 'onCancel') + } + , end: () => { + pageId && common.sendTo(pageId, 'onEnd') + } + , onCanClose: () => { + return pageId && common.sendTo(pageId, 'onCanClose') + } + , onClosed: () => { + pageId && common.sendTo(pageId, 'onClosed') + }, full: () => { + pageId && common.sendTo(pageId, 'onFull') + }, min: () => { + pageId && common.sendTo(pageId, 'onMin') + }, resizing: () => { + pageId && common.sendTo(pageId, 'onResizing') + }, moveEnd: () => { + pageId && common.sendTo(pageId, 'onMoveEnd') + }, restore: () => { + pageId && common.sendTo(pageId, 'onRestore') + } + }); + layer.open(p); + }, + + + /** + * 监听消息(不管来源哪里) + * @param {*} msg 消息标识常量 + * @param {*} callback 回调 callback(msg) + */ + on: function (msg, callback) { + return message.on(msg, callback) + }, + /** + * 监听消息(只管来源fromHandle 的消息) + * @param fromHandle 消息来源目标的句柄全局唯一 + * @param {*} msg 消息标识常量 + * @param {*} callback 回调 callback(msg) + */ + onForm: function (fromHandle, msg, callback) { + if (!fromHandle) { + throw new Error("fromHandle参数不允许为空") + } + return message.onFrom(fromHandle, msg, callback) + }, + + /** + * 给具体的目标发送消息 + * @param {*} toHandle 目标句柄全局唯一 + * @param {*} msg 消息标识常量 + * @param {*} params 附带的消息信息 + */ + sendTo: function (toHandle, msg, params) { + if (!toHandle) { + throw new Error("toHandle参数不允许为空") + } + return message.sendTo(toHandle, msg, params); + }, + + /** + * 本iframe内给所有的目标发送消息 + * @param {*} msg 消息标识常量 + * @param {*} params 附带的消息信息 + */ + send: function (msg, params) { + var msgobj = { + msg: msg, + params: params + } + return message.send(msgobj); + }, + /** + * 跨iframe给所有的目标发送消息 + * @param {*} msg 消息标识常量 + * @param {*} params 附带的消息信息 + */ + broadcast: function (msg, params) { + var msgobj = { + msg: msg, + params: params + } + return message.broadcast(msgobj); + } + } + + //对外暴露的接口 + exports('common', common); +}); \ No newline at end of file diff --git a/modules/kdayun-app/src/main/resources/static/framework/theme.js b/modules/kdayun-app/src/main/resources/static/framework/theme.js new file mode 100644 index 0000000..356b733 --- /dev/null +++ b/modules/kdayun-app/src/main/resources/static/framework/theme.js @@ -0,0 +1,1105 @@ + +layui.define(['laytpl', 'element', 'layer', 'zlPinYin', 'common'], function (exports) { + var $ = layui.jquery, + element = layui.element, + laytpl = layui.laytpl, + zlPinYin = layui.zlPinYin, + common = layui.common; + var THEME = { + defaulStyles: [ + { name: '亮色风格', value: "light", color: '#f0f2f5' }, + { name: '暗色风格', value: "dark", color: 'rgba(0,21,41,.85)' } + ], + defaulColors: [ + { name: "拂晓蓝", value: "#1890ff" }, + { name: "薄暮", value: "#F5222D" }, + { name: "火山", value: "#FA541C" }, + { name: "日暮", value: "#FAAD14" }, + { name: "明青", value: "#13C2C2" }, + { name: "极光绿", value: "#52C41A" }, + { name: "极客蓝", value: "#2F54EB" }, + { name: "酱紫", value: "#60339a" }, + ], + defaulLayouts: [ + { value: "left", name: '菜单在左边', icon: "url(" + layui.cache['contentPath'] + "/static/image/layout-left.svg)" }, + { value: "top", name: '菜单在顶部', icon: "url(" + layui.cache['contentPath'] + "/static/image/layout-top.svg)" } + ], + /** + * 默认主题 + */ + getDefaulThemeObj() { + var ColorBase = '#1890ff'; + return { + 'theme_title': "黑色主题", + 'theme_title-py': 'HeiSeZhuTi', + style: 'light', + color: ColorBase, + layout: 'left', + + // logo + logoFontColorInput: 'rgba(255,255,255,.8)', // logo字体颜色 + logoBgInput: '#20222A', // logo背景颜色 + + // 导航栏 + navFont: "Microsoft YaHei", // 导航栏字体 + navBgInput: "#FFFFFF", // 导航栏背景 + navFontColorInput: "#333333", // 导航栏 字体颜色 + navIconColorInput: "#333333", // 导航栏 图标颜色 + // 左侧菜单 + searchBoxBgInput: '#374850', // 搜索框背景 + searchBoxFontColorInput: '#FFFFFF', // 搜索框字体色 + menuBgInput: "#20222A", // 左侧菜单背景 + childMenuBgInput: 'rgba(0, 0, 0, .3)', + menuFont: "Microsoft YaHei", // 左侧菜单字体 + menuFontColorInput: "#FFFFFF", // 左侧菜单字体颜色 + menuSelectedBgInput: THEME.getLightColor(ColorBase, 0.5), // 左侧菜单 选中项背景颜色 + menuSelectedFontColorInput: '#FFFFFF', // 左侧菜单 选中项字体颜色 + menuItemBorderColorInput: '无', // 左侧菜单 选中项字体颜色 + // 窗口 + layerTitleBgInput: "#F8F8F8", // 窗口标题背景 + layerCloseBtnColor: "1", // 窗口关闭按钮颜色 + layerTitleFontColorInput: "#333333", // 窗口标题字体颜色 + + // 标准按钮 + btnBgInput: ColorBase, // 标准按钮背景 + btnFont: "Microsoft YaHei", // 标准按钮字体 + btnFontColorInput: "#FFFFFF", // 标准按钮字体颜色 + btnIconColorInput: "#FFFFFF", // 标准按钮图标颜色 + // 警告按钮 + dangerBtnBgInput: '#FF5722', // 警告按钮背景 + dangerBtnFont: 'Microsoft YaHei', // 警告按钮字体 + dangerBtnFontColorInput: "#FFFFFF", // 警告按钮字体颜色 + dangerBtnIconColorInput: "#FFFFFF", // 警告按钮图标颜色 + // 开关按钮 + switchBgInput: THEME.getLightColor(ColorBase, 0.5), // 开关按钮背景 + switchFont: "Microsoft YaHei", // 开关按钮字体 + switchFontColorInput: "#FFFFFF", // 开关按钮字体颜色 + // 复选框-默认 + checkBoxBgInput: THEME.getLightColor(ColorBase, 0.5), // 复选框-默认 背景 + checkBoxFontColorInput: "#FFFFFF", // 复选框-默认 字体颜色 + checkboxFont: "Microsoft YaHei", // 复选框-默认 字体 + // 复选框-原始 + originCheckBoxBgInput: THEME.getLightColor(ColorBase, 0.5), // 复选框-原始 背景 + originCheckBoxFontColorInput: "#FFFFFF", // 复选框-原始 字体颜色 + // 单选框 + radioBgInput: THEME.getLightColor(ColorBase, 0.5), // 单选框背景 + id: '25CE6A8B1C', + } + }, + /** + * 得到默认的主题数据 + * @returns 返回主题数据对象 + */ + getDefaultTheme() { + return THEME.mergerExtendData(THEME.getDefaulThemeObj()) + }, + /** + * 融合额外的主题属性。一般是用于界面设计器 + * @param {*} themeObj 主题数据对象 + * @param {*} colorBase 基本颜色 + */ + mergerExtendData(themeObj) { + var ColorBase = themeObj.color || THEME.getDefaulThemeObj().color; + if (!themeObj.kd_color_0) { + return $.extend(themeObj, { + /** + * 主色字体、边框的颜色调 + */ + kd_color: THEME.getLightColor(ColorBase, 1), + kd_color_0: THEME.getDarkColor(ColorBase, 0.1), + kd_color_1: ColorBase, + kd_color_2: THEME.getLightColor(ColorBase, 0.1), + kd_color_3: THEME.getLightColor(ColorBase, 0.2), + kd_color_4: THEME.getLightColor(ColorBase, 0.3), + kd_color_5: THEME.getLightColor(ColorBase, 0.4), + kd_color_6: THEME.getLightColor(ColorBase, 0.5), + kd_color_7: THEME.getLightColor(ColorBase, 0.6), + kd_color_8: THEME.getLightColor(ColorBase, 0.7), + kd_color_9: THEME.getLightColor(ColorBase, 0.8), + kd_color_10: THEME.getLightColor(ColorBase, 0.9), + kd_color_11: THEME.getLightColor(ColorBase, 1), + + /** + * 连接的颜色 + */ + kd_link_color: "#1e90ff", + /** + * 设计焦点的颜色 + */ + kd_design_focuse_color: "blue", + + /** + * 背景色 + */ + kd_bg_color: ColorBase, + /** + * 不可用的背景颜色 + */ + kd_bg_color_disabled: "#C9C9C9", + /** + * 激活(获取焦点)的背景颜色 + */ + kd_bg_color_active: THEME.getLightColor(ColorBase, 0.1), + + /** + * 主色鼠标停留字体,边框的颜色 + */ + kd_color_hover: THEME.getLightColor(ColorBase, 0.8), + /** + * 主色激活(获取焦点)的颜色 + */ + kd_color_active: THEME.getLightColor(ColorBase, 0.2), + /** + * 主色不可用颜色 + */ + kd_color_disabled: "#C2C2C2", + /** + * 主色轮廓线颜色 + */ + kd_color_outline: ColorBase, + + /** + * 主色组件边框颜色 + */ + kd_border_color: "#C9C9C9", + /** + * 主色组滚动框颜色 + */ + kd_scroll_color: "#C9C9C9", + + /** + * 正常的字体颜色 + * 一般是白底黑字/黑底白字 + */ + kd_normal_font_color: "#555", + + /** + * 主色鼠标停留组件边框颜色 + */ + kd_border_color_hover: THEME.getLightColor(ColorBase, 0.1), + /** + * 主色激活(获取焦点)字体,边框的颜色 + */ + kd_border_color_active: THEME.getLightColor(ColorBase, 0.7), + /** + * 主色不可用边框颜色 + */ + kd_border_color_disabled: "#C9C9C9", + + /** + * 成功主色调 + */ + kd_success_color: "#52c41a", + kd_success_color_hover: "#73d13d", + kd_success_color_active: "#389e0d", + kd_success_color_outline: "rgba(82,196,26,0.2)", + + /** + * 输入框的提示颜色 + */ + kd_placeholder_color: "#b2b2b2", + + /** + * 错误的颜色 + */ + kd_error_color: "#ff4d4f", + kd_error_color_hover: "#ff7875", + kd_error_color_active: "#d9363e", + kd_error_color_outline: "rgba(255,77,79,0.2)", + kd_error_color_bg: "#FF5722", + kd_error_color_border: "#ffccc7", + + /** + * 警告颜色 + */ + kd_warning_color: "#faad14", + kd_warning_color_hover: "#ffc53d", + kd_warning_color_active: "#d48806", + kd_warning_color_outline: "rgba(250,173,20,0.2)", + kd_warning_color_bg: "#FFB800", + + /** + * 信息提示颜色 + */ + kd_info_color: ColorBase, + kd_info_color_bg: "#e6f7ff", + kd_info_color_border: "#91d5ff", + + + // 标准按钮 + btnBgInput: ColorBase, // 标准按钮背景 + btnFont: "Microsoft YaHei", // 标准按钮字体 + btnFontColorInput: "#FFFFFF", // 标准按钮字体颜色 + btnIconColorInput: "#FFFFFF", // 标准按钮图标颜色 + // 警告按钮 + dangerBtnBgInput: '#FF5722', // 警告按钮背景 + dangerBtnFont: 'Microsoft YaHei', // 警告按钮字体 + dangerBtnFontColorInput: "#FFFFFF", // 警告按钮字体颜色 + dangerBtnIconColorInput: "#FFFFFF", // 警告按钮图标颜色 + // 开关按钮 + switchBgInput: THEME.getLightColor(ColorBase, 0.2), // 开关按钮背景 + switchFont: "Microsoft YaHei", // 开关按钮字体 + switchFontColorInput: "#FFFFFF", // 开关按钮字体颜色 + // 复选框-默认 + checkBoxBgInput: THEME.getLightColor(ColorBase, 0.2), // 复选框-默认 背景 + checkBoxFontColorInput: "#FFFFFF", // 复选框-默认 字体颜色 + checkboxFont: "Microsoft YaHei", // 复选框-默认 字体 + // 复选框-原始 + originCheckBoxBgInput: THEME.getLightColor(ColorBase, 0.2), // 复选框-原始 背景 + originCheckBoxFontColorInput: "#FFFFFF", // 复选框-原始 字体颜色 + // 单选框 + radioBgInput: THEME.getLightColor(ColorBase, 0.2), // 单选框背景 + }) + } else { + return themeObj; + } + }, + /** + * 设置主题, 设置保存当前页面的主题,并创建css 的样式节点 + * @param {*} theme 主题对象 + */ + setTheme: function (themeObj) { + sessionStorage.setItem('zltheme', JSON.stringify(themeObj)) + common.broadcast('setTheme', JSON.stringify(themeObj)); + }, + /** + * 给当前的docoment增加主题的styleSheet + */ + renderCssStyle(themeObj) { + if (themeObj && themeObj.childMenuBgInput && themeObj.childMenuBgInput.indexOf('.') != -1 && themeObj.childMenuBgInput.indexOf(',') != -1) { + var arr = themeObj.childMenuBgInput.split(','); + arr.pop(); + themeObj.childMenuTipsBgInput = arr.join() + ')'; + } + themeObj.layerMinBtnColor = themeObj.layerCloseBtnColor == 1 ? "#2E2D3C" : "#fff"; + themeObj.layerMaxBtnColor = themeObj.layerCloseBtnColor == 1 ? "-32" : "-102"; + themeObj.layerMaxMinBtnColor = themeObj.layerCloseBtnColor == 1 ? "-65" : "-120"; + themeObj.menuItemBorderColorInput = themeObj.menuItemBorderColorInput == '无' ? 'none' : ('1px solid ' + themeObj.menuItemBorderColorInput); + + THEME.mergerExtendData(themeObj) + + + var + styleid = 'kd-theme-style', + style = document.createElement('style'), + styleElem = document.getElementById(styleid), + styleText = laytpl( + ` + :root{ + --kd-color: {{d.kd_color_3}} + } + .layui-layer .layui-layer-title, + .layui-layer-iframe .layui-layer-title { + background-color:{{d.layerTitleBgInput}} !important; + color:{{d.layerTitleFontColorInput}}; + } + .layui-layer-setwin .layui-layer-min cite { + background-color:{{d.layerMinBtnColor}}; + } + .layui-layer-setwin .layui-layer-max { + background-position:{{d.layerMaxBtnColor}}px -40px; + } + .layui-layer-setwin .layui-layer-max.layui-layer-maxmin { + background-position:{{d.layerMaxMinBtnColor}}px -40px; + } + .layui-layer-setwin .layui-layer-close1 { + background-position:{{d.layerCloseBtnColor}}px -40px; + } + .layui-btn { + background-color:{{d.btnBgInput}}; + color:{{d.btnFontColorInput}}; + font-family:{{d.btnFont}} !important; + } + .layui-btn i { + color:{{d.btnIconColorInput}} !important; + } + .layui-btn.layui-btn-danger { + background-color:{{d.dangerBtnBgInput}}; + color:{{d.dangerBtnFontColorInput}}; + font-family:{{d.dangerBtnFont}} !important; + } + .layui-btn.layui-btn-danger i { + color:{{d.dangerBtnIconColorInput}} !important; + } + .layui-form-switch.layui-form-onswitch { + border-color:{{d.switchBgInput}}; + background-color:{{d.switchBgInput}}; + } + .layui-form-switch.layui-form-onswitch em { + color:{{d.switchFontColorInput}} !important; + } + .layui-unselect.layui-form-switch em { + font-family:{{d.switchFont}} !important; + } + .layui-form-switch.layui-form-onswitch i { + background-color:{{d.switchFontColorInput}}; + } + .layui-form-checkbox.layui-form-checked { + border-color:{{d.checkBoxBgInput}}; + } + .layui-unselect.layui-form-checkbox { + font-family:{{d.checkboxFont}} !important; + } + .layui-form-checkbox.layui-form-checked span { + background-color:{{d.checkBoxBgInput}}; + color:{{d.checkBoxFontColorInput}}; + } + .layui-form-checkbox.layui-form-checked i { + color:{{d.checkBoxBgInput}}; + } + .layui-form-checkbox[lay-skin="primary"]:hover i { + border-color: {{d.checkBoxBgInput}}; + } + .layui-form-checkbox.layui-form-checked[lay-skin="primary"] i { + border-color:{{d.originCheckBoxBgInput}}; + background-color:{{d.originCheckBoxBgInput}}; + color:{{d.originCheckBoxFontColorInput}}; + } + .layui-form-checkbox.layui-form-checked[lay-skin="primary"] span { + color: #666; + background: none !important; + } + .layui-form-radio.layui-form-radioed i { + color:{{d.radioBgInput}}; + } + .layui-form-radioed>i, .layui-form-radio>i:hover{ + color: {{d.radioBgInput}}; + } + .layui-form-select dl dd.layui-this { + background-color:{{d.menuBgInput}}; + } + .layui-side-menu { + font-family:{{d.menuFont}} !important; + background-color:{{d.menuBgInput}}; + } + .navbar-side-search { + background-color:{{d.menuBgInput}}!important; + } + .navbar-side-search input { + background-color:{{d.searchBoxBgInput}}!important; + border-color:{{d.searchBoxBgInput}}!important; + color:{{d.searchBoxFontColorInput}}!important; + } + .navbar-side-search input:hover { + border-color:{{d.searchBoxBgInput}}!important; + } + .navbar-side-search input:focus { + border-color:{{d.searchBoxBgInput}}!important; + } + .navbar-side-search input::-webkit-input-placeholder { + color:{{d.searchBoxFontColorInput}}!important; + } + .navbar-side-search input::-moz-placeholder { + color:{{d.searchBoxFontColorInput}}!important; + } + .navbar-side-search input::-ms-input-placeholder { + color:{{d.searchBoxFontColorInput}}!important; + } + .layui-side-menu .layui-nav.layui-nav-tree a, + .layui-side-menu .layui-nav.layui-nav-tree i.layui-icon { + color:{{d.menuFontColorInput}} !important; + } + .layui-side-menu .layui-nav.layui-nav-tree { + border-top:{{d.menuItemBorderColorInput}}; + } + .layui-side-menu .layui-nav.layui-nav-tree li.layui-nav-item { + border-bottom:{{d.menuItemBorderColorInput}}; + } + .layui-side-menu .layui-nav.layui-nav-tree span.layui-nav-more { + border-top-color:{{d.menuFontColorInput}} !important; + border-bottom-color:{{d.menuBgInput}} !important; + } + .layui-side-menu .layui-nav.layui-nav-tree .layui-nav-itemed>a span.layui-nav-more { + border-top-color:{{d.menuBgInput}} !important; + border-bottom-color:{{d.menuFontColorInput}} !important; + } + .layui-side-menu .layui-nav.layui-nav-tree .layui-nav-itemed>.layui-nav-child { + background-color:{{d.childMenuBgInput}} !important; + } + .layui-side-menu .layui-nav.layui-nav-tree .layui-this a, + .layui-side-menu .layui-nav.layui-nav-tree .layui-nav-bar { + background-color:{{d.menuSelectedBgInput}} !important; + color:{{d.menuSelectedFontColorInput||'var(--kd-color)'}} !important; + } + .layui-nav-bar{ + background-color: {{d.menuSelectedBgInput||'var(--kd-color)'}}!important; + } + .kdayun-app-layout .layui-header { + font-family:{{d.navFont}} !important; + background-color:{{d.navBgInput}}; + } + .kdayun-app-layout .layui-header a:hover, + .kdayun-app-layout .layui-header a cite { + color:{{d.navFontColorInput}}; + } + .kdayun-app-layout .layui-header a i.layui-icon, + .kdayun-app-layout .layui-header a i.zlui-icon, + .kdayun-app-layout .layui-header a i.fa { + color:{{d.navIconColorInput}}; + } + .kdayun-app-layout .layui-header a span.layui-nav-more { + border-top-color:{{d.navIconColorInput}} !important; + } + .kdayun-app-layout .layui-header .layui-nav .layui-nav-mored { + border-top-color:{{d.navBgInput}} !important; + border-bottom-color:{{d.navIconColorInput}} !important; + } + .kdayun-app-layout .layui-logo { + background-color:{{d.logoBgInput}}; + color:{{d.logoFontColorInput}}; + } + .layadmin-pagetabs .layui-tab-title li:after, + .layadmin-pagetabs .layui-tab-title li.layui-this:after { + background-color:{{d.menuSelectedBgInput||'var(--kd-color)'}}; + } + .layui-tab-brief>.layui-tab-title .layui-this:after, + .layui-tab-brief>.layui-tab-more li.layui-this:after { + border-color:{{d.menuBgInput}}; + } + .layui-table tbody tr:hover,.layui-table-hover,.layui-table-click{ + background-color:`+ (themeObj.kd_color_10 || '#f2f2f2') + `; + } + .layui-layer-tips.menuTips .layui-layer-content { + background-color:`+ (themeObj.childMenuTipsBgInput || THEME.colorReverse(themeObj.menuFontColorInput || "#FFFFFF")) + `; + color:`+ (themeObj.menuFontColorInput || "#FFFFFF") + `; + } + .layui-layer-tips.menuTips .layui-layer-content i { + border-bottom-color:`+ (themeObj.childMenuTipsBgInput || "#FFFFFF") + `; + } + .layui-input:hover, + .layui-textarea:hover, + .layui-select:hover { + border-color:`+ themeObj.kd_color_1 + `!important; + outline: 0; + } + .layui-input:focus, + .layui-textarea:focus, + .layui-select:focus { + border-color:`+ (themeObj.kd_color_1) + `!important; + border-right-width: 1px!important; + outline: 0; + box-shadow : 0 0 0 2px `+ THEME.rgba(themeObj.kd_color_1, .2) + `; + } + .layui-card { + box-shadow: 0 3px 1px -2px rgb(0 0 0 / 20%), 0 2px 2px 0 rgb(0 0 0 / 14%), 0 1px 5px 0 rgb(0 0 0 / 12%); + } + `).render(themeObj); + + if ('styleSheet' in style) { + style.setAttribute('type', 'text/css'); + style.styleSheet.cssText = styleText; + } else { + style.innerHTML = styleText; + } + style.id = styleid; + + styleElem && $('body')[0].removeChild(styleElem); + $('body')[0].appendChild(style); + $('body').attr('layadmin-themealias', themeObj["theme_title-py"]); + + var iframes = $(".layadmin-iframe").contents(); + function setIframeTheme(iframes) { + for (var i = 0; i < iframes.length; i++) { + var $iframe = $(iframes[i]), + $iframeBody = $(iframes[i]).find("body"), + iframeBodyElemt = $iframeBody[0]; + var c_style = $iframe[0].createElement('style'), + c_styleElem = $iframe[0].getElementById(styleid); + if ('styleSheet' in c_style) { + c_style.setAttribute('type', 'text/css'); + c_style.styleSheet.cssText = styleText; + } else { + c_style.innerHTML = styleText; + } + c_style.id = styleid; + c_styleElem && iframeBodyElemt.removeChild(c_styleElem); + iframeBodyElemt && iframeBodyElemt.appendChild(c_style); + $iframeBody.attr('layadmin-themealias', themeObj["theme_title-py"]); + } + } + $('body').addClass('loaded'); + $('#loader-wrapper .load_title').remove(); + setIframeTheme(iframes); + }, + /** + * 获取当前的主题 + * @param {*} isServer true 从服务端获取主题数据, false 先从本地获取主题数据,不存在再从服务端获取,服务器不存在就去。 + */ + getTheme: function (isServer) { + let ret = null; + if (isServer) { + ret = THEME.getCurrentThemeFromServer() + } else { + ret = sessionStorage.getItem('zltheme') + if (!ret) { + ret = THEME.getCurrentThemeFromServer() + } else if (typeof (ret) == 'string') { + ret = JSON.parse(ret) + } + } + ret = ret || THEME.getDefaultTheme(); + return ret; + }, + /** + * 得到机构的主题数组 + * @param {*} orgid 机构id + * @param {*} callback(themeJson,err) 完成回调 + */ + getThemes: function (orgid, callback) { + let param = { + orgid: orgid, + optid: 'DF64BCDD33324F3DA4A63973E2462391' + } + $.ajax({ + url: layui.cache['contentPath'] + '/manager/coresysopt/queryxtypec', + type: "GET", + async: false, + data: param, + dataType: "json", + contentType: "application/json", + success: function (data) { + if (data.state == 'OK') { + callback && callback(JSON.parse(data.obj), null); + } else { + callback && callback(null, data.msg); + } + } + }); + }, + /** + * 从后台服务端获取当前单位的主题 (同步方法) + * @param {*} callback(themeJson,err) 完成回调 + * @returns 返回主题对象 + */ + getCurrentThemeFromServer(callback) { + let ret = null; + $.ajax({ + url: layui.cache['contentPath'] + '/manager/coresysopt/querytheme', + type: "POST", + async: false, + data: {}, + dataType: "json", + contentType: "application/json", + success: function (data) { + if (data && data.state == 'OK' && data.obj) { + ret = JSON.parse(data.obj); + callback && callback(ret) + } else { + callback && callback(eval(null, data.msg)) + } + } + }); + return ret; + }, + + /** + * 16进制色值获取反色设置方法 + * @param strHex 为16进制色值的字符串(例:'#000000') + * @return 返回反色的色值(例:'#ffffff') + */ + colorReverse(strHex) { + strHex = '0x' + strHex.replace(/#/g, ''); + let str = '000000' + (0xFFFFFF - strHex).toString(16); + return '#' + str.substring(str.length - 6, str.length); + }, + /** + * hex颜色转rgb颜色 + * @param strHex 十六进制的颜色值格式(#ffc53d) + * @returns 返回RGB数组 + */ + hexToRgb(strHex) { + let r = /^\#?[0-9A-Fa-z]{6}$/; + if (!r.test(strHex)) { + Common.error("输入错误的hex"); + return null; + } + strHex = strHex.replace("#", ""); + let hxs = strHex.match(/../g); + for (let i = 0; i < 3; i++) { + hxs[i] = parseInt(hxs[i], 16) + }; + return hxs; + }, + + /** + * hex颜色转rgba颜色 ,这个是带有透明参数 + * @param strHex + * @param alpha 透明度 (0~1)之间浮点数 + * @returns 返回 rgba(xx,xx,xx,0.2)格式的字符串 + */ + rgba(strHex, alpha) { + let rgb = THEME.hexToRgb(strHex); + rgb.push(alpha); + let ret = 'rgba(' + rgb.join(',') + ')' + return ret; + }, + + /** + * GRB颜色转Hex颜色 + * @param a R 值 + * @param b G 值 + * @param c B 值 + * @returns 返回十六进制字符串 + */ + rgbToHex(a, b, c) { + let r = /^\d{1,3}$/; + if (!r.test(a) || !r.test(b) || !r.test(c)) { + Common.error("输入错误的rgb颜色值"); + return null; + } + let hexs = [a.toString(16), b.toString(16), c.toString(16)]; + for (let i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = "0" + hexs[i]; + return "#" + hexs.join(""); + }, + + /** + * 得到hex颜色值为color的加深颜色值,level为加深的程度,限0-1之间 + * @param color 颜色的16禁止字符串 + * @param level 0-1 之间的浮点数 + * @returns 返回十六进制字符串 + */ + getDarkColor(color, level) { + let r = /^\#?[0-9A-Fa-z]{6}$/; + if (!r.test(color)) { + Common.error("输入错误的hex颜色值:" + color); + return null; + } + let rgbc = THEME.hexToRgb(color); + //floor 向下取整 + for (let i = 0; i < 3; i++) rgbc[i] = Math.floor(rgbc[i] * (1 - level)); + return THEME.rgbToHex(rgbc[0], rgbc[1], rgbc[2]); + }, + + /** + * 得到hex颜色值为color的减淡颜色值,level为加深的程度,限0-1之间 + * @param color 颜色的16禁止字符串 + * @param level 0-1 之间的浮点数 + * @returns 返回十六进制字符串 + */ + getLightColor(color, level) { + let r = /^\#?[0-9A-Fa-z]{6}$/; + if (!r.test(color)) { + Common.error("输入错误的hex颜色值:" + color); return; + } + let rgbc = THEME.hexToRgb(color); + for (let i = 0; i < 3; i++) rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i]); + let ret = THEME.rgbToHex(rgbc[0], rgbc[1], rgbc[2]); + return ret; + }, + + /** + * 开始渲染主题 + */ + render(isServer, isDefalut) { + var themeObj = THEME.getTheme(isServer); + if (isDefalut) { + var leftThemeRender = new LeftTheme(themeObj); + leftThemeRender.render(); + return; + } + + if (themeObj.layout == 'top') { + var topThemeRender = new TopTheme(themeObj); + topThemeRender.render(); + } else { + var leftThemeRender = new LeftTheme(themeObj); + leftThemeRender.render(); + } + } + } + + /** + * 主题渲染类 + * @param {*} config + */ + var ThemeRenderBase = function (config) { + this.config = { + $elem: $('#kdayun-app'), //主容器 + $headerElem: $('.layui-header'), + $tabElem: $('.layadmin-pagetabs'), + $menuElem: $('.layui-side-menu'), + $logoElem: $('.layui-logo'), + theme: THEME.getTheme(), //主题 + } + } + ThemeRenderBase.prototype.constructor = ThemeRenderBase; + ThemeRenderBase.prototype.render = function () { + var that = this; + that.config.$elem.empty(); + that.renderHeader(); + that.renderMenus(); + that.renderBody(); + that.renderFoot(); + }; + ThemeRenderBase.prototype.renderHeader = function () { + var that = this; + that.config.$headerElem = $($('#tpl-header').html()); + that.config.$elem.append(that.config.$headerElem); + that.config.$headerElem.append($('#tpl-header-left-tools').html()); + that.config.$headerElem.append($('#tpl-header-right-tools').html()) + }; + ThemeRenderBase.prototype.renderMenus = function () { + var that = this; + that.config.$menuElem = $($('#tpl-left-side').html()) + that.config.$elem.append(that.config.$menuElem); + that.config.$menuElem.append($('#tpl-search').html()) + that.config.$menuElem.find('.navbar-side-search').before($('#tpl-logo').html()) + that.config.$menuElem.find('.navbar-side-search').after($('#tpl-menu').html()) + var menuRender = new MenuRender() + menuRender.set({ + spreadOne: true, + elem: '#admin-navbar-menu', + cached: false, + url: layui.cache['contentPath'] + '/core/security/querymenuauth', + type: 'post' + }); + menuRender.render(); + + }; + ThemeRenderBase.prototype.renderFoot = function () { + var that = this; + }; + ThemeRenderBase.prototype.renderBody = function () { + var that = this; + that.config.$menuElem = $($('#tpl-body').html()) + that.config.$elem.append(that.config.$menuElem); + }; + + + /** + * 菜单靠左的布局 + */ + var LeftTheme = function (config) { + ThemeRenderBase.call(this, config); + }; + (function () { + // 创建一个没有实例方法的类 + var Super = function () { }; + Super.prototype = ThemeRenderBase.prototype; + //将实例作为子类的原型 + LeftTheme.prototype = new Super(); + })(); + LeftTheme.prototype.constructor = LeftTheme; + + /** + * 菜单是在头部 + */ + var TopTheme = function (config) { + ThemeRenderBase.call(this, config); + }; + (function () { + var Super = function () { }; + Super.prototype = ThemeRenderBase.prototype; + TopTheme.prototype = new Super(); + })(); + TopTheme.prototype.constructor = TopTheme; + TopTheme.prototype.renderMenus = function () { + var that = this; + that.config.$headerElem.find('.layui-layout-left').remove(); + that.config.$headerElem.append($('#tpl-logo').html()); + that.config.$headerElem.append($('#tpl-menu').html()); + that.config.$menuElem = $('#admin-navbar-menu') + that.config.$menuElem.after($('#tpl-search').html()) + var menuRender = new MenuRender(); + menuRender.set({ + spreadOne: true, + elem: '#admin-navbar-menu', + cached: false, + url: layui.cache['contentPath'] + '/core/security/querymenuauth', + type: 'post' + }); + menuRender.render(); + }; + + /** + * 菜单的渲染器 + */ + var MenuRender = function () { + /** + * 默认配置 + */ + this.config = { + elem: undefined, //容器 + data: undefined, //数据源 + url: undefined, //数据源地址 + type: 'GET', //读取方式 + cached: false, //是否使用缓存 + spreadOne: false //设置是否只展开一个二级菜单 + } + + }; + /** + * 渲染菜单 + */ + MenuRender.prototype.render = function () { + var that = this; + var _config = that.config; + if (typeof (_config.elem) !== 'string' && typeof (_config.elem) !== 'object') { + common.throwError('MenuRender error: elem参数未定义或设置出错,具体设置格式请参考文档API.'); + } + var $container; + if (typeof (_config.elem) === 'string') { + $container = $('' + _config.elem + ''); + } + if (typeof (_config.elem) === 'object') { + $container = _config.elem; + } + if ($container.length === 0) { + common.throwError('MenuRender error:找不到elem参数配置的容器,请检查.'); + } + if (_config.data === undefined && _config.url === undefined) { + common.throwError('MenuRender error:请为Navbar配置数据源.') + } + if (_config.data !== undefined && typeof (_config.data) === 'object') { + var html = that.getHtml(_config.data); + $container.html(html); + element.init(); + that.config.elem = $container; + } else { + $.ajax({ + type: _config.type, + url: _config.url, + async: false, //_config.async, + dataType: 'json', + success: function (result, status, xhr) { + var html = that.getHtml(result.obj); + $container.html(html); + element.init(); + }, + error: function (xhr, status, error) { + common.msgError('MenuRender error:' + error); + }, + complete: function (xhr, status) { + that.config.elem = $container; + } + }); + } + + //只展开一个二级菜单 + if (_config.spreadOne) { + var $ul = $container.children('ul'); + $ul.find('li.layui-nav-item').each(function () { + // $(this).on('click', function () { + // $(this).siblings().removeClass('layui-nav-itemed'); + // }); + }); + } + + this.iniEvent(); + return that; + }; + MenuRender.prototype.iniEvent = function () { + $('#navbarSearchValue').on('keyup', function (e) { + navbarSeacherHandle($(this).val(), this) + }); + $('#navbarSearchIcon').on('click', function () { + navbarSeacherHandle($(this).siblings('input').val(), this) + }); + // 点击搜索项 + $('ul.navbarSearchResult').on('click', 'li', function () { + var value = $(this).find('cite').html(); + $('ul.navbarSearchResult').removeClass('layui-show').addClass('layui-hide'); + $(this).parent().siblings('input').val(''); + if (!$('#admin-navbar-menu').find('a[lay-tips="' + value + '"]').parent().hasClass('layui-nav-itemed')) { + $('#admin-navbar-menu').find('a[lay-tips="' + value + '"]').click(); + } + }) + + function navbarSeacherHandle(value, dom) { + var targetData = $(dom).parent('div.navbar-side-search').siblings('div#admin-navbar-menu').find('a'), + ulItem = $(dom).siblings('ul.navbarSearchResult'), + num = 0; + ulItem.html(' '); + if (value == '') { + ulItem.addClass('layui-hide').removeClass('layui-show'); + return; + } + for (var i = 0; i < targetData.length; i++) { + // if ($(targetData[i]).find('span.layui-nav-more').length == 0) { + var matchingTarget = $(targetData[i]).find('cite').html(), + imgHtml = $(targetData[i]).find('img').length > 0 ? $(targetData[i]).find('img')[0].outerHTML : ''; + + if (matchingTarget.indexOf(value) != -1 || zlPinYin.A(matchingTarget).toLowerCase().indexOf(value.toLowerCase()) != -1) { + ulItem.append('
  • ' + imgHtml + '' + matchingTarget + '
  • '); + num++; + } + // } + } + ulItem.removeClass('layui-hide').addClass('layui-show'); + if (num == 0) { + ulItem.append('
  • 未查询到对应数据!
  • ') + } + } + }; + /** + * 获取html字符串 + * @param {Object} data 菜单的项数组 + */ + MenuRender.prototype.getHtml = function (data) { + var ulHtml = ''; + + return ulHtml; + }; + MenuRender.prototype.getTokenIdUrl = function (url, resid) { + if (url.indexOf("?") != -1) { + return '&tokenId=' + ($('#tokenId').val() ? $('#tokenId').val() : '') + '&resId=' + resid; + } else { + return '?tokenId=' + ($('#tokenId').val() ? $('#tokenId').val() : '') + '&resId=' + resid; + } + }; + /** + * 获取一个菜单的的html + * @param {*} item + */ + MenuRender.prototype.getItemHtml = function (item) { + var ulHtml = ''; + var url = item.href; + if (url != null) { + url = url.replace(/#{contentpath}/i, layui.cache['contentPath']); + } + var iconUrl = layui.cache['contentPath'] + item.icon; + var svgOnLoad = '' + if (iconUrl && (iconUrl.indexOf('.svg') != -1 || iconUrl.indexOf('.SVG') != -1)) { + svgOnLoad = 'onload = "SVGInject(this)" fill="currentColor"' + } + + var layhref = (url !== undefined && url !== '' && url !== null) ? 'lay-href="' + url + '"' : ''; + ulHtml += ''; + if (item.icon != undefined && item.icon != '') { + ulHtml += ''; + } + if (item.children != undefined && item.children != undefined && item.children.length > 0) { + ulHtml += '' + item.title + '' + ulHtml += ''; + ulHtml += '
    ' + for (var j = 0; j < item.children.length; j++) { + ulHtml += '
    '; + if (item.children !== undefined && item.children.length > 0) + ulHtml += this.getItemHtml(item.children[j]); + ulHtml += '
    '; + } + ulHtml += '
    '; + } else { + ulHtml += '' + item.title + '' + ulHtml += ''; + } + return ulHtml; + } + /** + * 配置MenuRender + * @param {Object} options + */ + MenuRender.prototype.set = function (options) { + var that = this; + that.config.data = undefined; + $.extend(true, that.config, options); + return that; + }; + /** + * 绑定事件 + * @param {String} events + * @param {Function} callback + */ + MenuRender.prototype.on = function (events, callback) { + var that = this; + var _con = that.config.elem; + if (typeof (events) !== 'string') { + common.throwError('MenuRender error:事件名配置出错,请参考API文档.'); + } + var lIndex = events.indexOf('('); + var eventName = events.substr(0, lIndex); + var filter = events.substring(lIndex + 1, events.indexOf(')')); + if (eventName === 'click') { + if (_con.attr('lay-filter') !== undefined) { + _con.children('ul').find('li').each(function () { + var $this = $(this); + if ($this.find('dl').length > 0) { + var $dd = $this.find('dd').each(function () { + $(this).on('click', function () { + var $a = $(this).children('a'); + var href = $a.data('url'); + var icon = $a.children('i:first').data('icon'); + var title = $a.children('cite').text(); + if (href) { + var data = { + elem: $a, + field: { + href: href, + icon: icon, + title: title + } + } + callback(data); + } + }); + }); + } else { + $this.on('click', function () { + var $a = $this.children('a'); + var href = $a.data('url'); + var icon = $a.children('i:first').data('icon'); + var title = $a.children('cite').text(); + if (href) { + var data = { + elem: $a, + field: { + href: href, + icon: icon, + title: title + } + } + callback(data); + } + }); + } + }); + } + } + }; + /** + * 清除缓存 + */ + MenuRender.prototype.cleanCached = function () { + }; + + common.on('setTheme', function (event) { + var themeObj = JSON.parse(event.params); + if (themeObj) { + THEME.renderCssStyle(themeObj); + } + }) + + !function () { + common.on('setTheme', function (event) { + var themeObj = JSON.parse(event.params); + if (themeObj) { + THEME.renderCssStyle(themeObj); + } + element.render(); + }) + //当前设定主题设置 + if (!window['--hasload-kd-Theme']) { + let m = THEME.getTheme(false); + if (m) { + THEME.setTheme(m); + common.broadcast('TabPageFinished', {}); + } + } + $('body').addClass('loaded'); + $('#loader-wrapper .load_title').remove(); + }(); + + //对外接口 + exports('theme', THEME); + window['kdtheme'] = THEME; +}); \ No newline at end of file diff --git a/modules/kdayun-app/src/main/resources/static/image/layout-left.svg b/modules/kdayun-app/src/main/resources/static/image/layout-left.svg new file mode 100644 index 0000000..2485429 --- /dev/null +++ b/modules/kdayun-app/src/main/resources/static/image/layout-left.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/modules/kdayun-app/src/main/resources/static/image/layout-top.svg b/modules/kdayun-app/src/main/resources/static/image/layout-top.svg new file mode 100644 index 0000000..65f2584 --- /dev/null +++ b/modules/kdayun-app/src/main/resources/static/image/layout-top.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/modules/kdayun-app/src/main/resources/static/libs/aes.min.js b/modules/kdayun-app/src/main/resources/static/libs/aes.min.js new file mode 100644 index 0000000..45f88bc --- /dev/null +++ b/modules/kdayun-app/src/main/resources/static/libs/aes.min.js @@ -0,0 +1,18 @@ +!function(t,n){"object"==typeof exports?module.exports=exports=n():"function"==typeof define&&define.amd?define([],n):t.CryptoJS=n()}(this,function(){var t=t||function(t,n){var i=Object.create||function(){function t(){}return function(n){var i;return t.prototype=n,i=new t,t.prototype=null,i}}(),e={},r=e.lib={},o=r.Base=function(){return{extend:function(t){var n=i(this);return t&&n.mixIn(t),n.hasOwnProperty("init")&&this.init!==n.init||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var n in t)t.hasOwnProperty(n)&&(this[n]=t[n]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),s=r.WordArray=o.extend({init:function(t,i){t=this.words=t||[],i!=n?this.sigBytes=i:this.sigBytes=4*t.length},toString:function(t){return(t||c).stringify(this)},concat:function(t){var n=this.words,i=t.words,e=this.sigBytes,r=t.sigBytes;if(this.clamp(),e%4)for(var o=0;o>>2]>>>24-o%4*8&255;n[e+o>>>2]|=s<<24-(e+o)%4*8}else for(var o=0;o>>2]=i[o>>>2];return this.sigBytes+=r,this},clamp:function(){var n=this.words,i=this.sigBytes;n[i>>>2]&=4294967295<<32-i%4*8,n.length=t.ceil(i/4)},clone:function(){var t=o.clone.call(this);return t.words=this.words.slice(0),t},random:function(n){for(var i,e=[],r=function(n){var n=n,i=987654321,e=4294967295;return function(){i=36969*(65535&i)+(i>>16)&e,n=18e3*(65535&n)+(n>>16)&e;var r=(i<<16)+n&e;return r/=4294967296,r+=.5,r*(t.random()>.5?1:-1)}},o=0;o>>2]>>>24-r%4*8&255;e.push((o>>>4).toString(16)),e.push((15&o).toString(16))}return e.join("")},parse:function(t){for(var n=t.length,i=[],e=0;e>>3]|=parseInt(t.substr(e,2),16)<<24-e%8*4;return new s.init(i,n/2)}},u=a.Latin1={stringify:function(t){for(var n=t.words,i=t.sigBytes,e=[],r=0;r>>2]>>>24-r%4*8&255;e.push(String.fromCharCode(o))}return e.join("")},parse:function(t){for(var n=t.length,i=[],e=0;e>>2]|=(255&t.charCodeAt(e))<<24-e%4*8;return new s.init(i,n)}},f=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(t){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},h=r.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new s.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=f.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(n){var i=this._data,e=i.words,r=i.sigBytes,o=this.blockSize,a=4*o,c=r/a;c=n?t.ceil(c):t.max((0|c)-this._minBufferSize,0);var u=c*o,f=t.min(4*u,r);if(u){for(var h=0;h>>6-o%4*2;n[i>>>2]|=(f|c)<<24-i%4*8,i++}return a.create(n,i)}var t=r,n=t.lib,a=n.WordArray,i=t.enc;i.Base64={stringify:function(r){var e=r.words,t=r.sigBytes,n=this._map;r.clamp();for(var a=[],i=0;i>>2]>>>24-i%4*8&255,f=e[i+1>>>2]>>>24-(i+1)%4*8&255,c=e[i+2>>>2]>>>24-(i+2)%4*8&255,s=o<<16|f<<8|c,h=0;h<4&&i+.75*h>>6*(3-h)&63));var p=n.charAt(64);if(p)for(;a.length%4;)a.push(p);return a.join("")},parse:function(r){var t=r.length,n=this._map,a=this._reverseMap;if(!a){a=this._reverseMap=[];for(var i=0;i>>2];e.sigBytes-=t}},y=(i.BlockCipher=d.extend({cfg:d.cfg.extend({mode:l,padding:v}),reset:function(){d.reset.call(this);var e=this.cfg,t=e.iv,r=e.mode;if(this._xformMode==this._ENC_XFORM_MODE)var i=r.createEncryptor;else{var i=r.createDecryptor;this._minBufferSize=1}this._mode&&this._mode.__creator==i?this._mode.init(this,t&&t.words):(this._mode=i.call(r,this,t&&t.words),this._mode.__creator=i)},_doProcessBlock:function(e,t){this._mode.processBlock(e,t)},_doFinalize:function(){var e=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){e.pad(this._data,this.blockSize);var t=this._process(!0)}else{var t=this._process(!0);e.unpad(t)}return t},blockSize:4}),i.CipherParams=n.extend({init:function(e){this.mixIn(e)},toString:function(e){return(e||this.formatter).stringify(this)}})),m=r.format={},k=m.OpenSSL={stringify:function(e){var t=e.ciphertext,r=e.salt;if(r)var i=c.create([1398893684,1701076831]).concat(r).concat(t);else var i=t;return i.toString(a)},parse:function(e){var t=a.parse(e),r=t.words;if(1398893684==r[0]&&1701076831==r[1]){var i=c.create(r.slice(2,4));r.splice(0,4),t.sigBytes-=16}return y.create({ciphertext:t,salt:i})}},x=i.SerializableCipher=n.extend({cfg:n.extend({format:k}),encrypt:function(e,t,r,i){i=this.cfg.extend(i);var n=e.createEncryptor(r,i),c=n.finalize(t),o=n.cfg;return y.create({ciphertext:c,key:r,iv:o.iv,algorithm:e,mode:o.mode,padding:o.padding,blockSize:e.blockSize,formatter:i.format})},decrypt:function(e,t,r,i){i=this.cfg.extend(i),t=this._parse(t,i.format);var n=e.createDecryptor(r,i).finalize(t.ciphertext);return n},_parse:function(e,t){return"string"==typeof e?t.parse(e,this):e}}),g=r.kdf={},S=g.OpenSSL={execute:function(e,t,r,i){i||(i=c.random(8));var n=p.create({keySize:t+r}).compute(e,i),o=c.create(n.words.slice(t),4*r);return n.sigBytes=4*t,y.create({key:n,iv:o,salt:i})}},B=i.PasswordBasedCipher=x.extend({cfg:x.cfg.extend({kdf:S}),encrypt:function(e,t,r,i){i=this.cfg.extend(i);var n=i.kdf.execute(r,e.keySize,e.ivSize);i.iv=n.iv;var c=x.encrypt.call(this,e,t,n.key,i);return c.mixIn(n),c},decrypt:function(e,t,r,i){i=this.cfg.extend(i),t=this._parse(t,i.format);var n=i.kdf.execute(r,e.keySize,e.ivSize,t.salt);i.iv=n.iv;var c=x.decrypt.call(this,e,t,n.key,i);return c}})}()}); +//# sourceMappingURL=cipher-core.min.js.map +!function(e,i){"object"==typeof exports?module.exports=exports=i(require("./core.min")):"function"==typeof define&&define.amd?define(["./core.min"],i):i(e.CryptoJS)}(this,function(e){!function(){var i=e,t=i.lib,n=t.Base,s=i.enc,r=s.Utf8,o=i.algo;o.HMAC=n.extend({init:function(e,i){e=this._hasher=new e.init,"string"==typeof i&&(i=r.parse(i));var t=e.blockSize,n=4*t;i.sigBytes>n&&(i=e.finalize(i)),i.clamp();for(var s=this._oKey=i.clone(),o=this._iKey=i.clone(),a=s.words,f=o.words,c=0;c>>8^255&o^99,t[i]=o,c[o]=i;var p=e[i],l=e[p],_=e[l],k=257*e[o]^16843008*o;s[i]=k<<24|k>>>8,f[i]=k<<16|k>>>16,a[i]=k<<8|k>>>24,d[i]=k;var k=16843009*_^65537*l^257*p^16843008*i;u[o]=k<<24|k>>>8,v[o]=k<<16|k>>>16,h[o]=k<<8|k>>>24,y[o]=k,i?(i=p^e[e[e[_^p]]],n^=e[e[n]]):i=n=1}}();var p=[0,1,2,4,8,16,32,64,128,27,54],l=o.AES=n.extend({_doReset:function(){if(!this._nRounds||this._keyPriorReset!==this._key){for(var e=this._keyPriorReset=this._key,r=e.words,i=e.sigBytes/4,n=this._nRounds=i+6,o=4*(n+1),c=this._keySchedule=[],s=0;s6&&s%i==4&&(f=t[f>>>24]<<24|t[f>>>16&255]<<16|t[f>>>8&255]<<8|t[255&f]):(f=f<<8|f>>>24,f=t[f>>>24]<<24|t[f>>>16&255]<<16|t[f>>>8&255]<<8|t[255&f],f^=p[s/i|0]<<24),c[s]=c[s-i]^f}for(var a=this._invKeySchedule=[],d=0;d>>24]]^v[t[f>>>16&255]]^h[t[f>>>8&255]]^y[t[255&f]]}}},encryptBlock:function(e,r){this._doCryptBlock(e,r,this._keySchedule,s,f,a,d,t)},decryptBlock:function(e,r){var i=e[r+1];e[r+1]=e[r+3],e[r+3]=i,this._doCryptBlock(e,r,this._invKeySchedule,u,v,h,y,c);var i=e[r+1];e[r+1]=e[r+3],e[r+3]=i},_doCryptBlock:function(e,r,i,n,o,t,c,s){for(var f=this._nRounds,a=e[r]^i[0],d=e[r+1]^i[1],u=e[r+2]^i[2],v=e[r+3]^i[3],h=4,y=1;y>>24]^o[d>>>16&255]^t[u>>>8&255]^c[255&v]^i[h++],l=n[d>>>24]^o[u>>>16&255]^t[v>>>8&255]^c[255&a]^i[h++],_=n[u>>>24]^o[v>>>16&255]^t[a>>>8&255]^c[255&d]^i[h++],k=n[v>>>24]^o[a>>>16&255]^t[d>>>8&255]^c[255&u]^i[h++];a=p,d=l,u=_,v=k}var p=(s[a>>>24]<<24|s[d>>>16&255]<<16|s[u>>>8&255]<<8|s[255&v])^i[h++],l=(s[d>>>24]<<24|s[u>>>16&255]<<16|s[v>>>8&255]<<8|s[255&a])^i[h++],_=(s[u>>>24]<<24|s[v>>>16&255]<<16|s[a>>>8&255]<<8|s[255&d])^i[h++],k=(s[v>>>24]<<24|s[a>>>16&255]<<16|s[d>>>8&255]<<8|s[255&u])^i[h++];e[r]=p,e[r+1]=l,e[r+2]=_,e[r+3]=k},keySize:8});r.AES=n._createHelper(l)}(),e.AES}); +//# sourceMappingURL=aes.min.js.map +!function(e,n){"object"==typeof exports?module.exports=exports=n(require("./core.min")):"function"==typeof define&&define.amd?define(["./core.min"],n):n(e.CryptoJS)}(this,function(e){return e.enc.Utf8}); +//# sourceMappingURL=enc-utf8.min.js.map \ No newline at end of file diff --git a/modules/kdayun-app/src/main/resources/static/libs/svg-inject.js b/modules/kdayun-app/src/main/resources/static/libs/svg-inject.js new file mode 100644 index 0000000..4e74af0 --- /dev/null +++ b/modules/kdayun-app/src/main/resources/static/libs/svg-inject.js @@ -0,0 +1,697 @@ +/** + * SVGInject - Version 1.2.3 + * A tiny, intuitive, robust, caching solution for injecting SVG files inline into the DOM. + * + * https://github.com/iconfu/svg-inject + * + * Copyright (c) 2018 INCORS, the creators of iconfu.com + * @license MIT License - https://github.com/iconfu/svg-inject/blob/master/LICENSE + */ + +(function(window, document) { + // constants for better minification + var _CREATE_ELEMENT_ = 'createElement'; + var _GET_ELEMENTS_BY_TAG_NAME_ = 'getElementsByTagName'; + var _LENGTH_ = 'length'; + var _STYLE_ = 'style'; + var _TITLE_ = 'title'; + var _UNDEFINED_ = 'undefined'; + var _SET_ATTRIBUTE_ = 'setAttribute'; + var _GET_ATTRIBUTE_ = 'getAttribute'; + + var NULL = null; + + // constants + var __SVGINJECT = '__svgInject'; + var ID_SUFFIX = '--inject-'; + var ID_SUFFIX_REGEX = new RegExp(ID_SUFFIX + '\\d+', "g"); + var LOAD_FAIL = 'LOAD_FAIL'; + var SVG_NOT_SUPPORTED = 'SVG_NOT_SUPPORTED'; + var SVG_INVALID = 'SVG_INVALID'; + var ATTRIBUTE_EXCLUSION_NAMES = ['src', 'alt', 'onload', 'onerror']; + var A_ELEMENT = document[_CREATE_ELEMENT_]('a'); + var IS_SVG_SUPPORTED = typeof SVGRect != _UNDEFINED_; + var DEFAULT_OPTIONS = { + useCache: true, + copyAttributes: true, + makeIdsUnique: true + }; + // Map of IRI referenceable tag names to properties that can reference them. This is defined in + // https://www.w3.org/TR/SVG11/linking.html#processingIRI + var IRI_TAG_PROPERTIES_MAP = { + clipPath: ['clip-path'], + 'color-profile': NULL, + cursor: NULL, + filter: NULL, + linearGradient: ['fill', 'stroke'], + marker: ['marker', 'marker-end', 'marker-mid', 'marker-start'], + mask: NULL, + pattern: ['fill', 'stroke'], + radialGradient: ['fill', 'stroke'] + }; + var INJECTED = 1; + var FAIL = 2; + + var uniqueIdCounter = 1; + var xmlSerializer; + var domParser; + + + // creates an SVG document from an SVG string + function svgStringToSvgDoc(svgStr) { + domParser = domParser || new DOMParser(); + return domParser.parseFromString(svgStr, 'text/xml'); + } + + + // searializes an SVG element to an SVG string + function svgElemToSvgString(svgElement) { + xmlSerializer = xmlSerializer || new XMLSerializer(); + return xmlSerializer.serializeToString(svgElement); + } + + + // Returns the absolute url for the specified url + function getAbsoluteUrl(url) { + A_ELEMENT.href = url; + return A_ELEMENT.href; + } + + + // Load svg with an XHR request + function loadSvg(url, callback, errorCallback) { + if (url) { + var req = new XMLHttpRequest(); + req.onreadystatechange = function() { + if (req.readyState == 4) { + // readyState is DONE + var status = req.status; + if (status == 200) { + // request status is OK + callback(req.responseXML, req.responseText.trim()); + } else if (status >= 400) { + // request status is error (4xx or 5xx) + errorCallback(); + } else if (status == 0) { + // request status 0 can indicate a failed cross-domain call + errorCallback(); + } + } + }; + req.open('GET', url, true); + req.send(); + } + } + + + // Copy attributes from img element to svg element + function copyAttributes(imgElem, svgElem) { + var attribute; + var attributeName; + var attributeValue; + var attributes = imgElem.attributes; + for (var i = 0; i < attributes[_LENGTH_]; i++) { + attribute = attributes[i]; + attributeName = attribute.name; + // Only copy attributes not explicitly excluded from copying + if (ATTRIBUTE_EXCLUSION_NAMES.indexOf(attributeName) == -1) { + attributeValue = attribute.value; + // If img attribute is "title", insert a title element into SVG element + if (attributeName == _TITLE_) { + var titleElem; + var firstElementChild = svgElem.firstElementChild; + if (firstElementChild && firstElementChild.localName.toLowerCase() == _TITLE_) { + // If the SVG element's first child is a title element, keep it as the title element + titleElem = firstElementChild; + } else { + // If the SVG element's first child element is not a title element, create a new title + // ele,emt and set it as the first child + titleElem = document[_CREATE_ELEMENT_ + 'NS']('http://www.w3.org/2000/svg', _TITLE_); + svgElem.insertBefore(titleElem, firstElementChild); + } + // Set new title content + titleElem.textContent = attributeValue; + } else { + // Set img attribute to svg element + svgElem[_SET_ATTRIBUTE_](attributeName, attributeValue); + } + } + } + } + + + // This function appends a suffix to IDs of referenced elements in the in order to to avoid ID collision + // between multiple injected SVGs. The suffix has the form "--inject-X", where X is a running number which is + // incremented with each injection. References to the IDs are adjusted accordingly. + // We assume tha all IDs within the injected SVG are unique, therefore the same suffix can be used for all IDs of one + // injected SVG. + // If the onlyReferenced argument is set to true, only those IDs will be made unique that are referenced from within the SVG + function makeIdsUnique(svgElem, onlyReferenced) { + var idSuffix = ID_SUFFIX + uniqueIdCounter++; + // Regular expression for functional notations of an IRI references. This will find occurences in the form + // url(#anyId) or url("#anyId") (for Internet Explorer) and capture the referenced ID + var funcIriRegex = /url\("?#([a-zA-Z][\w:.-]*)"?\)/g; + // Get all elements with an ID. The SVG spec recommends to put referenced elements inside elements, but + // this is not a requirement, therefore we have to search for IDs in the whole SVG. + var idElements = svgElem.querySelectorAll('[id]'); + var idElem; + // An object containing referenced IDs as keys is used if only referenced IDs should be uniquified. + // If this object does not exist, all IDs will be uniquified. + var referencedIds = onlyReferenced ? [] : NULL; + var tagName; + var iriTagNames = {}; + var iriProperties = []; + var changed = false; + var i, j; + + if (idElements[_LENGTH_]) { + // Make all IDs unique by adding the ID suffix and collect all encountered tag names + // that are IRI referenceable from properities. + for (i = 0; i < idElements[_LENGTH_]; i++) { + tagName = idElements[i].localName; // Use non-namespaced tag name + // Make ID unique if tag name is IRI referenceable + if (tagName in IRI_TAG_PROPERTIES_MAP) { + iriTagNames[tagName] = 1; + } + } + // Get all properties that are mapped to the found IRI referenceable tags + for (tagName in iriTagNames) { + (IRI_TAG_PROPERTIES_MAP[tagName] || [tagName]).forEach(function (mappedProperty) { + // Add mapped properties to array of iri referencing properties. + // Use linear search here because the number of possible entries is very small (maximum 11) + if (iriProperties.indexOf(mappedProperty) < 0) { + iriProperties.push(mappedProperty); + } + }); + } + if (iriProperties[_LENGTH_]) { + // Add "style" to properties, because it may contain references in the form 'style="fill:url(#myFill)"' + iriProperties.push(_STYLE_); + } + // Run through all elements of the SVG and replace IDs in references. + // To get all descending elements, getElementsByTagName('*') seems to perform faster than querySelectorAll('*'). + // Since svgElem.getElementsByTagName('*') does not return the svg element itself, we have to handle it separately. + var descElements = svgElem[_GET_ELEMENTS_BY_TAG_NAME_]('*'); + var element = svgElem; + var propertyName; + var value; + var newValue; + for (i = -1; element != NULL;) { + if (element.localName == _STYLE_) { + // If element is a style element, replace IDs in all occurences of "url(#anyId)" in text content + value = element.textContent; + newValue = value && value.replace(funcIriRegex, function(match, id) { + if (referencedIds) { + referencedIds[id] = 1; + } + return 'url(#' + id + idSuffix + ')'; + }); + if (newValue !== value) { + element.textContent = newValue; + } + } else if (element.hasAttributes()) { + // Run through all property names for which IDs were found + for (j = 0; j < iriProperties[_LENGTH_]; j++) { + propertyName = iriProperties[j]; + value = element[_GET_ATTRIBUTE_](propertyName); + newValue = value && value.replace(funcIriRegex, function(match, id) { + if (referencedIds) { + referencedIds[id] = 1; + } + return 'url(#' + id + idSuffix + ')'; + }); + if (newValue !== value) { + element[_SET_ATTRIBUTE_](propertyName, newValue); + } + } + // Replace IDs in xlink:ref and href attributes + ['xlink:href', 'href'].forEach(function(refAttrName) { + var iri = element[_GET_ATTRIBUTE_](refAttrName); + if (/^\s*#/.test(iri)) { // Check if iri is non-null and internal reference + iri = iri.trim(); + element[_SET_ATTRIBUTE_](refAttrName, iri + idSuffix); + if (referencedIds) { + // Add ID to referenced IDs + referencedIds[iri.substring(1)] = 1; + } + } + }); + } + element = descElements[++i]; + } + for (i = 0; i < idElements[_LENGTH_]; i++) { + idElem = idElements[i]; + // If set of referenced IDs exists, make only referenced IDs unique, + // otherwise make all IDs unique. + if (!referencedIds || referencedIds[idElem.id]) { + // Add suffix to element's ID + idElem.id += idSuffix; + changed = true; + } + } + } + // return true if SVG element has changed + return changed; + } + + + // For cached SVGs the IDs are made unique by simply replacing the already inserted unique IDs with a + // higher ID counter. This is much more performant than a call to makeIdsUnique(). + function makeIdsUniqueCached(svgString) { + return svgString.replace(ID_SUFFIX_REGEX, ID_SUFFIX + uniqueIdCounter++); + } + + + // Inject SVG by replacing the img element with the SVG element in the DOM + function inject(imgElem, svgElem, absUrl, options) { + if (svgElem) { + svgElem[_SET_ATTRIBUTE_]('data-inject-url', absUrl); + var parentNode = imgElem.parentNode; + if (parentNode) { + if (options.copyAttributes) { + copyAttributes(imgElem, svgElem); + } + // Invoke beforeInject hook if set + var beforeInject = options.beforeInject; + var injectElem = (beforeInject && beforeInject(imgElem, svgElem)) || svgElem; + // Replace img element with new element. This is the actual injection. + parentNode.replaceChild(injectElem, imgElem); + // Mark img element as injected + imgElem[__SVGINJECT] = INJECTED; + removeOnLoadAttribute(imgElem); + // Invoke afterInject hook if set + var afterInject = options.afterInject; + if (afterInject) { + afterInject(imgElem, injectElem); + } + } + } else { + svgInvalid(imgElem, options); + } + } + + + // Merges any number of options objects into a new object + function mergeOptions() { + var mergedOptions = {}; + var args = arguments; + // Iterate over all specified options objects and add all properties to the new options object + for (var i = 0; i < args[_LENGTH_]; i++) { + var argument = args[i]; + for (var key in argument) { + if (argument.hasOwnProperty(key)) { + mergedOptions[key] = argument[key]; + } + } + } + return mergedOptions; + } + + + // Adds the specified CSS to the document's element + function addStyleToHead(css) { + var head = document[_GET_ELEMENTS_BY_TAG_NAME_]('head')[0]; + if (head) { + var style = document[_CREATE_ELEMENT_](_STYLE_); + style.type = 'text/css'; + style.appendChild(document.createTextNode(css)); + head.appendChild(style); + } + } + + + // Builds an SVG element from the specified SVG string + function buildSvgElement(svgStr, verify) { + if (verify) { + var svgDoc; + try { + // Parse the SVG string with DOMParser + svgDoc = svgStringToSvgDoc(svgStr); + } catch(e) { + return NULL; + } + if (svgDoc[_GET_ELEMENTS_BY_TAG_NAME_]('parsererror')[_LENGTH_]) { + // DOMParser does not throw an exception, but instead puts parsererror tags in the document + return NULL; + } + return svgDoc.documentElement; + } else { + var div = document.createElement('div'); + div.innerHTML = svgStr; + return div.firstElementChild; + } + } + + + function removeOnLoadAttribute(imgElem) { + // Remove the onload attribute. Should only be used to remove the unstyled image flash protection and + // make the element visible, not for removing the event listener. + imgElem.removeAttribute('onload'); + } + + + function errorMessage(msg) { + console.error('SVGInject: ' + msg); + } + + + function fail(imgElem, status, options) { + imgElem[__SVGINJECT] = FAIL; + if (options.onFail) { + options.onFail(imgElem, status); + } else { + errorMessage(status); + } + } + + + function svgInvalid(imgElem, options) { + removeOnLoadAttribute(imgElem); + fail(imgElem, SVG_INVALID, options); + } + + + function svgNotSupported(imgElem, options) { + removeOnLoadAttribute(imgElem); + fail(imgElem, SVG_NOT_SUPPORTED, options); + } + + + function loadFail(imgElem, options) { + fail(imgElem, LOAD_FAIL, options); + } + + + function removeEventListeners(imgElem) { + imgElem.onload = NULL; + imgElem.onerror = NULL; + } + + + function imgNotSet(msg) { + errorMessage('no img element'); + } + + + function createSVGInject(globalName, options) { + var defaultOptions = mergeOptions(DEFAULT_OPTIONS, options); + var svgLoadCache = {}; + + if (IS_SVG_SUPPORTED) { + // If the browser supports SVG, add a small stylesheet that hides the elements until + // injection is finished. This avoids showing the unstyled SVGs before style is applied. + addStyleToHead('img[onload^="' + globalName + '("]{visibility:hidden;}'); + } + + + /** + * SVGInject + * + * Injects the SVG specified in the `src` attribute of the specified `img` element or array of `img` + * elements. Returns a Promise object which resolves if all passed in `img` elements have either been + * injected or failed to inject (Only if a global Promise object is available like in all modern browsers + * or through a polyfill). + * + * Options: + * useCache: If set to `true` the SVG will be cached using the absolute URL. Default value is `true`. + * copyAttributes: If set to `true` the attributes will be copied from `img` to `svg`. Dfault value + * is `true`. + * makeIdsUnique: If set to `true` the ID of elements in the `` element that can be references by + * property values (for example 'clipPath') are made unique by appending "--inject-X", where X is a + * running number which increases with each injection. This is done to avoid duplicate IDs in the DOM. + * beforeLoad: Hook before SVG is loaded. The `img` element is passed as a parameter. If the hook returns + * a string it is used as the URL instead of the `img` element's `src` attribute. + * afterLoad: Hook after SVG is loaded. The loaded `svg` element and `svg` string are passed as a + * parameters. If caching is active this hook will only get called once for injected SVGs with the + * same absolute path. Changes to the `svg` element in this hook will be applied to all injected SVGs + * with the same absolute path. It's also possible to return an `svg` string or `svg` element which + * will then be used for the injection. + * beforeInject: Hook before SVG is injected. The `img` and `svg` elements are passed as parameters. If + * any html element is returned it gets injected instead of applying the default SVG injection. + * afterInject: Hook after SVG is injected. The `img` and `svg` elements are passed as parameters. + * onAllFinish: Hook after all `img` elements passed to an SVGInject() call have either been injected or + * failed to inject. + * onFail: Hook after injection fails. The `img` element and a `status` string are passed as an parameter. + * The `status` can be either `'SVG_NOT_SUPPORTED'` (the browser does not support SVG), + * `'SVG_INVALID'` (the SVG is not in a valid format) or `'LOAD_FAILED'` (loading of the SVG failed). + * + * @param {HTMLImageElement} img - an img element or an array of img elements + * @param {Object} [options] - optional parameter with [options](#options) for this injection. + */ + function SVGInject(img, options) { + options = mergeOptions(defaultOptions, options); + + var run = function(resolve) { + var allFinish = function() { + var onAllFinish = options.onAllFinish; + if (onAllFinish) { + onAllFinish(); + } + resolve && resolve(); + }; + + if (img && typeof img[_LENGTH_] != _UNDEFINED_) { + // an array like structure of img elements + var injectIndex = 0; + var injectCount = img[_LENGTH_]; + + if (injectCount == 0) { + allFinish(); + } else { + var finish = function() { + if (++injectIndex == injectCount) { + allFinish(); + } + }; + + for (var i = 0; i < injectCount; i++) { + SVGInjectElement(img[i], options, finish); + } + } + } else { + // only one img element + SVGInjectElement(img, options, allFinish); + } + }; + + // return a Promise object if globally available + return typeof Promise == _UNDEFINED_ ? run() : new Promise(run); + } + + + // Injects a single svg element. Options must be already merged with the default options. + function SVGInjectElement(imgElem, options, callback) { + if (imgElem) { + var svgInjectAttributeValue = imgElem[__SVGINJECT]; + if (!svgInjectAttributeValue) { + removeEventListeners(imgElem); + + if (!IS_SVG_SUPPORTED) { + svgNotSupported(imgElem, options); + callback(); + return; + } + // Invoke beforeLoad hook if set. If the beforeLoad returns a value use it as the src for the load + // URL path. Else use the imgElem's src attribute value. + var beforeLoad = options.beforeLoad; + var src = (beforeLoad && beforeLoad(imgElem)) || imgElem[_GET_ATTRIBUTE_]('src'); + + if (!src) { + // If no image src attribute is set do no injection. This can only be reached by using javascript + // because if no src attribute is set the onload and onerror events do not get called + if (src === '') { + loadFail(imgElem, options); + } + callback(); + return; + } + + // set array so later calls can register callbacks + var onFinishCallbacks = []; + imgElem[__SVGINJECT] = onFinishCallbacks; + + var onFinish = function() { + callback(); + onFinishCallbacks.forEach(function(onFinishCallback) { + onFinishCallback(); + }); + }; + + var absUrl = getAbsoluteUrl(src); + var useCacheOption = options.useCache; + var makeIdsUniqueOption = options.makeIdsUnique; + + var setSvgLoadCacheValue = function(val) { + if (useCacheOption) { + svgLoadCache[absUrl].forEach(function(svgLoad) { + svgLoad(val); + }); + svgLoadCache[absUrl] = val; + } + }; + + if (useCacheOption) { + var svgLoad = svgLoadCache[absUrl]; + + var handleLoadValue = function(loadValue) { + if (loadValue === LOAD_FAIL) { + loadFail(imgElem, options); + } else if (loadValue === SVG_INVALID) { + svgInvalid(imgElem, options); + } else { + var hasUniqueIds = loadValue[0]; + var svgString = loadValue[1]; + var uniqueIdsSvgString = loadValue[2]; + var svgElem; + + if (makeIdsUniqueOption) { + if (hasUniqueIds === NULL) { + // IDs for the SVG string have not been made unique before. This may happen if previous + // injection of a cached SVG have been run with the option makedIdsUnique set to false + svgElem = buildSvgElement(svgString, false); + hasUniqueIds = makeIdsUnique(svgElem, false); + + loadValue[0] = hasUniqueIds; + loadValue[2] = hasUniqueIds && svgElemToSvgString(svgElem); + } else if (hasUniqueIds) { + // Make IDs unique for already cached SVGs with better performance + svgString = makeIdsUniqueCached(uniqueIdsSvgString); + } + } + + svgElem = svgElem || buildSvgElement(svgString, false); + + inject(imgElem, svgElem, absUrl, options); + } + onFinish(); + }; + + if (typeof svgLoad != _UNDEFINED_) { + // Value for url exists in cache + if (svgLoad.isCallbackQueue) { + // Same url has been cached, but value has not been loaded yet, so add to callbacks + svgLoad.push(handleLoadValue); + } else { + handleLoadValue(svgLoad); + } + return; + } else { + var svgLoad = []; + // set property isCallbackQueue to Array to differentiate from array with cached loaded values + svgLoad.isCallbackQueue = true; + svgLoadCache[absUrl] = svgLoad; + } + } + + // Load the SVG because it is not cached or caching is disabled + loadSvg(absUrl, function(svgXml, svgString) { + // Use the XML from the XHR request if it is an instance of Document. Otherwise + // (for example of IE9), create the svg document from the svg string. + var svgElem = svgXml instanceof Document ? svgXml.documentElement : buildSvgElement(svgString, true); + + var afterLoad = options.afterLoad; + if (afterLoad) { + // Invoke afterLoad hook which may modify the SVG element. After load may also return a new + // svg element or svg string + var svgElemOrSvgString = afterLoad(svgElem, svgString) || svgElem; + if (svgElemOrSvgString) { + // Update svgElem and svgString because of modifications to the SVG element or SVG string in + // the afterLoad hook, so the modified SVG is also used for all later cached injections + var isString = typeof svgElemOrSvgString == 'string'; + svgString = isString ? svgElemOrSvgString : svgElemToSvgString(svgElem); + svgElem = isString ? buildSvgElement(svgElemOrSvgString, true) : svgElemOrSvgString; + } + } + + if (svgElem instanceof SVGElement) { + var hasUniqueIds = NULL; + if (makeIdsUniqueOption) { + hasUniqueIds = makeIdsUnique(svgElem, false); + } + + if (useCacheOption) { + var uniqueIdsSvgString = hasUniqueIds && svgElemToSvgString(svgElem); + // set an array with three entries to the load cache + setSvgLoadCacheValue([hasUniqueIds, svgString, uniqueIdsSvgString]); + } + + inject(imgElem, svgElem, absUrl, options); + } else { + svgInvalid(imgElem, options); + setSvgLoadCacheValue(SVG_INVALID); + } + onFinish(); + }, function() { + loadFail(imgElem, options); + setSvgLoadCacheValue(LOAD_FAIL); + onFinish(); + }); + } else { + if (Array.isArray(svgInjectAttributeValue)) { + // svgInjectAttributeValue is an array. Injection is not complete so register callback + svgInjectAttributeValue.push(callback); + } else { + callback(); + } + } + } else { + imgNotSet(); + } + } + + + /** + * Sets the default [options](#options) for SVGInject. + * + * @param {Object} [options] - default [options](#options) for an injection. + */ + SVGInject.setOptions = function(options) { + defaultOptions = mergeOptions(defaultOptions, options); + }; + + + // Create a new instance of SVGInject + SVGInject.create = createSVGInject; + + + /** + * Used in onerror Event of an `` element to handle cases when the loading the original src fails + * (for example if file is not found or if the browser does not support SVG). This triggers a call to the + * options onFail hook if available. The optional second parameter will be set as the new src attribute + * for the img element. + * + * @param {HTMLImageElement} img - an img element + * @param {String} [fallbackSrc] - optional parameter fallback src + */ + SVGInject.err = function(img, fallbackSrc) { + if (img) { + if (img[__SVGINJECT] != FAIL) { + removeEventListeners(img); + + if (!IS_SVG_SUPPORTED) { + svgNotSupported(img, defaultOptions); + } else { + removeOnLoadAttribute(img); + loadFail(img, defaultOptions); + } + if (fallbackSrc) { + removeOnLoadAttribute(img); + img.src = fallbackSrc; + } + } + } else { + imgNotSet(); + } + }; + + window[globalName] = SVGInject; + + return SVGInject; + } + + var SVGInjectInstance = createSVGInject('SVGInject'); + + if (typeof module == 'object' && typeof module.exports == 'object') { + module.exports = SVGInjectInstance; + } +})(window, document); \ No newline at end of file diff --git a/modules/kdayun-app/src/main/resources/static/libs/svg-inject.min.js b/modules/kdayun-app/src/main/resources/static/libs/svg-inject.min.js new file mode 100644 index 0000000..1631485 --- /dev/null +++ b/modules/kdayun-app/src/main/resources/static/libs/svg-inject.min.js @@ -0,0 +1,10 @@ +!function(o,l){var r,a,s="createElement",g="getElementsByTagName",b="length",E="style",d="title",y="undefined",k="setAttribute",w="getAttribute",x=null,A="__svgInject",C="--inject-",S=new RegExp(C+"\\d+","g"),I="LOAD_FAIL",t="SVG_NOT_SUPPORTED",L="SVG_INVALID",v=["src","alt","onload","onerror"],j=l[s]("a"),G=typeof SVGRect!=y,f={useCache:!0,copyAttributes:!0,makeIdsUnique:!0},N={clipPath:["clip-path"],"color-profile":x,cursor:x,filter:x,linearGradient:["fill","stroke"],marker:["marker", +"marker-end","marker-mid","marker-start"],mask:x,pattern:["fill","stroke"],radialGradient:["fill","stroke"]},u=1,c=2,O=1;function T(e){return(r=r||new XMLSerializer).serializeToString(e)}function P(e,r){var t,n,i,o,a=C+O++,f=/url\("?#([a-zA-Z][\w:.-]*)"?\)/g,u=e.querySelectorAll("[id]"),c=r?[]:x,l={},s=[],d=!1;if(u[b]){for(i=0;i2.0.4 - 1.2.0 + 1.9.0 3.15