(function (global, factory) { "use strict"; if (typeof module === "object" && typeof module.exports === "object") { module.exports = factory(global, true); } else { factory(global); } })(typeof window !== "undefined" ? window : this, function (window, noGlobal) { "use strict"; var bFinished = true; function getHttpObj() { var httpobj = null; if (IEVersion() < 10) { try { httpobj = new XDomainRequest(); } catch (e1) { httpobj = new createXHR(); } } else { httpobj = new createXHR(); } return httpobj; } //兼容IE低版本的创建xmlhttprequest对象的方法 function createXHR() { if (typeof XMLHttpRequest != 'undefined') { //兼容高版本浏览器 return new XMLHttpRequest(); } else if (typeof ActiveXObject != 'undefined') { //IE6 采用 ActiveXObject, 兼容IE6 var versions = [ //由于MSXML库有3个版本,因此都要考虑 'MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp' ]; for (var i = 0; i < versions.length; i++) { try { return new ActiveXObject(versions[i]); } catch (e) { //跳过 } } } else { throw new Error('您的浏览器不支持XHR对象'); } } function startWps(options) { if (!bFinished && !options.concurrent) { if (options.callback) options.callback({ status: 1, message: "上一次请求没有完成" }); return; } bFinished = false; function startWpsInnder(tryCount) { if (tryCount <= 0) { if (bFinished) return; bFinished = true; if (options.callback) options.callback({ status: 2, message: "请允许浏览器打开WPS Office" }); return; } var xmlReq = getHttpObj(); //WPS客户端提供的接收参数的本地服务,HTTP服务端口为58890,HTTPS服务端口为58891 //这俩配置,取一即可,不可同时启用 xmlReq.open('POST', options.url); xmlReq.onload = function (res) { bFinished = true; if (options.callback) { options.callback({ status: 0, response: IEVersion() < 10 ? xmlReq.responseText : res.target.response }); } } xmlReq.ontimeout = xmlReq.onerror = function (res) { xmlReq.bTimeout = true; if (tryCount == options.tryCount && options.bPop) { //打开wps并传参 window.location.href = "ksoWPSCloudSvr://start=RelayHttpServer" //是否启动wps弹框 } setTimeout(function () { startWpsInnder(tryCount - 1) }, 1000); } if (IEVersion() < 10) { xmlReq.onreadystatechange = function () { if (xmlReq.readyState != 4) return; if (xmlReq.bTimeout) { return; } if (xmlReq.status === 200) xmlReq.onload(); else xmlReq.onerror(); } } xmlReq.timeout = options.timeout; xmlReq.send(options.sendData) } startWpsInnder(options.tryCount); return; } var fromCharCode = String.fromCharCode; // encoder stuff var cb_utob = function (c) { if (c.length < 2) { var cc = c.charCodeAt(0); return cc < 0x80 ? c : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) + fromCharCode(0x80 | (cc & 0x3f))) : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + fromCharCode(0x80 | (cc & 0x3f))); } else { var cc = 0x10000 + (c.charCodeAt(0) - 0xD800) * 0x400 + (c.charCodeAt(1) - 0xDC00); return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + fromCharCode(0x80 | (cc & 0x3f))); } }; var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; var utob = function (u) { return u.replace(re_utob, cb_utob); }; var _encode = function (u) { var isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]'; if (isUint8Array) return u.toString('base64') else return btoa(utob(String(u))); } if (typeof window.btoa !== 'function') window.btoa = func_btoa; function func_btoa(input) { var str = String(input); var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; for ( // initialize result and counter var block, charCode, idx = 0, map = chars, output = ''; // if the next str index does not exist: // change the mapping table to "=" // check if d has no fractional digits str.charAt(idx | 0) || (map = '=', idx % 1); // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8 output += map.charAt(63 & block >> 8 - idx % 1 * 8) ) { charCode = str.charCodeAt(idx += 3 / 4); if (charCode > 0xFF) { throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."); } block = block << 8 | charCode; } return output; } var encode = function (u, urisafe) { return !urisafe ? _encode(u) : _encode(String(u)).replace(/[+\/]/g, function (m0) { return m0 == '+' ? '-' : '_'; }).replace(/=/g, ''); }; function IEVersion() { var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串 var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器 var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器 var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1; if (isIE) { var reIE = new RegExp("MSIE (\\d+\\.\\d+);"); reIE.test(userAgent); var fIEVersion = parseFloat(RegExp["$1"]); if (fIEVersion == 7) { return 7; } else if (fIEVersion == 8) { return 8; } else if (fIEVersion == 9) { return 9; } else if (fIEVersion == 10) { return 10; } else { return 6; //IE版本<=7 } } else if (isEdge) { return 20; //edge } else if (isIE11) { return 11; //IE11 } else { return 30; //不是ie浏览器 } } function WpsStart(options) { var startInfo = { "name": options.name, "function": options.func, "info": options.param.param, "jsPluginsXml": options.param.jsPluginsXml }; var strData = JSON.stringify(startInfo); if (IEVersion() < 10) { try { eval("strData = '" + JSON.stringify(startInfo) + "';"); } catch (err) { } } var baseData = encode(strData); var url = options.urlBase + "/" + options.clientType + "/runParams"; var data = "ksowebstartup" + options.clientType + "://" + baseData; startWps({ url: url, sendData: data, callback: options.callback, tryCount: options.tryCount, bPop: options.bPop, timeout: 5000, concurrent: false, client: options.wpsclient }); } function WpsStartWrap(options) { WpsStart({ clientType: options.clientType, name: options.name, func: options.func, param: options.param, urlBase: options.urlBase, callback: options.callback, tryCount: 4, bPop: true, wpsclient: options.wpsclient, }) } /** * 支持浏览器触发,WPS有返回值的启动 * * @param {*} clientType 组件类型 * @param {*} name WPS加载项名称 * @param {*} func WPS加载项入口方法 * @param {*} param 参数:包括WPS加载项内部定义的方法,参数等 * @param {*} callback 回调函数 * @param {*} tryCount 重试次数 * @param {*} bPop 是否弹出浏览器提示对话框 */ var exId = 0; function WpsStartWrapExInner(options) { var infocontent = options.param.param; if (!options.wpsclient) { infocontent = JSON.stringify(options.param.param); var rspUrl = options.urlBase + "/transferEcho/runParams"; var time = new Date(); var cmdId = "js" + time.getTime() + "_" + exId; var funcEx = "var res = " + options.func; var cbCode = "var xhr = new XMLHttpRequest();xhr.open('POST', '" + rspUrl + "');xhr.send(JSON.stringify({id: '" + cmdId + "', response: res}));" //res 为func执行返回值 var infoEx = infocontent + ");" + cbCode + "void(0"; options.func = funcEx; infocontent = infoEx; } var startInfo = { "name": options.name, "function": options.func, "info": infocontent, "showToFront": options.param.showToFront, "jsPluginsXml": options.param.jsPluginsXml, }; var strData = JSON.stringify(startInfo); if (IEVersion() < 10) { try { eval("strData = '" + JSON.stringify(startInfo) + "';"); } catch (err) { } } var baseData = encode(strData); var wrapper; if (!options.wpsclient) { var url = options.urlBase + "/transfer/runParams"; var data = "ksowebstartup" + options.clientType + "://" + baseData; wrapper = { id: cmdId, app: options.clientType, data: data }; } else { var url = options.urlBase + "/transferEx/runParams"; wrapper = { id: options.wpsclient.clientId, app: options.clientType, data: baseData, mode: options.wpsclient.silentMode ? "true" : "false" }; } wrapper = JSON.stringify(wrapper); startWps({ url: url, sendData: wrapper, callback: options.callback, tryCount: options.tryCount, bPop: options.bPop, timeout: 0, concurrent: options.concurrent, client: options.wpsclient }); } var serverVersion = "wait" var cloudSvrStart = true; function WpsStartWrapVersionInner(options) { if (serverVersion == "wait") { if (cloudSvrStart == false) { window.location.href = "ksoWPSCloudSvr://start=RelayHttpServer" //是否启动wps弹框 } startWps({ url: options.urlBase + '/version', data: "", callback: function (res) { if (res.status !== 0) { options.callback(res) return; } serverVersion = res.response; cloudSvrStart = true; options.tryCount = 1 options.bPop = false if (serverVersion === "") { WpsStart(options) } else if (serverVersion < "1.0.1" && options.wpsclient) { if (options.callback) { options.callback({ status: 4, message: "当前客户端不支持,请升级客户端" }) } } else { WpsStartWrapExInner(options); } }, tryCount: 4, bPop: true, timeout: 5000, concurrent: options.concurrent }); } else { if (serverVersion === "") { WpsStartWrap(options) } else if (serverVersion < "1.0.1" && options.wpsclient) { if (options.callback) { options.callback({ status: 4, message: "当前客户端不支持,请升级客户端" }) } } else { WpsStartWrapExInner(options); } } } var RegWebNotifyMap = { wps: {}, wpp: {}, et: {} } var bWebNotifyUseTimeout = true function WebNotifyUseTimeout(value) { bWebNotifyUseTimeout = value ? true : false } /** * 注册一个前端页面接收WPS传来消息的方法 * @param {*} clientType wps | et | wpp * @param {*} name WPS加载项的名称 * @param {*} callback 回调函数 */ function RegWebNotify(clientType, name, callback, wpsclient) { if (clientType != "wps" && clientType != "wpp" && clientType != "et") return; var paramStr = {} if (wpsclient) { if (wpsclient.notifyRegsitered == true) { return } wpsclient.notifyRegsitered = true; paramStr = { clientId: wpsclient.clientId, name: name, type: clientType } } else { if (typeof callback != 'function') return if (RegWebNotifyMap[clientType][name]) { RegWebNotifyMap[clientType][name] = callback; return } var RegWebNotifyID = new Date().valueOf() + '' paramStr = { id: RegWebNotifyID, name: name, type: clientType } RegWebNotifyMap[clientType][name] = callback } var askItem = function () { var xhr = getHttpObj() xhr.onload = function (e) { if (xhr.responseText == "WPSInnerMessage_quit") { return; } if (wpsclient) { wpsclient.OnRegWebNotify(xhr.responseText) } else { var func = RegWebNotifyMap[clientType][name] func(xhr.responseText) } window.setTimeout(askItem, 300) } xhr.onerror = function (e) { if (bWebNotifyUseTimeout) window.setTimeout(askItem, 1000) else window.setTimeout(askItem, 10000) } xhr.ontimeout = function (e) { if (bWebNotifyUseTimeout) window.setTimeout(askItem, 300) else window.setTimeout(askItem, 10000) } if (IEVersion() < 10) { xhr.onreadystatechange = function () { if (xhr.readyState != 4) return; if (xhr.bTimeout) { return; } if (xhr.status === 200) xhr.onload(); else xhr.onerror(); } } xhr.open('POST', GetUrlBase() + '/askwebnotify', true) if (bWebNotifyUseTimeout) xhr.timeout = 2000; xhr.send(JSON.stringify(paramStr)) } window.setTimeout(askItem, 2000) } function GetUrlBase() { if (location.protocol == "http:") return "http://127.0.0.1:58890" return "https://127.0.0.1:58891" } function WpsStartWrapVersion(clientType, name, func, param, callback, showToFront, jsPluginsXml) { var paramEx = { jsPluginsXml: jsPluginsXml ? jsPluginsXml : "", showToFront: typeof (showToFront) == 'boolean' ? showToFront : true, param: (typeof (param) == 'object' ? param : JSON.parse(param)) } var options = { clientType: clientType, name: name, func: func, param: paramEx, urlBase: GetUrlBase(), callback: callback, wpsclient: undefined, concurrent: true } WpsStartWrapVersionInner(options); } //从外部浏览器远程调用 WPS 加载项中的方法 var WpsInvoke = { InvokeAsHttp: WpsStartWrapVersion, InvokeAsHttps: WpsStartWrapVersion, RegWebNotify: RegWebNotify, ClientType: { wps: "wps", et: "et", wpp: "wpp" }, CreateXHR: getHttpObj, IsClientRunning: IsClientRunning } window.wpsclients = []; /** * @constructor WpsClient wps客户端 * @param {string} clientType 必传参数,加载项类型,有效值为"wps","wpp","et";分别表示文字,演示,电子表格 */ function WpsClient(clientType) { /** * 设置RegWebNotify的回调函数,加载项给业务端发消息通过该函数 * @memberof WpsClient * @member onMessage */ this.onMessage; /** * 设置加载项路径 * @memberof WpsClient * @member jsPluginsXml */ this.jsPluginsXml; /** * 内部成员,外部无需调用 */ this.notifyRegsitered = false; this.clientId = ""; this.concurrent = false; this.clientType = clientType; this.firstRequest = true; /** * 内部函数,外部无需调用 * @param {*} options */ this.initWpsClient = function (options) { options.clientType = this.clientType options.wpsclient = this options.concurrent = this.firstRequest ? true : this.concurrent this.firstRequest = false; WpsStartWrapVersionInner(options) } /** * 以http启动 * @param {string} name 加载项名称 * @param {string} func 要调用的加载项中的函数行 * @param {string} param 在加载项中执行函数func要传递的数据 * @param {function({int, string})} callback 回调函数,status = 0 表示成功,失败请查看message信息 * @param {bool} showToFront 设置wps是否显示到前面来 * @return {string} "Failed to send message to WPS." 发送消息失败,客户端已关闭; * "WPS Addon is not response." 加载项阻塞,函数执行失败 */ this.InvokeAsHttp = function (name, func, param, callback, showToFront) { function clientCallback(res) { //this不是WpsClient if (res.status !== 0 || serverVersion < "1.0.1") { if (callback) callback(res); return; } var resObject = JSON.parse(res.response); if (this.client.clientId == "") { this.client.clientId = resObject.clientId; } this.client.concurrent = true; if (typeof resObject.data == "object") res.response = JSON.stringify(resObject.data); else res.response = resObject.data; if (IEVersion() < 10) eval(" res.response = '" + res.response + "';"); if (callback) callback(res); this.client.RegWebNotify(name); } var paramEx = { jsPluginsXml: this.jsPluginsXml ? this.jsPluginsXml : "", showToFront: typeof (showToFront) == 'boolean' ? showToFront : true, param: (typeof (param) == 'object' ? param : JSON.parse(param)) } this.initWpsClient({ name: name, func: func, param: paramEx, urlBase: GetUrlBase(), callback: clientCallback }) } /** * 以https启动 * @param {string} name 加载项名称 * @param {string} func 要调用的加载项中的函数行 * @param {string} param 在加载项中执行函数func要传递的数据 * @param {function({int, string})} callback 回调函数,status = 0 表示成功,失败请查看message信息 * @param {bool} showToFront 设置wps是否显示到前面来 */ this.InvokeAsHttps = function (name, func, param, callback, showToFront) { var paramEx = { jsPluginsXml: this.jsPluginsXml ? this.jsPluginsXml : "", showToFront: typeof (showToFront) == 'boolean' ? showToFront : true, param: (typeof (param) == 'object' ? param : JSON.parse(param)) } this.initWpsClient({ name: name, func: func, param: paramEx, urlBase: GetUrlBase(), callback: callback }) } /** * 内部函数,外部无需调用 * @param {*} name */ this.RegWebNotify = function (name) { RegWebNotify(this.clientType, name, null, this); } this.OnRegWebNotify = function (message) { if (this.onMessage) this.onMessage(message) } /** * 以静默模式启动客户端 * @param {string} name 必传参数,加载项名称 * @param {function({int, string})} [callback] 回调函数,status = 0 表示成功,失败请查看message信息 */ this.StartWpsInSilentMode = function (name, callback) { function initCallback(res) { //this不是WpsClient if (res.status !== 0 || serverVersion < "1.0.1") { if (callback) callback(res); return; } if (this.client.clientId == "") { this.client.clientId = JSON.parse(res.response).clientId; window.wpsclients[window.wpsclients.length] = { name: name, client: this.client }; } res.response = JSON.stringify(JSON.parse(res.response).data); this.client.concurrent = true; if (callback) { callback(res); } this.client.RegWebNotify(name); } var paramEx = { jsPluginsXml: this.jsPluginsXml, showToFront: false, param: { status: "InitInSilentMode" } } this.silentMode = true; this.initWpsClient({ name: name, func: "", param: paramEx, urlBase: GetUrlBase(), callback: initCallback }) } /** * 显示客户端到最前面 * @param {string} name 必传参数,加载项名称 * @param {function({int, string})} [callback] 回调函数 */ this.ShowToFront = function (name, callback) { if (serverVersion < "1.0.1") { if (callback) { callback({ status: 4, message: "当前客户端不支持,请升级客户端" }); return; } return; } if (this.clientId == "") { if (callback) callback({ status: 3, message: "没有静默启动客户端" }); return; } var paramEx = { jsPluginsXml: "", showToFront: true, param: { status: "ShowToFront" } } this.initWpsClient({ name: name, func: "", param: paramEx, urlBase: GetUrlBase(), callback: callback }) } /** * 关闭未显示出来的静默启动客户端 * @param {string} name 必传参数,加载项名称 * @param {function({int, string})} [callback] 回调函数 */ this.CloseSilentClient = function (name, callback) { if (serverVersion < "1.0.1") { if (callback) { callback({ status: 4, message: "当前客户端不支持,请升级客户端" }); return; } return; } if (this.clientId == "") { if (callback) callback({ status: 3, message: "没有静默启动客户端" }); return; } var paramEx = { jsPluginsXml: "", showToFront: false, param: undefined } var func; if (this.clientType == "wps") func = "wps.WpsApplication().Quit" else if (this.clientType == "et") func = "wps.EtApplication().Quit" else if (this.clientType == "wpp") func = "wps.WppApplication().Quit" function closeSilentClient(res) { if (res.status == 0) this.client.clientId = "" if (callback) callback(res); return; } this.initWpsClient({ name: name, func: func, param: paramEx, urlBase: GetUrlBase(), callback: closeSilentClient }) } /** * 当前客户端是否在运行,使用WpsClient.IsClientRunning()进行调用 * @param {function({int, string})} [callback] 回调函数,"Client is running." 客户端正在运行 * "Client is not running." 客户端没有运行 */ this.IsClientRunning = function (callback) { if (serverVersion < "1.0.1") { if (callback) { callback({ status: 4, message: "当前客户端不支持,请升级客户端" }); return; } return; } IsClientRunning(this.clientType, callback, this) } } function InitSdk() { var url = GetUrlBase() + "/version"; startWps({ url: url, data: "", callback: function (res) { if (res.status !== 0) { cloudSvrStart = false; return; } if (serverVersion == "wait") { serverVersion = res.response; cloudSvrStart = true; } }, tryCount: 1, bPop: false, timeout: 5000 }); } if (typeof noGlobal === "undefined") { window.WpsInvoke = WpsInvoke; window.WpsClient = WpsClient; window.WebNotifyUseTimeout = WebNotifyUseTimeout; InitSdk(); } /** * 当前客户端是否在运行,使用WpsInvoke.IsClientRunning()进行调用 * @param {string} clientType 加载项类型 * @param {function} [callback] 回调函数,"Client is running." 客户端正在运行 * "Client is not running." 客户端没有运行 */ function IsClientRunning(clientType, callback, wpsclient) { var url = GetUrlBase() + "/isRunning"; var wrapper = { id: wpsclient == undefined ? undefined : wpsclient.clientId, app: clientType } wrapper = JSON.stringify(wrapper); startWps({ url: url, sendData: wrapper, callback: callback, tryCount: 1, bPop: false, timeout: 2000, concurrent: true, client: wpsclient }); } function WpsAddonGetAllConfig(callBack) { var baseData; startWps({ url: GetUrlBase() + "/publishlist", type: "GET", sendData: baseData, callback: callBack, tryCount: 3, bPop: true, timeout: 5000, concurrent: true }); } function WpsAddonVerifyStatus(element, callBack) { var xmlReq = getHttpObj(); var offline = element.online === "false"; var url = offline ? element.url : element.url + "ribbon.xml"; xmlReq.open("POST", GetUrlBase() + "/redirect/runParams"); xmlReq.onload = function (res) { if (offline && !res.target.response.startsWith("7z")) { callBack({ status: 1, msg: "不是有效的7z格式" + url }); } else if (!offline && !res.target.response.startsWith("