publish.html 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>加载项配置</title>
  6. <style>
  7. body {
  8. margin: 30px;
  9. }
  10. .addonList {
  11. /* max-width: 80%; */
  12. min-width: 1000px;
  13. flex-direction: column;
  14. padding: 18px;
  15. border-radius: 4px;
  16. border: 1px solid silver;
  17. }
  18. .addonItem {
  19. font-size: 16px;
  20. line-height: 36px;
  21. margin-bottom: 4px;
  22. border: 1px solid transparent;
  23. }
  24. .addonItem:hover {
  25. border-radius: 2px;
  26. border: 1px dashed silver;
  27. }
  28. .addonItemName1 {
  29. display: inline-block;
  30. width: 15%;
  31. text-align: left;
  32. vertical-align: middle;
  33. word-wrap: break-word;
  34. }
  35. .addonItemName2 {
  36. display: inline-block;
  37. width: 10%;
  38. vertical-align: middle;
  39. text-align: left;
  40. word-wrap: break-word;
  41. }
  42. .addonItemName3 {
  43. display: inline-block;
  44. width: 10%;
  45. vertical-align: middle;
  46. text-align: left;
  47. word-wrap: break-word;
  48. }
  49. .addonItemName4 {
  50. display: inline-block;
  51. width: 30%;
  52. text-align: left;
  53. vertical-align: middle;
  54. word-wrap: break-word;
  55. }
  56. .addonItemName5 {
  57. display: inline-block;
  58. width: 10%;
  59. text-align: left;
  60. vertical-align: middle;
  61. word-wrap: break-word;
  62. }
  63. .addonItemName6 {
  64. display: inline-block;
  65. width: 10%;
  66. text-align: left;
  67. vertical-align: middle;
  68. word-wrap: break-word;
  69. }
  70. .addonItemName7 {
  71. display: inline-block;
  72. width: 10%;
  73. text-align: left;
  74. vertical-align: middle;
  75. word-wrap: break-word;
  76. }
  77. .addonItemButton {
  78. padding: 4px 8px;
  79. background-color: #417ff9;
  80. display: inline-block;
  81. cursor: pointer;
  82. box-sizing: border-box;
  83. border-radius: 4px;
  84. text-align: center;
  85. color: #fff;
  86. line-height: 1.4;
  87. }
  88. .addonItemButton:hover {
  89. background-color: #5696ff;
  90. }
  91. .addonItemTitle {
  92. padding: 0px;
  93. border-width: 0 0 1px 0;
  94. border-bottom: 1px solid silver;
  95. }
  96. .addonItemTitle:hover {
  97. border-radius: 0px;
  98. border-width: 0 0 1px 0;
  99. }
  100. .ClearAll {
  101. /* max-width: 80%; */
  102. min-width: 1000px;
  103. margin-top: 20px;
  104. font-size: 16px;
  105. line-height: 36px;
  106. text-align: center;
  107. cursor: pointer;
  108. border: 1px dashed silver;
  109. padding: 0px 18px;
  110. }
  111. .ClearAll:hover {
  112. border-radius: 2px;
  113. background-color: silver;
  114. }
  115. .divTitle {
  116. font-size: 30px;
  117. font-weight: bolder;
  118. margin-bottom: 20px;
  119. }
  120. </style>
  121. <script>
  122. if (!String.prototype.startsWith) {
  123. Object.defineProperty(String.prototype, 'startsWith', {
  124. value: function (search, pos) {
  125. pos = !pos || pos < 0 ? 0 : +pos
  126. return this.substring(pos, pos + search.length) === search
  127. },
  128. })
  129. }
  130. var domain =
  131. location.protocol == 'http:'
  132. ? 'http://127.0.0.1:58890'
  133. : 'https://127.0.0.1:58891'
  134. </script>
  135. <script src="../share/version.js"></script>
  136. <script>
  137. function getHttpObj() {
  138. var httpobj = null
  139. if (IEVersion() < 10) {
  140. try {
  141. httpobj = new XDomainRequest()
  142. } catch (e1) {
  143. httpobj = new createXHR()
  144. }
  145. } else {
  146. httpobj = new createXHR()
  147. }
  148. return httpobj
  149. }
  150. //兼容IE低版本的创建xmlhttprequest对象的方法
  151. function createXHR() {
  152. if (typeof XMLHttpRequest != 'undefined') {
  153. //兼容高版本浏览器
  154. return new XMLHttpRequest()
  155. } else if (typeof ActiveXObject != 'undefined') {
  156. //IE6 采用 ActiveXObject, 兼容IE6
  157. var versions = [
  158. //由于MSXML库有3个版本,因此都要考虑
  159. 'MSXML2.XMLHttp.6.0',
  160. 'MSXML2.XMLHttp.3.0',
  161. 'MSXML2.XMLHttp',
  162. ]
  163. for (var i = 0; i < versions.length; i++) {
  164. try {
  165. return new ActiveXObject(versions[i])
  166. } catch (e) {
  167. //跳过
  168. }
  169. }
  170. } else {
  171. throw new Error('您的浏览器不支持XHR对象')
  172. }
  173. }
  174. var fromCharCode = String.fromCharCode
  175. // encoder stuff
  176. var cb_utob = function (c) {
  177. if (c.length < 2) {
  178. var cc = c.charCodeAt(0)
  179. return cc < 0x80
  180. ? c
  181. : cc < 0x800
  182. ? fromCharCode(0xc0 | (cc >>> 6)) + fromCharCode(0x80 | (cc & 0x3f))
  183. : fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) +
  184. fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) +
  185. fromCharCode(0x80 | (cc & 0x3f))
  186. } else {
  187. var cc =
  188. 0x10000 +
  189. (c.charCodeAt(0) - 0xd800) * 0x400 +
  190. (c.charCodeAt(1) - 0xdc00)
  191. return (
  192. fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) +
  193. fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) +
  194. fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) +
  195. fromCharCode(0x80 | (cc & 0x3f))
  196. )
  197. }
  198. }
  199. var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g
  200. var utob = function (u) {
  201. return u.replace(re_utob, cb_utob)
  202. }
  203. var _encode = function (u) {
  204. console.log(u)
  205. var isUint8Array =
  206. Object.prototype.toString.call(u) === '[object Uint8Array]'
  207. if (isUint8Array) return u.toString('base64')
  208. else return btoa(utob(String(u)))
  209. }
  210. if (typeof btoa !== 'function') btoa = func_btoa
  211. function func_btoa(input) {
  212. var str = String(input)
  213. var chars =
  214. 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
  215. for (
  216. // initialize result and counter
  217. var block, charCode, idx = 0, map = chars, output = '';
  218. // if the next str index does not exist:
  219. // change the mapping table to "="
  220. // check if d has no fractional digits
  221. str.charAt(idx | 0) || ((map = '='), idx % 1);
  222. // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
  223. output += map.charAt(63 & (block >> (8 - (idx % 1) * 8)))
  224. ) {
  225. charCode = str.charCodeAt((idx += 3 / 4))
  226. if (charCode > 0xff) {
  227. throw new InvalidCharacterError(
  228. "'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."
  229. )
  230. }
  231. block = (block << 8) | charCode
  232. }
  233. return output
  234. }
  235. function encode(u, urisafe) {
  236. return !urisafe
  237. ? _encode(u)
  238. : _encode(String(u))
  239. .replace(/[+\/]/g, function (m0) {
  240. return m0 == '+' ? '-' : '_'
  241. })
  242. .replace(/=/g, '')
  243. }
  244. function IEVersion() {
  245. var userAgent = navigator.userAgent //取得浏览器的userAgent字符串
  246. var isIE =
  247. userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1 //判断是否IE<11浏览器
  248. var isEdge = userAgent.indexOf('Edge') > -1 && !isIE //判断是否IE的Edge浏览器
  249. var isIE11 =
  250. userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1
  251. if (isIE) {
  252. var reIE = new RegExp('MSIE (\\d+\\.\\d+);')
  253. reIE.test(userAgent)
  254. var fIEVersion = parseFloat(RegExp['$1'])
  255. if (fIEVersion == 7) {
  256. return 7
  257. } else if (fIEVersion == 8) {
  258. return 8
  259. } else if (fIEVersion == 9) {
  260. return 9
  261. } else if (fIEVersion == 10) {
  262. return 10
  263. } else {
  264. return 6 //IE版本<=7
  265. }
  266. } else if (isEdge) {
  267. return 20 //edge
  268. } else if (isIE11) {
  269. return 11 //IE11
  270. } else {
  271. return 30 //不是ie浏览器
  272. }
  273. }
  274. function startWps(req, t, callback) {
  275. function startWpsInnder(reqInner, tryCount, bPop) {
  276. if (tryCount < 1) {
  277. if (callback)
  278. callback({
  279. status: 2,
  280. message: '请允许浏览器打开WPS Office',
  281. })
  282. return
  283. }
  284. var bRetry = true
  285. var xmlReq = getHttpObj()
  286. //WPS客户端提供的接收参数的本地服务,HTTP服务端口为58890,HTTPS服务端口为58891
  287. //这俩配置,取一即可,不可同时启用
  288. xmlReq.open(reqInner.type, reqInner.url)
  289. xmlReq.onload = function (res) {
  290. bFinished = true
  291. if (callback)
  292. callback({
  293. status: 0,
  294. res: res,
  295. })
  296. }
  297. xmlReq.ontimeout = xmlReq.onerror = function (res) {
  298. xmlReq.bTimeout = true
  299. if (bPop) {
  300. //打开wps并传参
  301. window.location.href = 'ksoWPSCloudSvr://start=RelayHttpServer' //是否启动wps弹框
  302. }
  303. setTimeout(function () {
  304. if (bRetry) {
  305. bRetry = false
  306. startWpsInnder(reqInner, --tryCount, false)
  307. }
  308. }, 1000)
  309. }
  310. if (IEVersion() < 10) {
  311. xmlReq.onreadystatechange = function () {
  312. if (xmlReq.readyState != 4) return
  313. if (xmlReq.bTimeout) {
  314. return
  315. }
  316. if (xmlReq.status === 200) xmlReq.onload()
  317. else xmlReq.onerror()
  318. }
  319. }
  320. xmlReq.timeout = 3000
  321. xmlReq.send(t)
  322. }
  323. startWpsInnder(req, 4, true)
  324. return
  325. }
  326. function CheckPlugin(element) {
  327. var id = GetAddonId(element)
  328. var ele = document.getElementById(id + '_status')
  329. // var xmlReq = getHttpObj()
  330. // var offline = element.online === 'false'
  331. // var url = offline ? element.url : element.url + 'ribbon.xml'
  332. // xmlReq.open('POST', domain + '/redirect/runParams')
  333. // xmlReq.onload = function (res) {
  334. if (element.enable == 'true' || element.enable == 'enable_dev') {
  335. ele.style.color = 'green'
  336. ele.style.textAlign = 'center'
  337. ele.style.backgroundColor = 'white'
  338. ele.innerHTML = '正常'
  339. } else {
  340. ele.style.color = 'white'
  341. ele.style.backgroundColor = 'gray'
  342. ele.style.textAlign = 'center'
  343. ele.innerHTML = '无效'
  344. // ele.title = offline
  345. // ? '不是有效的7z格式' + url
  346. // : '不是有效的ribbon.xml,' + url
  347. }
  348. return
  349. // }
  350. xmlReq.onerror = function (res) {
  351. xmlReq.bTimeout = true
  352. ele.style.color = 'white'
  353. ele.style.backgroundColor = 'gray'
  354. ele.style.textAlign = 'center'
  355. ele.innerHTML = '无效'
  356. ele.title = '网页路径不可访问,如果是跨域问题,不影响使用:' + url
  357. }
  358. xmlReq.ontimeout = function (res) {
  359. xmlReq.bTimeout = true
  360. ele.style.color = 'white'
  361. ele.style.backgroundColor = 'gray'
  362. ele.style.textAlign = 'center'
  363. ele.innerHTML = '异常'
  364. ele.title = '访问超时,' + url
  365. }
  366. if (IEVersion() < 10) {
  367. xmlReq.onreadystatechange = function () {
  368. if (xmlReq.readyState != 4) return
  369. if (xmlReq.bTimeout) {
  370. return
  371. }
  372. if (xmlReq.status === 200) xmlReq.onload()
  373. else xmlReq.onerror()
  374. }
  375. }
  376. xmlReq.timeout = 5000
  377. var data = {
  378. method: 'get',
  379. url: url,
  380. data: '',
  381. }
  382. var sendData = FormatSendData(data)
  383. xmlReq.send(sendData)
  384. }
  385. function GetAddonId(element) {
  386. return element.name + '/' + element.addonType
  387. }
  388. function UpdateElement(element, cmd) {
  389. if (typeof element.name === 'undefined') return
  390. var id = GetAddonId(element)
  391. var addonList = document.getElementById('addonList')
  392. //var param = JSON.stringify(element).replace(/"/g, "\'");
  393. var buttonLabel = cmd === 'enable' ? '安装' : '卸载'
  394. var des = '文字'
  395. if (element.addonType == 'et') des = '电子表格'
  396. else if (element.addonType == 'wpp') des = '演示'
  397. var loadType = '在线'
  398. if (element.online == 'false') loadType = '离线'
  399. var old = document.getElementById(id)
  400. if (old !== null) {
  401. var oldOnline = old.wpsaddon.online === 'false'
  402. var newOnline = element.online === 'false'
  403. if (
  404. cmd === 'disable' &&
  405. (oldOnline !== newOnline ||
  406. old.wpsaddon.url !== element.url ||
  407. (oldOnline && old.wpsaddon.version !== element.version))
  408. ) {
  409. buttonLabel = '更新/卸载'
  410. cmd = 'choose'
  411. }
  412. old.wpsaddoncmd = cmd
  413. document.getElementById(id + '_button').innerHTML = buttonLabel
  414. CheckPlugin(element)
  415. } else {
  416. var ele = document.createElement('div')
  417. ele.className = 'addonItem'
  418. ele.id = id
  419. ele.wpsaddon = element
  420. ele.wpsaddoncmd = cmd
  421. ele.innerHTML =
  422. '<div class="addonItemName1">' +
  423. element.name +
  424. '</div>\n' +
  425. '<div class="addonItemName2">' +
  426. des +
  427. '</div>\n' +
  428. '<div class="addonItemName3">' +
  429. loadType +
  430. '</div>\n' +
  431. '<div class="addonItemName4">' +
  432. element.url +
  433. '</div>\n' +
  434. '<div class="addonItemName5"><div class="addonItemButton" id="' +
  435. id +
  436. '_button' +
  437. '" onclick="WpsAddonHandle(\'' +
  438. id +
  439. '\')">' +
  440. buttonLabel +
  441. '</div></div>\n' +
  442. '<div class="addonItemName6" id="' +
  443. id +
  444. '_version' +
  445. '">' +
  446. element.version +
  447. '</div>\n' +
  448. '<div class="addonItemName7" id="' +
  449. id +
  450. '_status' +
  451. '">验证中...</div>\n'
  452. addonList.appendChild(ele)
  453. CheckPlugin(element)
  454. }
  455. }
  456. function WpsAddonHandle(id) {
  457. var ele = document.getElementById(id)
  458. var element = ele.wpsaddon
  459. var cmd = ele.wpsaddoncmd
  460. WpsAddonHandleEx(element, cmd)
  461. }
  462. function WpsAddonHandleEx(element, cmd, showalert) {
  463. if (cmd === 'choose') {
  464. if (confirm('点击确定将更新 WPS 加载项,或点击取消完成卸载')) {
  465. cmd = 'enable'
  466. } else {
  467. cmd = 'disable'
  468. }
  469. }
  470. var data = FormartData(element, cmd)
  471. var req = {
  472. url: domain + '/deployaddons/runParams',
  473. type: 'POST',
  474. }
  475. startWps(req, data, function (res) {
  476. if (res.status == 0) {
  477. if (cmd === 'disableall') {
  478. // window.location.reload()
  479. return
  480. } else {
  481. var newCmd = 'disable'
  482. if (cmd === 'disable') newCmd = 'enable'
  483. UpdateElement(element, newCmd)
  484. if (showalert === true)
  485. alert(cmd === 'disable' ? '卸载成功' : '安装成功')
  486. }
  487. // LoadLocalAddons()
  488. } else {
  489. alert(res.message)
  490. }
  491. })
  492. }
  493. function FormartData(element, cmd) {
  494. var data = {
  495. cmd: cmd, //"enable", 启用, "disable", 禁用, "disableall", 禁用所有
  496. name: element.name,
  497. url: element.url,
  498. addonType: element.addonType,
  499. online: element.online,
  500. version: element.version,
  501. }
  502. return FormatSendData(data)
  503. }
  504. function FormatSendData(data) {
  505. var strData = JSON.stringify(data)
  506. if (IEVersion() < 10)
  507. eval("strData = '" + JSON.stringify(strData) + "';")
  508. return encode(strData)
  509. }
  510. function LoadLocalAddons() {
  511. var baseData
  512. var req = { url: domain + '/publishlist', type: 'GET' }
  513. startWps(req, baseData, function (res) {
  514. if (res.status == 0) {
  515. var addonList = document.getElementById('addonList')
  516. var curList = JSON.parse(res.res.target.response)
  517. curList.forEach(function (element) {
  518. // if (element.enable === 'false') return
  519. UpdateElement(
  520. element,
  521. element.enable === 'false' ? 'enable' : 'disable'
  522. )
  523. })
  524. } else {
  525. alert(res.message)
  526. }
  527. })
  528. }
  529. function LoadPublishAddons() {
  530. var addonList = document.getElementById('addonList')
  531. var curList = [
  532. {
  533. name: 'IndiDocX',
  534. addonType: 'wps',
  535. online: 'true',
  536. url:
  537. window.location.origin +
  538. window.location.pathname.replace('publish.html', ''),
  539. version: GetCurrentVersion(),
  540. },
  541. {
  542. name: 'IndiDocXET',
  543. addonType: 'et',
  544. online: 'true',
  545. url:
  546. window.location.origin +
  547. window.location.pathname.replace(
  548. 'jsplugindir/publish.html',
  549. 'jsetplugindir/'
  550. ),
  551. version: GetCurrentVersion(),
  552. },
  553. ]
  554. curList.forEach(function (element) {
  555. var param = JSON.stringify(element).replace('"', "'")
  556. UpdateElement(element, 'enable')
  557. })
  558. }
  559. function LoadAddons() {
  560. var addonList = document.getElementById('addonList')
  561. // addonList.style.maxWidth = 800 * window.devicePixelRatio + 'px'
  562. var ClearAll = document.getElementById('ClearAll')
  563. // ClearAll.style.maxWidth = 800 * window.devicePixelRatio + 'px'
  564. LoadPublishAddons()
  565. // LoadLocalAddons()
  566. setInterval(() => {
  567. LoadLocalAddons()
  568. }, 1000)
  569. }
  570. function ClearAll() {
  571. if (confirm('确定要禁用所有WPS加载项吗?')) {
  572. var element = {}
  573. WpsAddonHandleEx(element, 'disableall')
  574. }
  575. }
  576. function InstallAll() {
  577. var addonList = document.querySelectorAll(
  578. '#addonList>.addonItem:not(:first-child)'
  579. )
  580. addonList.forEach(function (element) {
  581. WpsAddonHandleEx(element.wpsaddon, 'enable', false)
  582. })
  583. // alert('安装成功')
  584. }
  585. </script>
  586. </head>
  587. <body onload="LoadAddons()">
  588. <div class="divTitle">加载项配置</div>
  589. <div class="addonList" id="addonList">
  590. <div class="addonItem addonItemTitle">
  591. <div class="addonItemName1">加载项名称</div>
  592. <div class="addonItemName2">类型</div>
  593. <div class="addonItemName3">加载方式</div>
  594. <div class="addonItemName4">URL</div>
  595. <div class="addonItemName5">管理</div>
  596. <div class="addonItemName6">版本</div>
  597. <div class="addonItemName7">状态</div>
  598. </div>
  599. </div>
  600. <div class="ClearAll" onclick="InstallAll()" id="InstallAll">
  601. 一键安装加载项
  602. </div>
  603. <div class="ClearAll" onclick="ClearAll()" id="ClearAll">
  604. 一键禁用加载项
  605. </div>
  606. </body>
  607. </html>