diff --git a/code/modules/tgui/tgui_panel/tgui_panel_external.dm b/code/modules/tgui/tgui_panel/tgui_panel_external.dm index 74bdfa64b0a3..e3e5e3c62eca 100644 --- a/code/modules/tgui/tgui_panel/tgui_panel_external.dm +++ b/code/modules/tgui/tgui_panel/tgui_panel_external.dm @@ -19,21 +19,18 @@ // Failed to fix action = alert(src, "Did that work?", "", "Yes", "No, switch to old ui") if(action == "No, switch to old ui") - winset(src, "output", "on-show=&is-disabled=0&is-visible=1") - winset(src, "chat_panel", "is-disabled=1;is-visible=0") + winset(src, "legacy_output_selector", "left=output_legacy") log_tgui(src, "Failed to fix.") /client/proc/nuke_chat() // Catch all solution (kick the whole thing in the pants) - winset(src, "output", "on-show=&is-disabled=0&is-visible=1") - winset(src, "chat_panel", "is-disabled=1;is-visible=0") + winset(src, "legacy_output_selector", "left=output_legacy") if(!tgui_panel || !istype(tgui_panel)) log_tgui(src, "tgui_panel datum is missing") tgui_panel = new(src, "chat_panel") tgui_panel.initialize(force = TRUE) // Force show the panel to see if there are any errors - winset(src, "output", "is-disabled=1&is-visible=0") - winset(src, "chat_panel", "is-disabled=0;is-visible=1") + winset(src, "legacy_output_selector", "left=output_browser") if(byond_version >= 516) winset(src, null, "browser-options=byondstorage,find") diff --git a/interface/skin.dmf b/interface/skin.dmf index ebf2ead0b7da..e5a6501a7d01 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -294,7 +294,7 @@ window "rpane" window "outputwindow" elem "outputwindow" type = MAIN - pos = 281,0 + pos = 0,0 size = 640x480 anchor1 = -1,-1 anchor2 = -1,-1 @@ -346,15 +346,25 @@ window "outputwindow" command = ".winset \"mebutton.is-checked=true ? input.command=\"!me \\\"\" : input.command=\"\"mebutton.is-checked=true ? saybutton.is-checked=false\"\"mebutton.is-checked=true ? oocbutton.is-checked=false\"" is-flat = true button-type = pushbox - elem "chat_panel" - type = BROWSER + elem "legacy_output_selector" + type = CHILD pos = 0,0 size = 640x456 anchor1 = 0,0 anchor2 = 100,100 - is-visible = false - is-disabled = true - saved-params = "" + saved-params = "splitter" + left = "output_legacy" + is-vert = false +window "output_legacy" + elem "output_legacy" + type = MAIN + pos = 0,0 + size = 640x456 + anchor1 = -1,-1 + anchor2 = -1,-1 + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true elem "output" type = OUTPUT pos = 0,0 @@ -362,6 +372,25 @@ window "outputwindow" anchor1 = 0,0 anchor2 = 100,100 is-default = true + saved-params = "max-lines" + +window "output_browser" + elem "output_browser" + type = MAIN + pos = 0,0 + size = 640x456 + anchor1 = -1,-1 + anchor2 = -1,-1 + background-color = none + saved-params = "pos;size;is-minimized;is-maximized" + is-pane = true + elem "chat_panel" + type = BROWSER + pos = 0,0 + size = 640x456 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = none saved-params = "" window "infowindow" diff --git a/tgui/global.d.ts b/tgui/global.d.ts index 7161334c2a2a..225d1a9dd39c 100644 --- a/tgui/global.d.ts +++ b/tgui/global.d.ts @@ -143,6 +143,11 @@ type ByondType = { */ parseJson(text: string): any; + /** + * Downloads a blob, platform-agnostic + */ + saveBlob(blob: Blob, filename: string, ext: string): void; + /** * Sends a message to `/datum/tgui_window` which hosts this window instance. */ diff --git a/tgui/packages/tgui-panel/chat/renderer.js b/tgui/packages/tgui-panel/chat/renderer.js index deb0e802383f..103081d10978 100644 --- a/tgui/packages/tgui-panel/chat/renderer.js +++ b/tgui/packages/tgui-panel/chat/renderer.js @@ -548,9 +548,9 @@ class ChatRenderer { + '\n' + '\n'; // Create and send a nice blob - const blob = new Blob([pageHtml]); + const blob = new Blob([pageHtml], { type: 'text/plain' }); const timestamp = new Date().toISOString().substring(0, 19).replace(/[-:]/g, '').replace('T', '-'); - window.navigator.msSaveBlob(blob, `ss13-chatlog-${timestamp}.html`); + Byond.saveBlob(blob, `ss13-paradise-chatlog-${timestamp}.html`, '.html'); } } diff --git a/tgui/packages/tgui-panel/index.js b/tgui/packages/tgui-panel/index.js index 40a8597731fd..92dded04599c 100644 --- a/tgui/packages/tgui-panel/index.js +++ b/tgui/packages/tgui-panel/index.js @@ -70,18 +70,9 @@ const setupApp = () => { // Dispatch incoming messages as store actions Byond.subscribe((type, payload) => store.dispatch({ type, payload })); - // Hide output - Byond.winset('output', { - 'is-visible': false, - 'is-disabled': true, - }); - // Unhide the panel - Byond.winset('chat_panel', { - 'is-visible': true, - 'is-disabled': false, - 'pos': '0x0', - 'size': '0x0', + Byond.winset('legacy_output_selector', { + left: 'output_browser', }); // Resize the panel to match the non-browser output diff --git a/tgui/public/tgui-panel.bundle.js b/tgui/public/tgui-panel.bundle.js index a26b958cf544..e898e74640aa 100644 --- a/tgui/public/tgui-panel.bundle.js +++ b/tgui/public/tgui-panel.bundle.js @@ -134,7 +134,7 @@ * @file * @copyright 2020 Aleksej Komarov * @license MIT -*/var c=(0,a.createLogger)("chatRenderer"),g=24,v=["iframe","video"],h=function(A){for(var P=document.body,M=A;M&&M!==P;){if(M.scrollWidth=s.IMAGE_RETRY_LIMIT){c.error("failed to load an image after "+M+" attempts");return}var w=P.src;P.src=null,P.src=w+"#"+M,P.setAttribute("data-reload-n",M+1)},s.IMAGE_RETRY_DELAY)},C=function(A){var P=A.node,M=A.times;if(!(!P||!M)){var w=P.querySelector(".Chat__badge"),V=w||document.createElement("div");V.textContent=M,V.className="Chat__badge",w||P.appendChild(V)}},S=function(){function b(){var P=this;this.loaded=!1,this.rootNode=null,this.queue=[],this.messages=[],this.visibleMessages=[],this.page=null,this.events=new r.EventEmitter,this.scrollNode=null,this.scrollTracking=!0,this.handleScroll=function(M){var w=P.scrollNode,V=w.scrollHeight,U=w.scrollTop+w.offsetHeight,j=Math.abs(V-U)0&&(this.processBatch(this.queue),this.queue=[])}return P}(),A.assignStyle=function(){function P(M){M===void 0&&(M={});for(var w=0,V=Object.keys(M);w{}[\]:;'"|~`_\-\\/]/g,W=String(G).split(/[,|]/).map(function(it){return it.trim()}).filter(function(it){return it&&it.length>1&&H.test(it)&&((H.lastIndex=0)||!0)}),q,ut;if(W.length!==0){for(var ct=[],Q=f(W),X;!(X=Q()).done;){var at=X.value;if(at.charAt(0)==="/"&&at.charAt(at.length-1)==="/"){var ft=at.substring(1,at.length-1);if(/^(\[.*\]|\\.|.)$/.test(ft))continue;ct.push(ft)}else q||(q=[]),at=at.replace(K,"\\$&"),q.push(at)}var dt=ct.join("|"),_="g"+(F?"":"i");try{if(dt)ut=new RegExp("("+dt+")",_);else{var rt=(B?"\\b":"")+"("+q.join("|")+")"+(B?"\\b":"");ut=new RegExp(rt,_)}}catch(it){ut=null}V.highlightParsers||(V.highlightParsers=[]),V.highlightParsers.push({highlightWords:q,highlightRegex:ut,highlightColor:$,highlightWholeMessage:x})}})}return P}(),A.scrollToBottom=function(){function P(){this.scrollNode.scrollTop=this.scrollNode.scrollHeight}return P}(),A.changePage=function(){function P(M){if(!this.isReady()){this.page=M,this.tryFlushQueue();return}this.page=M,this.rootNode.textContent="",this.visibleMessages=[];for(var w=document.createDocumentFragment(),V,U=f(this.messages),j;!(j=U()).done;){var G=j.value;(0,u.canPageAcceptType)(M,G.type)&&(V=G.node,w.appendChild(V),this.visibleMessages.push(G))}V&&(this.rootNode.appendChild(w),V.scrollIntoView())}return P}(),A.getCombinableMessage=function(){function P(M,w,V,U){for(var j=V;j>=U;j--){var G=this.visibleMessages[j],$=!G.type.startsWith(s.MESSAGE_TYPE_INTERNAL)&&(0,u.isSameMessage)(G,M)&&w0){this.visibleMessages=M.slice(w);for(var V=0;V0&&(this.messages=this.messages.slice(j),c.log("pruned "+j+" stored messages"))}}}return P}(),A.rebuildChat=function(){function P(){if(this.isReady()){for(var M=Math.max(0,this.messages.length-s.MAX_VISIBLE_MESSAGES),w=this.messages.slice(M),V=f(w),U;!(U=V()).done;){var j=U.value;j.node=void 0}this.rootNode.textContent="",this.messages=[],this.visibleMessages=[],this.processBatch(w,{notifyListeners:!1})}}return P}(),A.clearChat=function(){function P(){var M=this.visibleMessages;this.visibleMessages=[];for(var w=0;w\n\n\n
\n'+$+"
\n\n\n",K=new Blob([H]),W=new Date().toISOString().substring(0,19).replace(/[-:]/g,"").replace("T","-");window.navigator.msSaveBlob(K,"ss13-chatlog-"+W+".html")}return P}(),b}();window.__chatRenderer__||(window.__chatRenderer__=new S);var T=e.chatRenderer=window.__chatRenderer__},51747:function(y,e){"use strict";e.__esModule=!0,e.replaceInTextNode=e.linkifyNode=e.highlightNode=void 0;function t(i,d){var c=typeof Symbol!="undefined"&&i[Symbol.iterator]||i["@@iterator"];if(c)return(c=c.call(i)).next.bind(c);if(Array.isArray(i)||(c=n(i))||d&&i&&typeof i.length=="number"){c&&(i=c);var g=0;return function(){return g>=i.length?{done:!0}:{done:!1,value:i[g++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(i,d){if(i){if(typeof i=="string")return r(i,d);var c={}.toString.call(i).slice(8,-1);return c==="Object"&&i.constructor&&(c=i.constructor.name),c==="Map"||c==="Set"?Array.from(i):c==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c)?r(i,d):void 0}}function r(i,d){(d==null||d>i.length)&&(d=i.length);for(var c=0,g=Array(d);c=s.IMAGE_RETRY_LIMIT){c.error("failed to load an image after "+M+" attempts");return}var w=P.src;P.src=null,P.src=w+"#"+M,P.setAttribute("data-reload-n",M+1)},s.IMAGE_RETRY_DELAY)},C=function(A){var P=A.node,M=A.times;if(!(!P||!M)){var w=P.querySelector(".Chat__badge"),V=w||document.createElement("div");V.textContent=M,V.className="Chat__badge",w||P.appendChild(V)}},S=function(){function b(){var P=this;this.loaded=!1,this.rootNode=null,this.queue=[],this.messages=[],this.visibleMessages=[],this.page=null,this.events=new r.EventEmitter,this.scrollNode=null,this.scrollTracking=!0,this.handleScroll=function(M){var w=P.scrollNode,V=w.scrollHeight,U=w.scrollTop+w.offsetHeight,j=Math.abs(V-U)0&&(this.processBatch(this.queue),this.queue=[])}return P}(),A.assignStyle=function(){function P(M){M===void 0&&(M={});for(var w=0,V=Object.keys(M);w{}[\]:;'"|~`_\-\\/]/g,W=String(G).split(/[,|]/).map(function(it){return it.trim()}).filter(function(it){return it&&it.length>1&&H.test(it)&&((H.lastIndex=0)||!0)}),q,ut;if(W.length!==0){for(var ct=[],Q=f(W),X;!(X=Q()).done;){var at=X.value;if(at.charAt(0)==="/"&&at.charAt(at.length-1)==="/"){var ft=at.substring(1,at.length-1);if(/^(\[.*\]|\\.|.)$/.test(ft))continue;ct.push(ft)}else q||(q=[]),at=at.replace(K,"\\$&"),q.push(at)}var dt=ct.join("|"),_="g"+(F?"":"i");try{if(dt)ut=new RegExp("("+dt+")",_);else{var rt=(B?"\\b":"")+"("+q.join("|")+")"+(B?"\\b":"");ut=new RegExp(rt,_)}}catch(it){ut=null}V.highlightParsers||(V.highlightParsers=[]),V.highlightParsers.push({highlightWords:q,highlightRegex:ut,highlightColor:$,highlightWholeMessage:x})}})}return P}(),A.scrollToBottom=function(){function P(){this.scrollNode.scrollTop=this.scrollNode.scrollHeight}return P}(),A.changePage=function(){function P(M){if(!this.isReady()){this.page=M,this.tryFlushQueue();return}this.page=M,this.rootNode.textContent="",this.visibleMessages=[];for(var w=document.createDocumentFragment(),V,U=f(this.messages),j;!(j=U()).done;){var G=j.value;(0,u.canPageAcceptType)(M,G.type)&&(V=G.node,w.appendChild(V),this.visibleMessages.push(G))}V&&(this.rootNode.appendChild(w),V.scrollIntoView())}return P}(),A.getCombinableMessage=function(){function P(M,w,V,U){for(var j=V;j>=U;j--){var G=this.visibleMessages[j],$=!G.type.startsWith(s.MESSAGE_TYPE_INTERNAL)&&(0,u.isSameMessage)(G,M)&&w0){this.visibleMessages=M.slice(w);for(var V=0;V0&&(this.messages=this.messages.slice(j),c.log("pruned "+j+" stored messages"))}}}return P}(),A.rebuildChat=function(){function P(){if(this.isReady()){for(var M=Math.max(0,this.messages.length-s.MAX_VISIBLE_MESSAGES),w=this.messages.slice(M),V=f(w),U;!(U=V()).done;){var j=U.value;j.node=void 0}this.rootNode.textContent="",this.messages=[],this.visibleMessages=[],this.processBatch(w,{notifyListeners:!1})}}return P}(),A.clearChat=function(){function P(){var M=this.visibleMessages;this.visibleMessages=[];for(var w=0;w\n\n\n
\n'+$+"
\n\n\n",K=new Blob([H],{type:"text/plain"}),W=new Date().toISOString().substring(0,19).replace(/[-:]/g,"").replace("T","-");Byond.saveBlob(K,"ss13-paradise-chatlog-"+W+".html",".html")}return P}(),b}();window.__chatRenderer__||(window.__chatRenderer__=new S);var T=e.chatRenderer=window.__chatRenderer__},51747:function(y,e){"use strict";e.__esModule=!0,e.replaceInTextNode=e.linkifyNode=e.highlightNode=void 0;function t(i,d){var c=typeof Symbol!="undefined"&&i[Symbol.iterator]||i["@@iterator"];if(c)return(c=c.call(i)).next.bind(c);if(Array.isArray(i)||(c=n(i))||d&&i&&typeof i.length=="number"){c&&(i=c);var g=0;return function(){return g>=i.length?{done:!0}:{done:!1,value:i[g++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function n(i,d){if(i){if(typeof i=="string")return r(i,d);var c={}.toString.call(i).slice(8,-1);return c==="Object"&&i.constructor&&(c=i.constructor.name),c==="Map"||c==="Set"?Array.from(i):c==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c)?r(i,d):void 0}}function r(i,d){(d==null||d>i.length)&&(d=i.length);for(var c=0,g=Array(d);c + - - - - - - - - - + + - - + + + + - - - - - - - - -
- - -
- - - A fatal exception has occurred at 002B:C562F1B7 in TGUI. The current - application will be terminated. Please remain calm. Get to the nearest - NTNet workstation and send the copy of the following stack trace to: - https://github.com/ParadiseSS13/Paradise. Thank you for your cooperation. - -
- -
- -