diff --git a/garrysmod/lua/vgui/dhtml.lua b/garrysmod/lua/vgui/dhtml.lua
index 0f3b2caf0d..0ba9d6e56d 100644
--- a/garrysmod/lua/vgui/dhtml.lua
+++ b/garrysmod/lua/vgui/dhtml.lua
@@ -63,6 +63,82 @@ function PANEL:Call( js )
self:QueueJavascript( js )
end
+local function BuildFunction( func, ... )
+
+ --
+ -- Build a Javascript-safe JS function call.
+ -- To be run by either panel:RunFunction or panel:QueueFunction
+ --
+ -- First parameter is the JS function name,
+ -- additional parameters are the values to provide to the function call.
+ -- The values provided to the function call are treated as strings except where noted below.
+ --
+
+ local formatArgs = {}
+ local safeArgs = {}
+
+ for k, v in ipairs( { ... } ) do
+
+ if isbool( v ) then -- Boolean
+
+ formatArgs[ k ] = '%s'
+ safeArgs[ k ] = v and true or false
+
+ elseif isnumber( v ) then -- Numbers
+
+ formatArgs[ k ] = '%s'
+ safeArgs[ k ] = v
+
+ elseif IsColor( v ) then -- Colors, convert to CSS format
+
+ formatArgs[ k ] = '"%s"'
+ safeArgs[ k ] = v:ToHex() -- returns "#rrggbb" or "#rrggbbaa" depending on alpha
+
+ -- Awesomium does NOT support "#rrggbbaa", so for now we're overriding any alpha ones with "rgba()". Once Awesomium has been fully replaced by CEF, remove this override.
+ if v.a != 255 then
+ -- alpha has 3dp precision, as that's enough to accurately convert back to 0-255 or 00-FF.
+ safeArgs[ k ] = string.format( "rgba(%d,%d,%d,%.3f)", v.r, v.g, v.b, ( v.a / 255 ) )
+ end
+
+ elseif istable( v ) then -- Tables, convert to json object
+
+ formatArgs[ k ] = 'JSON.parse("%s")'
+ safeArgs[ k ] = string.JavascriptSafe( util.TableToJSON( v ) )
+
+ else -- Strings, and all else treated as strings
+
+ formatArgs[ k ] = '"%s"'
+ safeArgs[ k ] = string.JavascriptSafe( tostring( v ) )
+
+ end
+
+ end
+
+
+ func = string.gsub( func, "[^%w%._]", "" ) -- Function name strips any characters that aren't underscore "_", dot ".", or alphanumeric.
+
+ return string.format( [[ %s( ]] .. table.concat( formatArgs, ", " ) .. [[ ); ]], func, unpack( safeArgs ) )
+
+end
+
+function PANEL:RunFunction( func, ... )
+
+ --
+ -- Build and Run a Javascript function immediately.
+ --
+ self:RunJavascript( BuildFunction( func, ... ) )
+
+end
+
+function PANEL:QueueFunction( func, ... )
+
+ --
+ -- Build and Queue a Javascript function.
+ --
+ self:QueueJavascript( BuildFunction( func, ... ) )
+
+end
+
function PANEL:ConsoleMessage( msg, file, line, severity )
if ( !isstring( msg ) ) then msg = "*js variable*" end