diff --git a/code/datums/server_greeting.dm b/code/datums/server_greeting.dm
index b395e402d6e..70c9409ef95 100644
--- a/code/datums/server_greeting.dm
+++ b/code/datums/server_greeting.dm
@@ -14,6 +14,8 @@
#define OUTDATED_MEMO 2
#define OUTDATED_NOTE 4
+#define JS_SANITIZE(msg) list2params(list(json_encode(msg)))
+
/datum/server_greeting
// Hashes to figure out if we need to display the greeting message.
// These correspond to motd_hash and memo_hash on /datum/preferences for each client.
@@ -21,24 +23,19 @@
var/memo_hash = ""
// The stored strings of general subcomponents.
- var/motd = ""
- var/memo_list[] = list()
- var/memo = ""
+ var/motd = "
No new announcements to showcase. "
- var/raw_data_user = ""
- var/raw_data_staff = ""
- // The near-final string to be displayed.
- // Only one placeholder remains: .
- var/user_data = ""
- var/staff_data = ""
+ var/memo_list[] = list()
+ var/memo = "No memos have been posted. "
+
+ // Cached outdated information.
+ var/list/client_cache = list()
/datum/server_greeting/New()
..()
load_from_file()
- prepare_data()
-
/*
* Populates variables from save file, and loads the raw HTML data.
* Needs to be called at least once for successful initialization.
@@ -52,51 +49,33 @@
if (F["memo"])
F["memo"] >> memo_list
- raw_data_staff = file2text('html/templates/welcome_screen.html')
-
- // This is a lazy way, but it disables the user from being able to see the memo button.
- var/staff_button = "Staff Memos "
- raw_data_user = replacetextEx(raw_data_staff, staff_button, "")
+ update_data()
/*
- * Generates hashes, placeholders, and reparses var/memo.
- * Then updates staff_data and user_data with the new contents.
- * To be called after load_from_file or update_value.
+ * A helper to regenerate the hashes for all data fields.
+ * As well as to reparse the staff memo list.
+ * Separated for the sake of avoiding the duplication of code.
*/
-/datum/server_greeting/proc/prepare_data()
- if (!motd)
- motd = "No new announcements to showcase. "
- motd_hash = ""
- else
+/datum/server_greeting/proc/update_data()
+ if (motd)
motd_hash = md5(motd)
-
- memo = ""
+ else
+ motd = initial(motd)
+ motd_hash = ""
if (memo_list.len)
+ memo = ""
for (var/ckey in memo_list)
- var/data = {"
- [ckey] wrote on [memo_list[ckey]["date"]]:
- [memo_list[ckey]["content"]]
- "}
+ var/data = {"[ckey] wrote on [memo_list[ckey]["date"]]:
+ [memo_list[ckey]["content"]]
"}
memo += data
memo_hash = md5(memo)
else
- memo = "No memos have been posted. "
+ memo = initial(memo)
memo_hash = ""
- var/html_one = raw_data_staff
- html_one = replacetextEx(html_one, "", motd)
- html_one = replacetextEx(html_one, "", memo)
- staff_data = html_one
-
- var/html_two = raw_data_user
- html_two = replacetextEx(html_two, "", motd)
- user_data = html_two
-
- return
-
/*
* Helper to update the MoTD or memo contents.
* Args:
@@ -113,7 +92,6 @@
switch (change)
if ("motd")
motd = new_value
- motd_hash = md5(new_value)
if ("memo_write")
memo_list[new_value[1]] = list("date" = time2text(world.realtime, "DD-MMM-YYYY"), "content" = new_value[2])
@@ -131,7 +109,7 @@
F["motd"] << motd
F["memo"] << memo_list
- prepare_data()
+ update_data()
return 1
@@ -142,10 +120,13 @@
* Returns:
* - int
*/
-/datum/server_greeting/proc/find_outdated_info(var/client/user)
+/datum/server_greeting/proc/find_outdated_info(var/client/user, var/force_eval = 0)
if (!user || !user.prefs)
return 0
+ if (!force_eval && !isnull(client_cache[user]))
+ return client_cache[user]
+
var/outdated_info = 0
if (motd_hash && user.prefs.motd_hash != motd_hash)
@@ -157,53 +138,88 @@
if (user.prefs.notifications.len)
outdated_info |= OUTDATED_NOTE
+ client_cache[user] = outdated_info
+
return outdated_info
/*
- * Composes the final message and displays it to the user.
- * Also clears the user's notifications, should he have any.
+ * A proc used to open the server greeting window for a user.
+ * Args:
+ * - var/user client
+ * - var/outdated_info int
*/
-/datum/server_greeting/proc/display_to_client(var/client/user, var/outdated_info = 0)
+/datum/server_greeting/proc/display_to_client(var/client/user)
if (!user)
return
- var/notifications = "You do not have any notifications to show.
"
- var/list/outdated_tabs = list()
+ user << browse('html/templates/welcome_screen.html', "window=greeting;size=640x500")
+
+/*
+ * Sends data to the JS controllers used in the server greeting.
+ * Also updates the user's preferences, if any of the hashes were out of date.
+ * Args:
+ * - var/user client
+ * - var/outdated_info int
+ */
+/datum/server_greeting/proc/send_to_javascript(var/client/user)
+ if (!user)
+ return
+
+ // This is fine now, because it uses cached information.
+ var/outdated_info = server_greeting.find_outdated_info(user)
+
var/save_prefs = 0
+ var/list/data = list("div" = "", "content" = "", "update" = 1)
if (outdated_info & OUTDATED_NOTE)
- outdated_tabs += "#note-tab"
+ user << output("#note-placeholder", "greeting.browser:RemoveElement")
+
+ data["div"] = "#note"
+ data["update"] = 1
- notifications = ""
for (var/datum/client_notification/a in user.prefs.notifications)
- notifications += a.get_html()
+ data["content"] = a.get_html()
+ user << output(JS_SANITIZE(data), "greeting.browser:AddContent")
- if (outdated_info & OUTDATED_MEMO)
- outdated_tabs += "#memo-tab"
- user.prefs.memo_hash = memo_hash
- save_prefs = 1
+ if (!user.holder)
+ user << output("#memo-tab", "greeting.browser:RemoveElement")
+ else
+ if (outdated_info & OUTDATED_MEMO)
+ data["update"] = 1
+ user.prefs.memo_hash = memo_hash
+ save_prefs = 1
+ else
+ data["update"] = 0
+
+ data["div"] = "#memo"
+ data["content"] = memo
+ user << output(JS_SANITIZE(data), "greeting.browser:AddContent")
if (outdated_info & OUTDATED_MOTD)
- outdated_tabs += "#motd-tab"
+ data["update"] = 1
user.prefs.motd_hash = motd_hash
save_prefs = 1
+ else
+ data["update"] = 0
- var/data = user_data
-
- if (user.holder)
- data = staff_data
-
- data = replacetextEx(data, "", notifications)
-
- if (outdated_tabs.len)
- var/tab_string = json_encode(outdated_tabs)
- data = replacetextEx(data, "var updated_tabs = \[\]", "var updated_tabs = [tab_string]")
-
- user << browse(data, "window=welcome_screen;size=640x500")
+ data["div"] = "#motd"
+ data["content"] = motd
+ user << output(JS_SANITIZE(data), "greeting.browser:AddContent")
if (save_prefs)
user.prefs.handle_preferences_save(user)
+/*
+ * Basically the Topic proc for the greeting datum.
+ */
+/datum/server_greeting/proc/handle_call(var/href_list, var/client/C)
+ if (!href_list || !href_list["command"] || !C)
+ return
+
+ switch (href_list["command"])
+ if ("request_data")
+ send_to_javascript(C)
+
#undef OUTDATED_NOTE
#undef OUTDATED_MEMO
#undef OUTDATED_MOTD
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index 2715e4a68c6..33fb624ab93 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -55,8 +55,6 @@
cmd_admin_discord_pm(href_list["discord_msg"])
return
-
-
//Logs all hrefs
if(config && config.log_hrefs && href_logfile)
href_logfile << "[time2text(world.timeofday,"hh:mm")] [src] (usr:[usr]) || [hsrc ? "[hsrc] " : ""][href] "
@@ -178,6 +176,10 @@
var/DBQuery/query = dbcon.NewQuery("INSERT INTO ss13_stats_ie (ckey, IsIE, IsEdge, EdgeHtmlVersion, TrueVersion, ActingVersion, CompatibilityMode, DateUpdated) VALUES (_ckey, _IsIE, _IsEdge, _EdgeHtmlVersion, _TrueVersion, _ActingVersion, _CompatibilityMode, NOW()) ON DUPLICATE KEY UPDATE IsIE = VALUES(IsIe), IsEdge = VALUES(IsEdge), EdgeHtmlVersion = VALUES(EdgeHtmlVersion), TrueVersion = VALUES(TrueVersion), ActingVersion = VALUES(ActingVersion), CompatibilityMode = VALUES(CompatibilityMode), DateUpdated = NOW()")
query.Execute(data)
+ if ("greeting")
+ if (server_greeting)
+ server_greeting.handle_call(href_list, src)
+
return
// Antag contest shit
@@ -294,10 +296,9 @@
send_resources()
nanomanager.send_resources(src)
- var/outdated_greeting_info = server_greeting.find_outdated_info(src)
-
- if (outdated_greeting_info)
- server_greeting.display_to_client(src, outdated_greeting_info)
+ // Server greeting shenanigans.
+ if (server_greeting.find_outdated_info(src, 1))
+ server_greeting.display_to_client(src)
// Check code/modules/admin/verbs/antag-ooc.dm for definition
add_aooc_if_necessary()
@@ -421,10 +422,7 @@
'html/images/talisman.png',
'html/bootstrap/css/bootstrap.min.css',
'html/bootstrap/js/bootstrap.min.js',
- 'html/bootstrap/js/html5shiv.min.js',
- 'html/bootstrap/js/respond.min.js',
'html/jquery/jquery-2.0.0.min.js',
- 'html/iestats/json2.min.js',
'html/iestats/ie-truth.min.js',
'icons/pda_icons/pda_atmos.png',
'icons/pda_icons/pda_back.png',
@@ -586,4 +584,7 @@
set name = "Open Greeting"
set category = "OOC"
- server_greeting.display_to_client(src, server_greeting.find_outdated_info(src))
+ // Update the information just in case.
+ server_greeting.find_outdated_info(src, 1)
+
+ server_greeting.display_to_client(src)
diff --git a/code/modules/client/preferences_notification.dm b/code/modules/client/preferences_notification.dm
index 0e347defd0e..ac42be96411 100644
--- a/code/modules/client/preferences_notification.dm
+++ b/code/modules/client/preferences_notification.dm
@@ -61,13 +61,13 @@
* Returns the HTML required to display this alert.
*/
/datum/client_notification/proc/get_html()
- var/html = "[note_wrapper[1]]\n"
+ var/html = "
[note_wrapper[1]]"
if (!persistent)
- html += "
× \n"
+ html += "
× "
html += note_text
- html += "\n[note_wrapper[2]]
"
+ html += "[note_wrapper[2]]
"
return html
diff --git a/html/bootstrap/js/html5shiv.min.js b/html/bootstrap/js/html5shiv.min.js
deleted file mode 100644
index 355afd10608..00000000000
--- a/html/bootstrap/js/html5shiv.min.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
-* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
-*/
-!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML=" ",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
\ No newline at end of file
diff --git a/html/bootstrap/js/respond.min.js b/html/bootstrap/js/respond.min.js
deleted file mode 100644
index 80a7b69dcce..00000000000
--- a/html/bootstrap/js/respond.min.js
+++ /dev/null
@@ -1,5 +0,0 @@
-/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl
- * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT
- * */
-
-!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b
Aurorastation Welcome Screen
-
+
@@ -46,9 +46,9 @@
-
-
-
+
+
+ You do not have any notifications to show.
@@ -56,28 +56,72 @@
-
-
-
-