let wpsModule = { version: '2023.0427.01', createInstance(options) { var forWindowID = !!window.forWindowID ? window.forWindowID : (window.forWindowID = CreateRandomId()) let wpsobj = { $$idx: {}, //对象属性 slCtl: { SupportFormat: [ 'wps', //wps word 'wpt', 'doc', 'docx', 'dotx', 'docm', 'dotm', 'et', //wps excel 'ett', 'xls', 'xlt', 'xlsx', 'xlsm', 'xltx', 'xltm', 'xlsb', ], forWindowID, curFileType: 'default', isFileOpen: false, isWPSInstall: false, isWPSAddonInstall: false, refurl: '', publishIndex: 0, uploadCompentInfoUrl: 'api/framework/v1/indidocx/saveIndidocxMessage', curList: [ { name: 'IndiDocX', addonType: 'wps', online: 'true', url: window.location.origin + '/resource/jsplugindir/', }, { name: 'IndiDocXET', addonType: 'et', online: 'true', url: window.location.origin + '/resource/jsetplugindir/', }, ], localList: [], ErrorMessage: { NotSupport: 'FormatNotSupport' }, checkInstall: function (argsobj) { wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) if (window.sessionStorage && sessionStorage.getItem('isWPSAddonInstall') == 'true') { wpsobj.slCtl.isWPSAddonInstall = true startNotice() return Promise.resolve(true) } wpsobj.slCtl.curList[0].url = argsobj.WPSPluginUrl var promise = new Promise((resolve, reject) => { wpsobj.slCtl.Content.Control._inithttpCompleted = function (o) { if (wpsobj.slCtl.isWPSAddonInstall == true) { if (window.sessionStorage) sessionStorage.setItem('isWPSAddonInstall', 'true') resolve(true) } else { reject(false) } if (wpsobj.slCtl.isWPSInstall == false) { reject(false) } } wpsobj.slCtl.checkWPSInstall(5, 2000) }) return promise }, checkWPSInstall: function (tryCount, timeout) { var xmlReq = new createXHR() var url = 'http://127.0.0.1:58890/version' if (window.location.protocol != 'http:') url = 'https://127.0.0.1:58891/version' xmlReq.open('POST', url) xmlReq.onload = function (res) { wpsobj.slCtl.isWPSInstall = true wpsobj.slCtl.isWPSAddonInstall = false wpsobj.slCtl.CheckWPSAddonInstall(2000) //setTimeout(function () {}, 1000); } xmlReq.ontimeout = xmlReq.onerror = function (res) { if (tryCount == 1) { wpsobj.slCtl.isWPSInstall = false wpsobj.slCtl.Content.Control._inithttpCompleted(false) return } window.location.href = 'ksoWPSCloudSvr://start=RelayHttpServer' setTimeout(function () { wpsobj.slCtl.checkWPSInstall(--tryCount, 2000) }, 2000) } if (timeout == undefined) { timeout = 2000 } xmlReq.timeout = timeout xmlReq.send() }, CheckWPSAddonInstall: function (timeout) { var localList = [] WpsAddonMgr.getAllConfig(function (e) { var elementStr = e.response if (elementStr) { localList = localList.concat(JSON.parse(elementStr)) if (localList[0] != null) { for (var i = 0; i < localList.length; i++) { if ( localList[i].name == 'IndiDocX' && //localList[i].url.indexOf(location.origin) > -1 && (localList[i].enable == 'true' || localList[i].enable == 'enable_dev') ) { wpsobj.slCtl.isWPSAddonInstall = true startNotice() wpsobj.slCtl._uploadCompentInfo(localList[i]) } if ( localList[i].name == 'IndiDocXET' && // localList[i].url.indexOf(location.origin) > -1 && (localList[i].enable == 'true' || localList[i].enable == 'enable_dev') ) { wpsobj.slCtl.isWPSAddonInstall = true } } } else { console.log('准备安装加载项') wpsobj.slCtl.isWPSAddonInstall = false wpsobj.slCtl.installWpsAddin() } } if (timeout == undefined) { timeout = 2000 } setTimeout(wpsobj.slCtl.Content.Control._inithttpCompleted, timeout) }) }, installWpsAddin: function () { WpsAddonMgr.getAllConfig(function (e) { if (wpsobj.slCtl.curList.length > 0) { wpsobj.slCtl.installWpsAddinOne() } }) }, installWpsAddinOne: function () { WpsAddonMgr.enable(wpsobj.slCtl.curList[wpsobj.slCtl.publishIndex], function (e) { if (e.status) { console.log(e.msg) } else { wpsobj.slCtl.Content.Control._inithttpCompleted(true) console.log('安装成功') } wpsobj.slCtl.publishIndex++ if (wpsobj.slCtl.publishIndex < wpsobj.slCtl.curList.length) { wpsobj.slCtl.installWpsAddinOne() } }) }, isSupport(fname) { var ext = fname.match(/\.(?\w*)$/i).groups.ext return this.SupportFormat.some((x) => ext == x) }, InstallWPSAddon: function (callBack) { var localList = [] WpsAddonMgr.getAllConfig(function (e) { var elementStr = e.response if (elementStr) { localList = localList.concat(JSON.parse(elementStr)) for (var i = 0; i < localList.length; i++) { if (localList[i].name == 'IndiDocX' && localList[i].enable == 'false') { WpsAddonMgr.enable(localList[i], callBack) } if (localList[i].name == 'IndiDocXET' && localList[i].enable == 'false') { WpsAddonMgr.enable(localList[i], callBack) } } } }) }, launchBrowser: function (url, type) { return new Promise(function (resolve, reject) { _WpsInvokeExtends( 'command', { name: 'launchBrowser', data: { url, type } }, function (rps) { if (rps.status == 0) { var result = JSON.parse(rps.response) resolve(result) } else { reject() } }, true, 4e4 ) }) }, getRef: function (str, start, substr, seperator) { var pos var endpos pos = str.indexOf(substr, start) if (pos == -1) return '' endpos = str.indexOf(seperator, pos + 1) if (endpos == -1) return str.substring(pos + substr.length, str.length) else return str.substring(pos + substr.length, endpos) }, htmldecode: function (s) { return s; // var div = document.createElement('div') // div.innerHTML = s // return div.textContent }, setFileList: function (data) { var strlist = new Array() for (var i = 0; i < data.length; i++) { strlist.push( data[i].properties + '' + fnGetFileLink(data[i].code) + '' ) } if (strlist != null && strlist != undefined) { wpsobj.slCtl.Content.Files._FileInfoString = strlist wpsobj.slCtl.Content.Files.FileList = wpsobj.slCtl.analyzeFileList(strlist) //解析filelist } }, analyzeFileList: function (FileInfoString) { var arrFileMap = FileInfoString.map(function (onefile, index) { var filelink = '' if (typeof fnGetFileLink === 'function') { filelink = fnGetFileLink( wpsobj.slCtl.getRef(onefile, 0, '', '') ) } return { FileName: wpsobj.slCtl.htmldecode( wpsobj.slCtl.getRef(onefile, 0, '', '') ), Unid: wpsobj.slCtl.getRef(onefile, 0, '', ''), CatNum: wpsobj.slCtl.getRef(onefile, 0, '', ''), Size: wpsobj.slCtl.getRef(onefile, 0, '', ''), FileType: wpsobj.slCtl.getRef(onefile, 0, '', ''), Completed: parseInt(wpsobj.slCtl.getRef(onefile, 0, '', '')), doAdd: wpsobj.slCtl.getRef(onefile, 0, '', '') == 'True' ? true : false, Type: wpsobj.slCtl.getFileType( wpsobj.slCtl.getRef(onefile, 0, '', '') ), CreateInfo: wpsobj.slCtl.getRef(onefile, 0, '', ''), UpdateInfo: wpsobj.slCtl.getRef(onefile, 0, '', ''), TaodaInfo: wpsobj.slCtl.getRef(onefile, 0, '', ''), NeedUpdate: wpsobj.slCtl.getRef(onefile, 0, '', ''), AllowPrint: false, DocUnid: wpsobj.slCtl.getRef(onefile, 0, '', ''), Uploading: parseInt(wpsobj.slCtl.getRef(onefile, 0, '', '')) == 0 && wpsobj.slCtl.getRef(onefile, 0, '', '') == 'False' ? true : false, Link: filelink, } }) return arrFileMap }, formatParams: function (argsobj) { var $$idxtemp = {} $$idxtemp.httpserver = {} $$idxtemp.httpserver.UserName = argsobj.UserName == undefined ? 'admin' : argsobj.UserName $$idxtemp.httpserver.UploadParam = argsobj.UploadParam == undefined ? '' : argsobj.UploadParam $$idxtemp.httpserver.UploadUrl = argsobj.UploadUrl == undefined ? '' : argsobj.UploadUrl $$idxtemp.httpserver.cookie = argsobj.cookie == undefined ? '' : argsobj.cookie $$idxtemp.httpserver.refresh_token = argsobj.refresh_token == undefined ? '' : argsobj.refresh_token return $$idxtemp }, //参数规范化 fileParamsNormalized: function (fileparam) { var result = Object.assign({}, fileparam); if (fileparam.hasOwnProperty('IsMaximization')) result.IsMaximization = getBoolean(fileparam.IsMaximization, true); return result; }, // V6控件打开附件 fnV6OpenFile: function (fname, fileparam) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var promise = new Promise((resolve, reject) => { if (!wpsobj.slCtl.isSupport(fname)) { reject(wpsobj.slCtl.ErrorMessage.NotSupport) return } var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } registerEvent(userfile, resolve) if ( wpsobj.slCtl.getFileType(fname).toLocaleLowerCase() == '.xls' || wpsobj.slCtl.getFileType(fname).toLocaleLowerCase() == '.xlsx' || wpsobj.slCtl.getFileType(fname).toLocaleLowerCase() == '.et' ) { _WpsInvokeET( [ { OpenDoc: { uploadPath: wpsobj.slCtl.$$idx.httpserver.UploadUrl, // 保存文档上传路径 cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, fileparam: fileparam, uploadFieldName: 'file', userName: wpsobj.slCtl.$$idx.httpserver.UserName, openType: { //文档打开方式 // 文档保护类型,-1:不启用保护模式,0:只允许对现有内容进行修订, // 1:只允许添加批注,2:只允许修改窗体域(禁止拷贝功能),3:只读 protectType: Number.parseInt(fileparam.Status), }, }, }, ], reject ) } else { var protectType = Number.parseInt(fileparam.Status) if (protectType == 4) protectType = 1 _WpsInvoke( [ { OpenDoc: { uploadPath: wpsobj.slCtl.$$idx.httpserver.UploadUrl, // 保存文档上传路径 cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, fileparam: fileparam, uploadFieldName: 'file', userName: wpsobj.slCtl.$$idx.httpserver.UserName, openType: { //文档打开方式 // 文档保护类型,-1:不启用保护模式,0:只允许对现有内容进行修订, // 1:只允许添加批注,2:只允许修改窗体域(禁止拷贝功能),3:只读 protectType, }, }, }, ], reject ) } }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, CreateTrackFileName: function (sourcename) { var count = 1 var tmp = null var files = wpsobj.slCtl.Content.Files for (var i = 0; i < files.FileList.length; i++) { var userFile = files.FileList[i] var filename = userFile.FileName if (filename.indexOf('痕迹稿') != -1 && filename.indexOf('_' + sourcename) != -1) { count++ } } tmp = '痕迹稿' + count + '_' + sourcename //痕迹1_正文.doc return tmp }, /** * 获取用户信息的扩展接口,如果项目需要,可以自行覆盖实现方法 * 默认是基于产品的实现 * @returns Object{id,account,name,access_token} */ getUserInfo: function () { var state = JSON.parse(sessionStorage.getItem('vuex')) // var userinfo = state?.sd?.common?.userInfo?.default || {} if (!!state && !!state.sd.login && state.sd.login.tokens) { var info = {} info.access_token = state.sd.login.tokens.access_token if ( !!state.sd.common && !!state.sd.common.userInfo && !!state.sd.common.userInfo.default ) { var dft = state.sd.common.userInfo.default info.id = dft.id info.account = dft.account info.name = dft.name return info } else return undefined } return undefined }, _uploadCompentInfo: function (serverinfo) { var userinfo = wpsobj.slCtl.getUserInfo() if (userinfo === undefined) return var data = { userId: userinfo.id, userAccount: userinfo.account, userName: userinfo.name, updateDate: Date.now(), //当前日期的毫秒值 controlType: 'wps加载项', // browsername: navigator.userAgent, // equipmentName: serverinfo.HostName, indidocxVersion: serverinfo.version, //inididoc版本 } var ajax = createXHR() ajax.open('POST', wpsobj.slCtl.uploadCompentInfoUrl) ajax.onreadystatechange = function () { if (ajax.readyState == 4 && ajax.status == 200) { console.log('上传组件信息成功') } } ajax.setRequestHeader('Cache-Control', 'no-cache') ajax.setRequestHeader('Content-type', 'application/json;charset=utf-8') ajax.setRequestHeader('Authorization', userinfo.access_token) ajax.send(JSON.stringify(data)) }, _download:function(url,fname){ return new Promise(function(resolve,reject){ var ajax = createXHR(); ajax.onload=function(){ if(ajax.status == 200) resolve(ajax.response); else reject() }; ajax.onerror=function(){ reject() } ajax.responseType = "blob"; var userinfo=wpsobj.slCtl.getUserInfo()||{}; ajax.open('GET',url); ajax.setRequestHeader('Authorization', userinfo.access_token) ajax.send(); }).then(function(data){ if ('msSaveOrOpenBlob' in window.navigator) { // 兼容IE window.navigator.msSaveOrOpenBlob(data, fname) return } const blobUrl = URL.createObjectURL(data) const a = document.createElement('a') a.href = blobUrl a.download = fname // 不用a.click()因为52的firefox不允许 var evt = document.createEvent('MouseEvents') evt.initEvent('click', true, true) a.dispatchEvent(evt) URL.revokeObjectURL(blobUrl) }) }, Content: { Files: { FileList: [], _FileInfoString: [], }, Control: { //页面打印回调 _PrintDocumented: function (o) { }, _inithttpCompleted: function (o) { }, getFileByName: function (fname) { var userfile = null wpsobj.slCtl.Content.Files.FileList.map(function (onefile, index) { if (onefile.Unid == fname || onefile.FileName == fname) { userfile = onefile } }) return userfile }, getFileByUnid: function (fname) { return wpsobj.slCtl.Content.Control.getFileByName(fname) }, _getFileInfoByName: function (fname) { var usefileinfostring = null wpsobj.slCtl.Content.Files._FileInfoString.map(function (onefile, index) { if ( wpsobj.slCtl.getRef(onefile, 0, '', '') == fname || wpsobj.slCtl.htmldecode( wpsobj.slCtl.getRef(onefile, 0, '', '') ) == fname ) { usefileinfostring = onefile } }) return usefileinfostring }, //编辑 EditFile: function (fname, fileparam, argsobj) { wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) return wpsobj.slCtl.fnV6OpenFile(fname, fileparam) }, //清稿 QingGao: function (fname, fileparam, argsobj) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var promise = new Promise((resolve, reject) => { if (!wpsobj.slCtl.isSupport(fname)) { reject(wpsobj.slCtl.ErrorMessage.NotSupport) return } wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } registerEvent(userfile, resolve) _WpsInvoke( [ { QingGao: { uploadPath: wpsobj.slCtl.$$idx.httpserver.UploadUrl, // 保存文档上传路径 cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, uploadFieldName: 'file', fileparam: fileparam, userName: wpsobj.slCtl.$$idx.httpserver.UserName, trackFileName: wpsobj.slCtl.CreateTrackFileName(fname), action: 'qinggao', openType: { //文档打开方式 // 文档保护类型,-1:不启用保护模式,0:只允许对现有内容进行修订, // 1:只允许添加批注,2:只允许修改窗体域(禁止拷贝功能),3:只读 protectType: Number.parseInt(fileparam.Status), }, }, }, ], reject ) }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, //套打 TaoDa: function ( ModelUrl, ContentFieldName, fname, fileparam, OldDocName, values, taodainfo, argsobj ) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var promise = new Promise((resolve, reject) => { if (!wpsobj.slCtl.isSupport(fname)) { reject(wpsobj.slCtl.ErrorMessage.NotSupport) return } wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } else { var infoarr = usefileinfostring.split('') usefileinfostring = infoarr[0] + '' + taodainfo + '' + infoarr[1].split('')[1] //更新taodainfo for (var i = 0; i < wpsobj.slCtl.Content.Files._FileInfoString.length; i++) { if ( wpsobj.slCtl.getRef( wpsobj.slCtl.Content.Files._FileInfoString[i], 0, '', '' ) == fname || wpsobj.slCtl.getRef( wpsobj.slCtl.Content.Files._FileInfoString[i], 0, '', '' ) == fname ) { wpsobj.slCtl.Content.Files._FileInfoString.splice(i, 1, usefileinfostring) } } } registerEvent(userfile, resolve) _WpsInvoke( [ { TaoDa: { uploadPath: wpsobj.slCtl.$$idx.httpserver.UploadUrl, // 保存文档上传路径 cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, uploadFieldName: 'file', userName: wpsobj.slCtl.$$idx.httpserver.UserName, ModelUrl: ModelUrl, fileparam: fileparam, ContentFieldName: ContentFieldName, values: values, action: 'taoda', openType: { //文档打开方式 // 文档保护类型,-1:不启用保护模式,0:只允许对现有内容进行修订, // 1:只允许添加批注,2:只允许修改窗体域(禁止拷贝功能),3:只读 protectType: Number.parseInt(fileparam.Status), }, }, }, ], reject ) }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, //盖章 GaiZhang: function ( ModelUrl, ContentFieldName, fname, fileparam, OldDocName, values, argsobj ) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var promise = new Promise((resolve, reject) => { if (!wpsobj.slCtl.isSupport(fname)) { reject(wpsobj.slCtl.ErrorMessage.NotSupport) return } wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } registerEvent(userfile, resolve) _WpsInvoke( [ { GaiZhang: { uploadPath: wpsobj.slCtl.$$idx.httpserver.UploadUrl, // 保存文档上传路径 cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, uploadFieldName: 'file', userName: wpsobj.slCtl.$$idx.httpserver.UserName, ModelUrl: ModelUrl, fileparam: fileparam, ContentFieldName: ContentFieldName, action: 'gaizhang', openType: { //文档打开方式 // 文档保护类型,-1:不启用保护模式,0:只允许对现有内容进行修订, // 1:只允许添加批注,2:只允许修改窗体域(禁止拷贝功能),3:只读 protectType: Number.parseInt(fileparam.Status), }, }, }, ], reject ) }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, //更新正文 UpdateRegion: function (fname, values, picvalues, fileparam, argsobj) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var promise = new Promise((resolve, reject) => { if (!wpsobj.slCtl.isSupport(fname)) { reject(wpsobj.slCtl.ErrorMessage.NotSupport) return } wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } registerEvent(userfile, resolve) //if(!slCtl.isString(values)){ //values=values.join("|") // } _WpsInvoke( [ { UpdateRegion: { uploadPath: wpsobj.slCtl.$$idx.httpserver.UploadUrl, // 保存文档上传路径 cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, uploadFieldName: 'file', values: values, fileparam: fileparam, userName: wpsobj.slCtl.$$idx.httpserver.UserName, action: 'updateregion', openType: { //文档打开方式 // 文档保护类型,-1:不启用保护模式,0:只允许对现有内容进行修订, // 1:只允许添加批注,2:只允许修改窗体域(禁止拷贝功能),3:只读 protectType: Number.parseInt(fileparam.Status), }, }, }, ], reject ) }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, //文档打印 PrintDocument: function (fname, fileparam, values, argsobj) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var promise = new Promise((resolve, reject) => { wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } registerEvent(userfile, resolve) _WpsInvoke( [ { PrintDocument: { cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileparam: fileparam, values: values, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, uploadFieldName: 'file', userName: wpsobj.slCtl.$$idx.httpserver.UserName, action: 'printdocument', }, }, ], reject ) }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, //转换pdf DOCConvertToPDF: function (fname, fileparam, argsobj) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var promise = new Promise((resolve, reject) => { if (!wpsobj.slCtl.isSupport(fname)) { reject(wpsobj.slCtl.ErrorMessage.NotSupport) return } wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } fileparam.IsMaximization = false //启用静默 registerEvent(userfile, resolve) _WpsInvoke( [ { DOCConvertToPDF: { uploadPath: wpsobj.slCtl.$$idx.httpserver.UploadUrl, // 保存文档上传路径 cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileparam: fileparam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, uploadFieldName: 'file', userName: wpsobj.slCtl.$$idx.httpserver.UserName, action: 'convertpdf', }, }, ], reject ) }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, DOCConvertToOFD: function (fname, fileparam, argsobj) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var promise = new Promise((resolve, reject) => { if (!wpsobj.slCtl.isSupport(fname)) { reject(wpsobj.slCtl.ErrorMessage.NotSupport) return } wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } fileparam.IsMaximization = false //启用静默 registerEvent(userfile, resolve) _WpsInvoke( [ { DOCConvertToOFD: { uploadPath: wpsobj.slCtl.$$idx.httpserver.UploadUrl, // 保存文档上传路径 cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileparam: fileparam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, uploadFieldName: 'file', userName: wpsobj.slCtl.$$idx.httpserver.UserName, action: 'convertofd', }, }, ], reject ) }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, SaveFileToLocal: function (fname, fileparam, argsobj) { fileparam = wpsobj.slCtl.fileParamsNormalized(fileparam); var userfile = wpsobj.slCtl.Content.Control.getFileByName(fname) var promise = new Promise((resolve, reject) => { if (!wpsobj.slCtl.isSupport(fname)) { //reject(wpsobj.slCtl.ErrorMessage.NotSupport) wpsobj.slCtl._download(userfile.Link,fname).then(function(){ resolve() }).catch(_=>resolve()) }else{ wpsobj.slCtl.$$idx = wpsobj.slCtl.formatParams(argsobj) var usefileinfostring = wpsobj.slCtl.Content.Control._getFileInfoByName(fname) if (userfile == null) { userfile = {} userfile.Unid = fname usefileinfostring = fname userfile.Link = fileparam.FileServerUrl } var openType = { protectType: Number.parseInt(fileparam.Status) } //处理indidox兼容 if (fileparam.Status === 'qinggao') { openType.protectType = -1 fileparam.AutoAcceptRevisions = true } registerEvent(userfile, resolve) if ( wpsobj.slCtl.getFileType(fname).toLocaleLowerCase() == '.xls' || wpsobj.slCtl.getFileType(fname).toLocaleLowerCase() == '.xlsx' || wpsobj.slCtl.getFileType(fname).toLocaleLowerCase() == '.et' ) _WpsInvokeET( [{ SaveFileToLocal: { cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileparam: fileparam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, userName: wpsobj.slCtl.$$idx.httpserver.UserName, action: 'saveAs', openType, }, }] ) else _WpsInvoke( [ { SaveFileToLocal: { cookie: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.cookie.replace('Authorization=', '') ), refresh_token: wpsobj.slCtl.Base64.encode( wpsobj.slCtl.$$idx.httpserver.refresh_token ), uploadParam: wpsobj.slCtl.$$idx.httpserver.UploadParam, fileparam: fileparam, fileInfo: usefileinfostring.split('')[0], fileName: userfile.Link, userName: wpsobj.slCtl.$$idx.httpserver.UserName, action: 'saveAs', openType, }, }, ], reject ) } }).catch(function (reason) { wpsobj.slCtl.isFileOpen = false return Promise.reject(reason) }) return promise }, SaveMultiFiles: function (strFiles, fileparam, argsobj) { var opts = {}; argsobj.UploadParam.split('|').forEach(function(v){ var item = v.split('='); opts[item[0]]=item[1]; }); return new Promise((resolve, reject) => { var arrFileNames = strFiles.split('|'); var fileName = arrFileNames[0]; var codes =arrFileNames.map(v=>wpsobj.slCtl.Content.Control.getFileByName(v)).filter(Boolean); wpsobj.slCtl._download( `api/framework/v1/attachment-extend/attachments-download/multi?groupId=${ opts.groupId }&codes=${codes.map(x=>x.Unid)}`, `${fileName}等${codes.length}个附件.zip` ).then(_=>resolve()).catch(_=>resolve()); }) } }, }, getFileType: function (strFileName) { var arrtmp = strFileName.split('.') return '.' + arrtmp.pop().toLowerCase() }, isString: function (str) { return typeof str == 'string' && str.constructor == String }, Base64: { base64EncodeChars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', base64DecodeChars: new Array( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 ), base64encode: function (str) { var out, i, len var c1, c2, c3 len = str.length i = 0 out = '' while (i < len) { c1 = str.charCodeAt(i++) & 0xff if (i == len) { out += this.base64EncodeChars.charAt(c1 >> 2) out += this.base64EncodeChars.charAt((c1 & 0x3) << 4) out += '==' break } c2 = str.charCodeAt(i++) if (i == len) { out += this.base64EncodeChars.charAt(c1 >> 2) out += this.base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)) out += this.base64EncodeChars.charAt((c2 & 0xf) << 2) out += '=' break } c3 = str.charCodeAt(i++) out += this.base64EncodeChars.charAt(c1 >> 2) out += this.base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)) out += this.base64EncodeChars.charAt(((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6)) out += this.base64EncodeChars.charAt(c3 & 0x3f) } return out }, base64decode: function (str) { var c1, c2, c3, c4 var i, len, out len = str.length i = 0 out = '' while (i < len) { do { c1 = this.base64DecodeChars[str.charCodeAt(i++) & 0xff] } while (i < len && c1 == -1) if (c1 == -1) break do { c2 = this.base64DecodeChars[str.charCodeAt(i++) & 0xff] } while (i < len && c2 == -1) if (c2 == -1) break out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)) do { c3 = str.charCodeAt(i++) & 0xff if (c3 == 61) return out c3 = this.base64DecodeChars[c3] } while (i < len && c3 == -1) if (c3 == -1) break out += String.fromCharCode(((c2 & 0xf) << 4) | ((c3 & 0x3c) >> 2)) do { c4 = str.charCodeAt(i++) & 0xff if (c4 == 61) return out c4 = this.base64DecodeChars[c4] } while (i < len && c4 == -1) if (c4 == -1) break out += String.fromCharCode(((c3 & 0x03) << 6) | c4) } return out }, utf16to8: function (str) { var out, i, len, c out = '' len = str.length for (i = 0; i < len; i++) { c = str.charCodeAt(i) if (c >= 0x0001 && c <= 0x007f) { out += str.charAt(i) } else if (c > 0x07ff) { out += String.fromCharCode(0xe0 | ((c >> 12) & 0x0f)) out += String.fromCharCode(0x80 | ((c >> 6) & 0x3f)) out += String.fromCharCode(0x80 | ((c >> 0) & 0x3f)) } else { out += String.fromCharCode(0xc0 | ((c >> 6) & 0x1f)) out += String.fromCharCode(0x80 | ((c >> 0) & 0x3f)) } } return out }, utf8to16: function (str) { var out, i, len, c var char2, char3 out = '' len = str.length i = 0 while (i < len) { c = str.charCodeAt(i++) switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 0xxxxxxx out += str.charAt(i - 1) break case 12: case 13: // 110x xxxx 10xx xxxx char2 = str.charCodeAt(i++) out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f)) break case 14: // 1110 xxxx 10xx xxxx 10xx xxxx char2 = str.charCodeAt(i++) char3 = str.charCodeAt(i++) out += String.fromCharCode( ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0) ) break } } return out }, //end encode: function (input) { return this.base64encode(this.utf16to8(input)) }, decode: function (str) { return this.utf8to16(this.base64decode(str)) }, }, }, } var getEventName = function (fname) { return wpsobj.slCtl.forWindowID + '_' + fname } /** * 只有操作文件的时候才会注册心跳 * @param {*} userfile * @param {*} resolve */ var registerEvent = function (userfile, resolve) { window.curPromise[getEventName(userfile.FileName || userfile.Unid)] = resolve var extend = userfile.Type || '.' + userfile.Unid.match(/\.(?\w*)$/i).groups.ext var clientType = ['.xls', '.xlsx', '.et'].indexOf(extend.toLocaleLowerCase()) > -1 ? WpsInvoke.ClientType.et : WpsInvoke.ClientType.wps // RegisterHeart(clientType, { uuid: userfile.Unid, name: userfile.FileName }) // delayHeart() } var triggerEvent = function (msg, value) { var func = window.curPromise[getEventName(msg)] if (!!func) func(value === undefined ? true : value) else console.warn('not found handler ' + getEventName(msg)) } var handleEvent = function (message) { var reg = /^{.*}$/; if (reg.test(message)) { var data = JSON.parse(message) if (data.cmd == '$reconnect') { RegisterHeart(data.type, { uuid: data.uuid, name: data.name }) heart(true) //强制启动心跳 } else if (data.cmd == '$disconnect') { logoutHeart(data.type, { uuid: data.uuid, name: data.name }) triggerEvent(data.name) } else { triggerEvent(data.name, reg.test(data.msg) ? JSON.parse(data.msg) : data.msg); } } else { triggerEvent(message) } } var startNotice = function () { if (!!window.$$__wpsNotice) return window.$$__wpsNotice = true WpsInvoke.RegWebNotify(WpsInvoke.ClientType.wps, 'IndiDocX', handleEvent) WpsInvoke.RegWebNotify(WpsInvoke.ClientType.et, 'IndiDocXET', handleEvent) startHeart() } return wpsobj }, } /* ******************* * * 心跳 功能 * ******************* */ var bUseHttps = false var heartTimeout = 2e3 //2秒 var heart_active_key = 'heart_active' var heart_active_clientid = 'heart_active_clientid' var heart_time_handler = null var heart_delay = false /** * 注册心跳检查 * @param {*} clientType * @param {number} active 0为不激活,大于0为激活 默认值为1 */ function RegisterHeart(clientType, info) { // var instancekey = `${window.forWindowID}_${clientType}` var instancekey = clientType var cfg = JSON.parse(sessionStorage.getItem(heart_active_key) || '{}') var obj = cfg[instancekey] || {} obj[info.uuid] = info cfg[instancekey] = obj sessionStorage.setItem(heart_active_key, JSON.stringify(cfg)) // 这里为了是立即设定心跳,但是这个动作可以做到wps加载项中,有通讯加标识已经激活 // if (active > 0) { // //新注册事件,立即激活心跳 // clearTimeout(heart_time_handler) // heart() // } } function logoutHeart(clientType, info) { delayHeart(2e3) // var instancekey = `${window.forWindowID}_${clientType}` var instancekey = clientType var cfg = JSON.parse(sessionStorage.getItem(heart_active_key) || '{}') var obj = cfg[instancekey] || {} delete obj[info.uuid] if (Object.keys(obj).length > 0) { cfg[instancekey] = obj } else { delete cfg[instancekey] } sessionStorage.setItem(heart_active_key, JSON.stringify(cfg)) } function delayHeart(time) { heart_delay = true if (heart_time_handler) { clearTimeout(heart_time_handler) heart_time_handler = setTimeout(heart, time || heartTimeout * 3) heart_delay = false } } /** * 启动心跳 * */ function startHeart() { //确保每个window只有一个心跳不管多少个控件 if (!!window.$$heartid) { return } else { window.$$heartid = CreateRandomId() } window.addEventListener('unload', function () { var val = localStorage.getItem(heart_active_clientid) if (val && window.$$heartid === val) { localStorage.removeItem(heart_active_clientid) } //清理心跳项目 // var cfg = JSON.parse(localStorage.getItem(heart_active_key) || '{}') // delete cfg[`${window.forWindowID}_${WpsInvoke.ClientType.wps}`] // delete cfg[`${window.forWindowID}_${WpsInvoke.ClientType.et}`] // console.log(cfg) // localStorage.setItem(heart_active_key, JSON.stringify(cfg)) }) localStorage.removeItem(heart_active_clientid) heart() } /** * 心跳 * 1.强制启动出现在第一次加载组件,用于重连客户端; * 2.但是由于wps客户端通信的时候不支持静默模式, * 所以改变思路,加载项检测到过期之后主动请求重连 * @param {boolean} force 默认false */ function heart(force = false) { if (force && !!heart_time_handler) { //强制启动会取消掉之前的循环 clearTimeout(heart_time_handler) } var val = localStorage.getItem(heart_active_clientid) || window.$$heartid //确保这个浏览器只有一个心跳链接 if (window.$$heartid === val) { localStorage.setItem(heart_active_clientid, val) //默认唤醒 var cfg = JSON.parse(sessionStorage.getItem(heart_active_key) || '{}') var wps = Object.keys(cfg).some((x) => x.endsWith(WpsInvoke.ClientType.wps)) var table = Object.keys(cfg).some((x) => x.endsWith(WpsInvoke.ClientType.et)) if (wps && !heart_delay) heart_invoke(WpsInvoke.ClientType.wps, 'IndiDocX') if (table && !heart_delay) heart_invoke(WpsInvoke.ClientType.et, 'IndiDocXET') } heart_time_handler = setTimeout(heart, heartTimeout) } function heart_invoke(clientType, pluginName) { var func = bUseHttps ? WpsInvoke.InvokeAsHttps : WpsInvoke.InvokeAsHttp func( clientType, // 组件类型 pluginName, // 插件名,与wps客户端加载的加载的插件名对应 'heart', // 插件方法入口,与wps客户端加载的加载的插件代码对应,详细见插件代码 null, function (result) { //这里是同步请求 // if (result.status === 0 && /^{.*}/i.test(result.response)) { // var docs = JSON.parse(result.response).docs // var count = docs.length // RegisterHeart(clientType, count, true) // } }, false, null, false, 2e3, null, 1 ) } 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对象') } } /** * 获取随机字符串 * @returns 随机ID字符串 */ function CreateRandomId() { return Number( Math.random() .toString() .substr(3, 3) + Date.now() ).toString(36) } /** * 此方法是根据wps_sdk.js做的调用方法封装 * 可参照此定义 * @param {*} funcs 这是在WPS加载项内部定义的方法,采用JSON格式(先方法名,再参数) */ function _WpsInvoke(funcs, reject) { var silentmode = IsSilentMode(funcs) console.log('silentmode:' + silentmode + ':' + typeof (silentmode)) var info = { funcs: funcs } var func = bUseHttps ? WpsInvoke.InvokeAsHttps : WpsInvoke.InvokeAsHttp func( WpsInvoke.ClientType.wps, // 组件类型 'IndiDocX', // 插件名,与wps客户端加载的加载的插件名对应 'dispatcher', // 插件方法入口,与wps客户端加载的加载的插件代码对应,详细见插件代码 info, // 传递给插件的数据 function (result) { // 调用回调,status为0为成功,其他是错误 if (result.status) { reject(result.message || result.response) if (bUseHttps && result.status == 100) { WpsInvoke.AuthHttpesCert('请在稍后打开的网页中,点击"高级" => "继续前往",完成授权。') return } alert(result.message) } else { console.log(result.response) !silentmode && funcs.length > 0 && _WpsInvoke([]) //麒麟系统弹出wps问题修复 } }, !silentmode, undefined, silentmode, 1e4, //10秒 null, 4 ) } function _WpsInvokeET(funcs, reject) { var info = {} info.funcs = funcs var func = bUseHttps ? WpsInvoke.InvokeAsHttps : WpsInvoke.InvokeAsHttp func( WpsInvoke.ClientType.et, // 组件类型 'IndiDocXET', // 插件名,与wps客户端加载的加载的插件名对应 'dispatcher', // 插件方法入口,与wps客户端加载的加载的插件代码对应,详细见插件代码 info, // 传递给插件的数据 function (result) { // 调用回调,status为0为成功,其他是错误 if (result.status) { reject(result.message || result.response) if (bUseHttps && result.status == 100) { WpsInvoke.AuthHttpesCert('请在稍后打开的网页中,点击"高级" => "继续前往",完成授权。') return } // alert(result.message) } else { if (result.response) { console.log(result.response) } } } ) } function _WpsInvokeExtends(enter, params, callback, silentmode, tiemout) { var func = bUseHttps ? WpsInvoke.InvokeAsHttps : WpsInvoke.InvokeAsHttp func( WpsInvoke.ClientType.wps, // 组件类型 'IndiDocX', // 插件名,与wps客户端加载的加载的插件名对应 enter, // 插件方法入口,与wps客户端加载的加载的插件代码对应,详细见插件代码 params, // 传递给插件的数据 callback, !silentmode, undefined, silentmode, tiemout || 1e5 //10秒 ) } /** * 判断是否使用静默启动 * @param {Array}} info */ function IsSilentMode(funcs) { for (const iterator of funcs) { for (const key in iterator) { if (Object.hasOwnProperty.call(iterator, key)) { const item = iterator[key] if (item.fileparam.IsMaximization == false) return true } } } return false } function getBoolean(str, defaultValue) { console.log('get str:' + str + ':' + typeof (str)); if (typeof str === 'string') return str.toLocaleLowerCase() === 'true' else if (typeof str === 'boolean') return str else if (typeof str === 'number') return !!str else if (str === undefined) return defaultValue else return !!str } /** * 处理WPS加载项的方法返回值 * * @param {*} resultData */ function showresult(resultData) { var json = eval('(' + resultData + ')') switch (json.message) { case 'GetDocStatus': { var docstatus = json.docstatus if (typeof docstatus != 'undefined') { var str = '文档保存状态:' + docstatus.saved + '\n文档字数:' + docstatus.words + '\n文档页数:' + docstatus.pages alert(str) } } } } /** * 这是页面中针对代码显示的变量定义,开发者无需关心 */ var _wps = {} /** * 检查操作系统 * * @returns Win10 | Win7 | WinVista | Win2003 | WinXP | Win2000 | Linux | Unix | Mac */ function detectOS() { var sUserAgent = navigator.userAgent var isWin = navigator.platform == 'Win32' || navigator.platform == 'Windows' var isMac = navigator.platform == 'Mac68K' || navigator.platform == 'MacPPC' || navigator.platform == 'Macintosh' || navigator.platform == 'MacIntel' if (isMac) return 'Mac' var isUnix = navigator.platform == 'X11' && !isWin && !isMac if (isUnix) return 'Unix' var isLinux = String(navigator.platform).indexOf('Linux') > -1 if (isLinux) return 'Linux' if (isWin) { var isWin2K = sUserAgent.indexOf('Windows NT 5.0') > -1 || sUserAgent.indexOf('Windows 2000') > -1 if (isWin2K) return 'Win2000' var isWinXP = sUserAgent.indexOf('Windows NT 5.1') > -1 || sUserAgent.indexOf('Windows XP') > -1 if (isWinXP) return 'WinXP' var isWin2003 = sUserAgent.indexOf('Windows NT 5.2') > -1 || sUserAgent.indexOf('Windows 2003') > -1 if (isWin2003) return 'Win2003' var isWinVista = sUserAgent.indexOf('Windows NT 6.0') > -1 || sUserAgent.indexOf('Windows Vista') > -1 if (isWinVista) return 'WinVista' var isWin7 = sUserAgent.indexOf('Windows NT 6.1') > -1 || sUserAgent.indexOf('Windows 7') > -1 if (isWin7) return 'Win7' var isWin10 = sUserAgent.indexOf('Windows NT 6.1') > -1 || sUserAgent.indexOf('Windows 10') > -1 if (isWin10) return 'Win10' } return 'other' } window.curPromise = {} /** * 这是浏览器与WPS通信的SDK,是WPS提供的SDK * 无需修改 * 直接引用到业务系统前端调用即可 * 可覆盖如下使用场景: * 1. 通过浏览器中的页面直接启动WPS * 2. 浏览器与WPS双向通信,WPS发消息,浏览器前端页面可接受并解析 */ ; (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 /** * 兼容IE低版本的创建httpobj对象的方法 * @returns httpobj,可用于进行数据传输的http的对象 */ 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对象的方法 /** * 兼容IE低版本的创建xmlhttprequest对象的方法 * @returns xmlhttprequest对象,兼容低版本IE */ 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对象') } } /** * 加载项本地服务返回的错误信息,统一为data : message的json格式 * 如果有新增错误信息,添加到下面 * 也可以通过请求状态码返回错误信息 */ var errorMsg = [ '{"data": "Failed to send message to WPS."}', '{"data": "Json parse failed."}', '{"error": "Json parse failed."}', ] /** * 通过该接口给服务器发请求 * @param {*} options 参数对象,具体包含的参数如下: * @param {*} url 网页路径,传输地址 * @param {*} type 传输类型,POST / GET / PUT * @param {*} sendData 传输的数据 * @param {*} callback 回调函数 * @param {*} tryCount 请求失败后的尝试次数 * @param {*} bPop 是否弹出浏览器提示对话框 * @param {*} timeout 请求等待响应的时间,超过时间请求实效 * @param {*} concurrent 请求是否同步发送 * @param {*} wpsclient wpsclient对象 * @returns NULL */ function startWps(options) { if (!bFinished && !options.concurrent) { if (options.callback) options.callback({ status: 1, message: '上一次请求没有完成', }) return } if (!options.concurrent) bFinished = false else options.bFinished = false function startWpsInnder(tryCount) { if (tryCount <= 0) { if (!options.concurrent) { if (bFinished) return bFinished = true } else { if (options.bFinished) { return } options.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) { var responseStr = IEVersion() < 10 ? xmlReq.responseText : res.target.response var respStatus = IEVersion() < 10 ? xmlReq.status : res.target.status if (!options.concurrent) bFinished = true else options.bFinished = true if (options.callback) { if (respStatus != 200 || errorMsg.indexOf(responseStr) != -1) { var errorMessage = JSON.parse(responseStr) options.callback({ status: 1, message: errorMessage.data, }) if ( errorMessage.data == 'Subserver not available.' && tryCount == options.tryCount && options.bPop ) { InitWpsCloudSvr() setTimeout(function () { startWpsInnder(tryCount - 1) }, 3000) } } else { options.callback({ status: 0, response: responseStr, }) } } } xmlReq.ontimeout = xmlReq.onerror = function (res) { xmlReq.bTimeout = true if (tryCount == options.tryCount && options.bPop) { //打开wps并传参 InitWpsCloudSvr() } 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 } if (typeof window.atob !== 'function') window.atob = func_atob function func_atob(input) { output = input.replace(/[\s\S]{1,4}/g, cb_decode) return output } function cb_decode(cccc) { var len = cccc.length, padlen = len % 4, n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) | (len > 3 ? b64tab[cccc.charAt(3)] : 0), chars = [fromCharCode(n >>> 16), fromCharCode((n >>> 8) & 0xff), fromCharCode(n & 0xff)] chars.length -= [0, 0, 2, 1][padlen] return chars.join('') } function btou(b) { return b.replace(re_btou, cb_btou) } // decoder stuff var re_btou = new RegExp( ['[\xC0-\xDF][\x80-\xBF]', '[\xE0-\xEF][\x80-\xBF]{2}', '[\xF0-\xF7][\x80-\xBF]{3}'].join('|'), 'g' ) function cb_btou(cccc) { switch (cccc.length) { case 4: var cp = ((0x07 & cccc.charCodeAt(0)) << 18) | ((0x3f & cccc.charCodeAt(1)) << 12) | ((0x3f & cccc.charCodeAt(2)) << 6) | (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000 return fromCharCode((offset >>> 10) + 0xd800) + fromCharCode((offset & 0x3ff) + 0xdc00) case 3: return fromCharCode( ((0x0f & cccc.charCodeAt(0)) << 12) | ((0x3f & cccc.charCodeAt(1)) << 6) | (0x3f & cccc.charCodeAt(2)) ) default: return fromCharCode(((0x1f & cccc.charCodeAt(0)) << 6) | (0x3f & cccc.charCodeAt(1))) } } /** * 将字符串进行Base64编码 * @param {*} u 需要编码的数据 * @param {*} urisafe 返回值,编码后的数据 * @returns urisafe */ var encode = function (u, urisafe) { return !urisafe ? _encode(u) : _encode(String(u)) .replace(/[+\/]/g, function (m0) { return m0 == '+' ? '-' : '_' }) .replace(/=/g, '') } var decode = function (u) { return btou(atob(String(u))) } /** * 获取IE浏览器版本 * @returns IE浏览器版本 */ 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浏览器 } } /** * 启动wps客户端,加载项执行操作,无返回值 * @param {*} options 参数对象,详情见下: * @param {*} clientType 加载项类型, wps / wpp / et * @param {*} name 加载项名称 * @param {*} func 客户端加载项要执行的方法 * @param {*} param 客户端家乡执行方法的参数 * @param {*} urlBase 网页路径前缀 * @param {*} callback 回调函数 * @param {*} tryCount 请求失败后的尝试次数 * @param {*} bPop 是否弹出浏览器提示对话框 * @param {*} wpsclient wpsclient对象 */ 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, wpsclient: options.wpsclient, }) } /** * 服务端版本为空时,通过该接口启动wps * @param {*} options 参数对象,详情见下: * @param {*} clientType 加载项类型, wps / wpp / et * @param {*} name 加载项名称 * @param {*} func 客户端加载项要执行的方法 * @param {*} param 客户端家乡执行方法的参数 * @param {*} urlBase 网页路径前缀 * @param {*} callback 回调函数 * @param {*} wpsclient wpsclient对象 * @param {*} concurrent 请求是否同步发送 */ 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 是否弹出浏览器提示对话框 */ function WpsStartWrapExInner(options) { var infocontent = options.param.param var cmdId = guid() if (!options.wpsclient || options.wpsclient.single) { infocontent = JSON.stringify(options.param.param) var rspUrl = options.urlBase + '/transferEcho/runParams' 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 || options.wpsclient.single) { var url = options.urlBase + '/transfer/runParams' var data = 'ksowebstartup' + options.clientType + '://' + baseData wrapper = { id: cmdId, app: options.clientType, data: data, serverId: serverId, mode: options.silentMode ? true : false, } } else { var url = options.urlBase + '/transferEx/runParams' wrapper = { id: options.wpsclient.clientId, app: options.clientType, data: baseData, mode: options.wpsclient.silentMode ? 'true' : 'false', serverId: serverId, } } wrapper = JSON.stringify(wrapper) startWps({ url: url, sendData: wrapper, callback: options.callback, tryCount: options.tryCount, bPop: options.bPop, timeout: 0, concurrent: options.concurrent, wpsclient: options.wpsclient, }) } var serverVersion = 'wait' /** * 获取服务端版本号的接口 * @param {*} options 参数对象,详情见下: * @param {*} clientType 加载项类型, wps / wpp / et * @param {*} name 加载项名称 * @param {*} func 客户端加载项要执行的方法 * @param {*} param 客户端家乡执行方法的参数 * @param {*} urlBase 网页路径前缀 * @param {*} callback 回调函数 * @param {*} wpsclient wpsclient对象 * @param {*} concurrent 请求是否同步发送 */ function WpsStartWrapVersionInner(options) { if (serverVersion == 'wait') { if (g_isSdkInited == true) { InitWpsCloudSvr() } startWps({ url: options.urlBase + '/version', sendData: JSON.stringify({ serverId: serverId }), callback: function (res) { if (res.status !== 0) { options.callback(res) return } serverVersion = res.response options.tryCount = 1 options.bPop = false if (serverVersion === '') { WpsStart(options) } else if (serverVersion < '1.0.1' && options.wpsclient) { options.wpsclient.single = true WpsStartWrapExInner(options) } else { WpsStartWrapExInner(options) } }, tryCount: 4, bPop: !g_isSdkInited, timeout: 5000, concurrent: options.concurrent, }) } else { options.tryCount = 4 options.bPop = true if (serverVersion === '') { WpsStartWrap(options) } else if (serverVersion < '1.0.1' && options.wpsclient) { options.wpsclient.single = true WpsStartWrapExInner(options) } else { WpsStartWrapExInner(options) } } } var HeartBeatCode = 'function getHttpObj() {\n' + ' var httpobj = null;\n' + ' if (IEVersion() < 10) {\n' + ' try {\n' + ' httpobj = new XDomainRequest();\n' + ' } catch (e1) {\n' + ' httpobj = new createXHR();\n' + ' }\n' + ' } else {\n' + ' httpobj = new createXHR();\n' + ' }\n' + ' return httpobj;\n' + ' }\n' + ' \n' + ' function createXHR() {\n' + " if (typeof XMLHttpRequest != 'undefined') {\n" + ' return new XMLHttpRequest();\n' + " } else if (typeof ActiveXObject != 'undefined') {\n" + ' var versions = [\n' + " 'MSXML2.XMLHttp.6.0',\n" + " 'MSXML2.XMLHttp.3.0',\n" + " 'MSXML2.XMLHttp'\n" + ' ];\n' + ' \n' + ' for (var i = 0; i < versions.length; i++) {\n' + ' try {\n' + ' return new ActiveXObject(versions[i]);\n' + ' } catch (e) {\n' + ' \n' + ' }\n' + ' }\n' + ' } else {\n' + " throw new Error('您的浏览器不支持XHR对象');\n" + ' }\n' + ' }\n' + ' \n' + ' function IEVersion() {\n' + ' var userAgent = navigator.userAgent; \n' + " var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1;\n" + " var isEdge = userAgent.indexOf('Edge') > -1 && !isIE; \n" + " var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;\n" + ' if (isIE) {\n' + " var reIE = new RegExp('MSIE (\\d+\\.\\d+);');\n" + ' reIE.test(userAgent);\n' + " var fIEVersion = parseFloat(RegExp['$1']);\n" + ' if (fIEVersion == 7) {\n' + ' return 7;\n' + ' } else if (fIEVersion == 8) {\n' + ' return 8;\n' + ' } else if (fIEVersion == 9) {\n' + ' return 9;\n' + ' } else if (fIEVersion == 10) {\n' + ' return 10;\n' + ' } else {\n' + ' return 6; \n' + ' }\n' + ' } else if (isEdge) {\n' + ' return 20; \n' + ' } else if (isIE11) {\n' + ' return 11; \n' + ' } else {\n' + ' return 30; \n' + ' }\n' + ' }\n' + ' var heartBeatStart = false;\n' + ' function checkLastRegTime() {\n' + ' var now = new Date().valueOf();\n' + ' var TimeGap = now - LastRegTime;\n' + ' if (TimeGap > 5000 && !heartBeatStart) {\n' + ' HeartBeat();\n' + ' heartBeatStart = true;\n' + ' }\n' + ' }\n' + ' \n' + ' function HeartBeat() {\n' + ' var heartBeatItem = function () {\n' + ' var xhr = getHttpObj();\n' + ' xhr.onload = function (e) {\n' + ' self.setTimeout(heartBeatItem, 5000);\n' + ' }\n' + ' xhr.onerror = function (e) {\n' + ' self.setTimeout(heartBeatItem, 5000);\n' + ' }\n' + ' xhr.ontimeout = function (e) {\n' + ' self.setTimeout(heartBeatItem, 5000);\n' + ' }\n' + " xhr.open('POST', 'http://127.0.0.1:58890/askwebnotify', true);\n" + ' xhr.timeout = 2000;\n' + ' xhr.send(JSON.stringify(paramStr));\n' + ' }\n' + ' heartBeatItem();\n' + ' }\n' + ' \n' + ' var paramStr;\n' + ' var startCheck = false;\n' + " self.addEventListener('message', function (event) {\n" + ' var data = event.data;\n' + ' paramStr = data.param\n' + ' paramStr.heartBeat = true\n' + ' LastRegTime = data.LastRegTime;\n' + ' if (!startCheck) {\n' + ' startCheck = true;\n' + ' self.setInterval(checkLastRegTime, 5000)\n' + ' }\n' + ' }, false);\n' /** * 生成guid的接口 * @returns guid */ function guid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8 return v.toString(16) }) } /** * 开启多用户的接口 */ var serverId = undefined function EnableMultiUser() { serverId = getServerId() InitSdk(true) } /** * 自定义协议启动服务端 * 默认不带参数serverId,linux未升级之前不要使用多用户 */ function InitWpsCloudSvr() { if (serverId == undefined) window.location.href = 'ksoWPSCloudSvr://start=RelayHttpServer' //是否启动wps弹框 else window.location.href = 'ksoWPSCloudSvr://start=RelayHttpServer' + '&serverId=' + serverId //是否启动wps弹框 } /** * 获取serverId的接口 * @returns serverId */ function getServerId() { if (window.localStorage) { if (localStorage.getItem('serverId')) { // } else { localStorage.setItem('serverId', guid()) } return localStorage.getItem('serverId') } else { return guid() } } /** * 将字符串转成二进制,这里用来将字符串化后的js代码转成二进制文件 * @param {*} code * @returns js文件对象的url */ function codeToBlob(code) { var blob = new Blob([code], { type: 'text/javascript' }) // 生成js文件对象 var objectURL = window.URL.createObjectURL(blob) // 生成js文件的url return objectURL } var RegWebNotifyMap = { wps: {}, wpp: {}, et: {} } var bWebNotifyUseTimeout = true function WebNotifyUseTimeout(value) { bWebNotifyUseTimeout = value ? true : false } var g_businessId = Number( Math.random() .toString() .substr(3, 5) + Date.parse(new Date()) ).toString(36) var HeartBeatWorker if (window.Worker) { try { HeartBeatWorker = new Worker(codeToBlob(HeartBeatCode)) } catch (error) { // } } var g_LastRegTime /** * 注册一个前端页面接收WPS传来消息的方法 * @param {*} clientType wps | et | wpp * @param {*} name WPS加载项的名称 * @param {*} callback 回调函数 * @param {*} wpsclient wpsclient对象 */ 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, serverId: serverId, } if (HeartBeatWorker) paramStr.businessId = g_businessId } 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, serverId: serverId, } if (HeartBeatWorker) paramStr.businessId = g_businessId RegWebNotifyMap[clientType][name] = callback } var askItem = function () { var xhr = getHttpObj() xhr.onload = function (e) { if (xhr.responseText == 'WPSInnerMessage_quit' || xhr.status != 200) { if (!wpsclient || wpsclient.single) { window.setTimeout(askItem, 2000) } return } window.setTimeout(askItem, 300) try { if (!HeartBeatWorker) throw new Error() var resText = JSON.parse(xhr.responseText) paramStr.messageId = resText.msgId if (wpsclient) { if (resText.data != undefined && paramStr.messageId != undefined) if (typeof resText.data == 'object') // 如果发的数据是字符串化后的json对象,这里的resText.data就是一个json对象,可以输出自己想要的json数据 wpsclient.OnRegWebNotify(JSON.stringify(resText.data)) else wpsclient.OnRegWebNotify(resText.data) else wpsclient.OnRegWebNotify(xhr.responseText) } else { var func = RegWebNotifyMap[clientType][name] if (resText.data != undefined && paramStr.messageId != undefined) if (typeof resText.data == 'object') // 如果发的数据是字符串化后的json对象,这里的resText.data就是一个json对象,可以输出自己想要的json数据 func(JSON.stringify(resText.data)) else func(resText.data) else func(xhr.responseText) } } catch (e) { // 这里做一个容错,即使json解析失败,也要把msgId提取出来,发回给服务端,避免消息清不掉一直重复发送 // 同时把data也取出来,但是格式无法保证 var data var str = xhr.responseText var idx1 = str.indexOf('"msgId"') var idx2 var idx3 var idx4 var data if (idx1 != -1) { idx1 = idx1 + 8 idx2 = str.indexOf('"data"') - 2 paramStr.messageId = parseInt(str.substring(idx1, idx2)) idx3 = str.indexOf('"data"') + 7 idx4 = str.length - 1 data = str.substring(idx3, idx4) if (/^\".*\"$/.test(data)) { data = data.substring(1, data.length - 1) } } if (wpsclient) { if (paramStr.messageId !== undefined && data != undefined) wpsclient.OnRegWebNotify(data) else wpsclient.OnRegWebNotify(xhr.responseText) } else { var func = RegWebNotifyMap[clientType][name] if (paramStr.messageId !== undefined && data != undefined) func(data) else func(xhr.responseText) } } } 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 if (HeartBeatWorker) { g_LastRegTime = new Date().valueOf() var param = { param: { name: name, type: clientType, businessId: g_businessId, serverId: serverId, }, LastRegTime: g_LastRegTime, } HeartBeatWorker.postMessage(param) } xhr.send(JSON.stringify(paramStr)) } askItem() } /** * 获取网页路径前缀 * @returns url前缀 */ function GetUrlBase() { if (location.protocol == 'https:') return 'https://127.0.0.1:58891' return 'http://127.0.0.1:58890' } /** * 获取服务端版本号的接口,这里主要是初始化一些参数 * @param {*} clientType 加载项类型, wps / wpp / et * @param {*} name 加载项名称 * @param {*} func 客户端加载项要执行的方法 * @param {*} param 客户端加载项执行方法的参数 * @param {*} callback 回调函数 * @param {*} showToFront 设置客户端是否显示到前面 * @param {*} jsPluginsXml 设置加载项路径 * @param {*} silentMode 是否是静默启动 */ function WpsStartWrapVersion( clientType, name, func, param, callback, showToFront, jsPluginsXml, silentMode ) { 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, silentMode: silentMode, } WpsStartWrapVersionInner(options) } //从外部浏览器远程调用 WPS 加载项中的方法 var WpsInvoke = { InvokeAsHttp: WpsStartWrapVersion, InvokeAsHttps: WpsStartWrapVersion, RegWebNotify: RegWebNotify, ClientType: { wps: 'wps', et: 'et', wpp: 'wpp', }, CreateXHR: getHttpObj, IsClientRunning: IsClientRunning, } /** * @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 = true this.clientType = clientType /** * 内部函数,外部无需调用 * @param {*} options */ this.initWpsClient = function (options) { options.clientType = this.clientType options.wpsclient = this options.concurrent = this.concurrent 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,是options对象 if (res.status !== 0 || serverVersion < '1.0.1' || this.wpsclient.single == true) { if (callback) callback(res) if (serverVersion < '1.0.1' || this.wpsclient.single == true) RegWebNotify(clientType, name, this.wpsclient.onMessage) return } if (serverVersion < '1.0.3') { try { var resObject = JSON.parse(res.response) if (this.wpsclient.clientId == '') { this.wpsclient.clientId = resObject.clientId } if (typeof resObject.data == 'object') res.response = JSON.stringify(resObject.data) else res.response = resObject.data } catch (e) { var str = res.response var idx1 = str.indexOf('"clientId":"{') var idx2 var idx3 var idx4 if (idx1 != -1) { idx1 = idx1 + '"clientId":"{'.length - 1 idx2 = str.indexOf('"data":') - 3 if (this.wpsclient.clientId == '') { this.wpsclient.clientId = str.substring(idx1, idx2) } idx3 = str.indexOf('"data":') + '"data":'.length idx4 = str.length - 1 if (idx3 < idx4) res.response = str.substring(idx3, idx4) else res.response = '' } } } else { var resObject = JSON.parse(res.response) if (this.wpsclient.clientId == '') { this.wpsclient.clientId = resObject.clientId } res.response = decode(resObject.data) } if (IEVersion() < 10) eval(" res.response = '" + res.response + "';") if (callback) callback(res) this.wpsclient.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) } /** * 消息注册函数的回调函数 * @param {*} message 客户端发来的消息 */ 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,是options对象 if (res.status !== 0 || serverVersion < '1.0.1' || this.wpsclient.single == true) { if (callback) callback(res) if (serverVersion < '1.0.1' || this.wpsclient.single == true) RegWebNotify(clientType, name, this.wpsclient.onMessage) return } var jsonObj = JSON.parse(res.response) if (this.wpsclient.clientId == '') { this.wpsclient.clientId = jsonObj.clientId } if (serverVersion < '1.0.3') { res.response = JSON.stringify(jsonObj.data) } else { res.response = decode(jsonObj.data) } if (callback) { callback(res) } this.wpsclient.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.wpsclient.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) } } /** * 初始化sdk,用来减少在服务进程启动时自定义协议弹框出现的次数 */ var g_isSdkInited = false function InitSdk(bMultiUser) { g_isSdkInited = false var url = GetUrlBase() + '/version' startWps({ url: url, sendData: JSON.stringify({ serverId: serverId }), callback: function (res) { if ((!serverId && !bMultiUser) || bMultiUser) g_isSdkInited = true if (res.status !== 0 && res.message !== 'Subserver not available.') { serverVersion = 'wait' return } if (res.response && serverVersion == 'wait') serverVersion = res.response }, tryCount: 1, bPop: false, concurrent: true, timeout: 1000, }) } InitSdk(false) if (typeof noGlobal === 'undefined') { window.WpsInvoke = WpsInvoke window.WpsClient = WpsClient window.WebNotifyUseTimeout = WebNotifyUseTimeout window.EnableMultiUser = EnableMultiUser } /** * 当前客户端是否在运行,使用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, serverId: serverId, } wrapper = JSON.stringify(wrapper) startWps({ url: url, sendData: wrapper, callback: callback, tryCount: 1, bPop: false, timeout: 2000, concurrent: true, wpsclient: wpsclient, }) } /** * 获取publish.xml的内容 * @param {*} callBack 回调函数 */ function WpsAddonGetAllConfig(callBack) { var baseData = JSON.stringify({ serverId: serverId }) startWps({ url: GetUrlBase() + '/publishlist', type: 'POST', sendData: baseData, callback: callBack, tryCount: 3, bPop: true, timeout: 5000, concurrent: true, }) } /** * 检查ribbon.xml文件是否有效 * @param {*} element 参数对象 * @param {*} callBack 回调函数 */ 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('= '1.0.2' && serverId != undefined) { var base64Data = encode(strData) return JSON.stringify({ serverId: serverId, data: base64Data, }) } else { return encode(strData) } } //管理 WPS 加载项 var WpsAddonMgr = { getAllConfig: WpsAddonGetAllConfig, verifyStatus: WpsAddonVerifyStatus, enable: WpsAddonEnable, disable: WpsAddonDisable, disableall: WpsAddonDisableAll, } if (typeof noGlobal === 'undefined') { window.WpsAddonMgr = WpsAddonMgr } return { WpsInvoke: WpsInvoke, WpsAddonMgr: WpsAddonMgr, version: '1.0.31' } }) export default wpsModule