Update webgui

parent 60ed8f6c
......@@ -25,7 +25,7 @@
],
"start_url": "/gui/",
"display": "fullscreen",
"display": "standalone",
"orientation": "portrait",
"developer": {
"name": "Franco (nextime) Lanza",
......
......@@ -37,6 +37,9 @@ body {
z-index: 10000;
overflow: hidden;
background-color: #333;
position: fixed;
top: 0;
width:100%;
}
/* Navbar links */
......@@ -55,19 +58,12 @@ body {
}
/* The sticky class is added to the navbar with JS when it reaches its scroll position */
.sticky {
position: fixed;
top: 0;
width: 100%
}
/* Add some top padding to the page content to prevent sudden quick movement (as the navigation bar gets a new position at the top of the page (position:fixed and top:0) */
.sticky + .content {
padding-top: 60px;
#content::before {
content: "";
display: block;
height: 40px;
}
/* The side navigation menu */
.sidenav {
height: 100%; /* 100% Full-height */
......@@ -107,10 +103,19 @@ body {
.column {
float: left;
width: 33.33%;
overflow-y: scroll;
height: 400px;
/* border: 1px solid white; */
width: 33%;
}
.coltitle {
background-color: #4a66ce;
color: white;
text-align: center;
padding: 6px;
padding-top: 14px;
padding-bottom: 14px;
margin: 4px;
border-radius: 10px;
}
/* Clear floats after the columns */
......@@ -189,8 +194,135 @@ div .menubtn div {
background-color: #0d1f29;
}
.button {
background-color: #3e3c3c;
border-radius: 10px;
margin: 4px;
padding: 10px;
padding-top: 14px;
padding-bottom: 14px;
}
.btnname {
color: #bbbbbb;
float: left;
}
.btnact {
float: right;
}
.button::after {
content: "";
display: table;
clear: both;
}
.onoffswitch {
position: relative; width: 110px;
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select: none;
}
.onoffswitch-checkbox {
display: none;
}
.onoffswitch-label {
display: block;
overflow: hidden;
cursor: pointer;
border: 2px solid #999999;
border-radius: 10px;
}
.onoffswitch-inner {
display: block;
width: 200%;
margin-left: -100%;
transition: margin 0.2s ease-in 0s;
}
.onoffswitch-inner-on, .onoffswitch-inner-off {
display: block;
float: left;
width: 50%;
height: 30px;
padding: 0;
line-height: 30px;
font-size: 14px;
color: white;
font-family: Trebuchet, Arial, sans-serif;
font-weight: bold;
box-sizing: border-box;
}
.onoffswitch-inner-on {
padding-left: 10px;
background-color: #38CDFF;
color: #FFFFFF;
}
.onoffswitch-inner-off {
padding-right: 10px;
background-color: #EEEEEE;
color: #999999;
text-align: right;
}
.onoffswitch-switch {
display: block;
width: 10px;
margin: 6px;
background: #cccccc;
position: absolute;
top: 0;
bottom: 0;
right: 84px;
border: 2px solid #999999;
border-radius: 8px;
transition: all 0.2s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
margin-left: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
right: 0px;
}
@media (min-width: 601px) {
.column {
height: 400px;
overflow-y: auto;
}
}
@media (max-width: 1280px) {
.column {
width: 50%;
}
}
@media (max-width: 640px) {
.column {
width: 100%;
}
}
</style>
<script language="javascript" src="/sockjs.min.js"></script>
<script language="javascript">
var sock = new SockJS('/sockjs');
sock.onopen = function() {
console.log('open');
sock.send('test');
};
sock.onmessage = function(e) {
console.log('message', e.data);
};
sock.onclose = function() {
console.log('close');
};
sideSize = "400px";
if ( window.innerWidth <= parseInt(sideSize)+200) {
sideSize = "100%";
......@@ -256,21 +388,16 @@ function CloseNav() {
</div>
<div id="SidenavLeft" class="sidenav sidenavleft">
<a href="#">About</a>
<a href="#">Services</a>
<a href="#">Clients</a>
<a href="#">Contact</a>
<a href="/gui/">Home</a>
@PLUGINS@
</div>
<div id="SidenavRight" class="sidenav sidenavright">
<div class="simplebtn"><a href="/__LOGOUT__/">Logout</a></div>
</div>
<div id="content" class="tblack" >
<div class="row">
<div class="column"></div>
<div class="column"></div>
<div class="column"></div>
</div>
@CONTENT@
</div>
</div>
</body>
</html>
......
<div class=button>
<div class="btnname">
@BTNNAME@
</div>
<div class="btnact">
@BTNACT@
</div>
</div>
<div class="column">
<div class="coltitle">
<span><b>@COLTITLE@</b></span>
</div>
@COLCONTENT@
</div>
<div class="onoffswitch">
<input type="checkbox" name="@ID@" class="onoffswitch-checkbox" id="@ID@">
<label class="onoffswitch-label" for="@ID@">
<span class="onoffswitch-inner">
<span class="onoffswitch-inner-on">@ON@</span>
<span class="onoffswitch-inner-off">@OFF@</span>
</span>
<span class="onoffswitch-switch"></span>
</label>
</div>
File mode changed from 100644 to 100755
......@@ -33,6 +33,13 @@ class IModules(Interface):
def initialize(self, callback, logger):
""" initialize a plugin module passing a callback """
def getWebHome(self):
""" get HTML for webgui homepage """
def getWebPage(self):
""" get HTML for plugin specific page """
def context2section(ctx):
if int(ctx) in C.SECTIONS.keys():
section=C.SECTIONS[int(ctx)]
......
......@@ -42,7 +42,7 @@ from singleton import Singleton
import pluggable
import ikap
from web import web
from singleton.ajaxconnections import AJAXCONNREG
try:
......@@ -67,6 +67,7 @@ class penguidomService(service.Service):
initialized=False
udp=False
tcp=False
plugins={}
def __init__(self, *args, **kwargs):
log.info('Initializing Core')
......@@ -135,3 +136,17 @@ class penguidomService(service.Service):
cfg.readConfig()
return cfg
def on_getPluginList(self):
return self.plugins.plugreg.keys()
def on_getPlugin(self, plugname):
if plugname in self.plugins.plugreg.keys():
return self.plugins.plugreg[plugname]
return None
def plugin_on_getWebParts(self):
return web.PageParts()
def web_on_test(self):
for c in AJAXCONNREG.connections.keys():
c.transport.write('CORE:test:OK')
......@@ -56,7 +56,7 @@ class PluginLogger(object):
self.name = plugname
def _format(self, what):
return str(self.name)+": "+what
return str(self.name)+": "+str(what)
def info(self, what):
log.info(self._format(what))
......@@ -84,8 +84,8 @@ class Loader(object):
try:
if genutils.isTrue(self.core.configGet('plugins', name)):
p = getPlugin(name, core)
self.plugreg[name] = p
p.initialize(ConvenienceCaller(lambda c: self._plugincback(name, c)), PluginLogger(name))
self.plugreg[name] = p
except NoSectionError:
log.error("Trying to load "+name+" plugin but no value in config file plugins section")
......
......@@ -119,6 +119,10 @@ class ParadoxEventMap(Singleton):
self.eventMap._siteNameLabel.update({number: value})
return
def getsiteNameLabel(self):
self.eventMap._siteNameLabel
def setwirelessSirenLabel(self, number, value):
self.eventMap._wirelessSiren.update({number: value})
return
......
......@@ -56,6 +56,7 @@ class ParadoxProtocol(BaseProtocol):
packettimeout = 0
proxy = False
zonemap = False
boardname = ''
def __init__(self, logger, core, cfg):
self.log = logger
......@@ -208,6 +209,7 @@ class ParadoxProtocol(BaseProtocol):
def _detectBoard(self, reply, cbargs=None):
board = p37b.getPanelName(reply)
self.boardname = board
self.log.info('Detected Panel Board as '+board)
if self.autodetect:
try:
......@@ -357,4 +359,27 @@ class Paradox(object):
logger.info("Plugin initialized")
def getWebHome(self):
webparts = self.core.getWebParts()
labelreg = REGISTERS.getsiteNameLabelRegister()
try:
if labelreg.items()[0][1][0] is not None:
colname = str(labelreg.items()[0][1][0])
else:
colname = " ".join(['Paradox', self.serproto.boardname])
except:
colname = 'paradox'
partitions = EVENTMAP.getAllpartitionLabel()
#self.log.info(EVENTMAP.getsiteNameLabel())
colcont = ''
for partition in partitions.items():
partname = partition[1]
partidx = partition[0]
colcont+=webparts.getButton(title=str(partname), act=webparts.getOnOffSwitch("".join(['paradox_partition_', str(partidx)]), on='ARMED', off='DISARMED'))
return webparts.getColumn(title=colname, content=colcont)
def getWebPage(self):
return REGISTERS.getsiteNameLabelRegister()
......@@ -29,6 +29,7 @@ from twisted.web import resource, static, server
import time
from txsockjs.factory import SockJSResource, SockJSFactory
import dmjson as dmj
from penguidom.singleton.ajaxconnections import AJAXCONNREG as CONNREG
log = logging.getLogger( 'Webgui' )
......@@ -44,22 +45,18 @@ class AjaxProtocol(object):
f=getattr(self, 'on_command_'+message.split(":")[0], None)
if f and callable(f):
log.debug("Received "+str(message.split(":")[0])+" command")
return f(message)
f(message)
else:
self.messageSend(message, binary)
def _getIOStatus(self, d, ts):
rs = self.factory.core.getRelays(ts)
rs.addCallback(relstatus, False, d)
return rs.addCallback(dmj.jsonize_text)
def on_command_getIOStatus(self, data):
wts=data.split(":")[1].split("=")[1]
ret=self.factory.core.getActionStatus()
ts=int(time.time())-1
ist=self.factory.core.getInputs(wts)
ist.addCallback(inputstatus, ts, ret).addCallback(self._getIOStatus, wts)
return ist.addCallback(self.messageSend)
def on_command_test(self, data):
log.debug("TEST AJAX COMMAND "+str(data))
if str(data) == 'test':
self.messageSend('test:OK')
splitted = data.split(':')
if len(splitted) > 1:
if splitted[1] == 'broadcast':
self.factory.core.test()
def connectionMade(self, who):
log.debug('AJAX connectionMade called by '+str(who))
......@@ -73,16 +70,18 @@ class AjaxProtocol(object):
class SockJSServerProtocolWrapper(protocol.Protocol, AjaxProtocol):
def dataReceived(self, data):
log.debug("SockJS RECEIVED: "+str(data))
log.info("SockJS RECEIVED: "+str(data))
self.messageReceived(data, False)
def messageSend(self, msg, binary=False):
self.transport.write(msg)
def connectionMade(self):
CONNREG.connections[self] = 1
AjaxProtocol.connectionMade(self, 'sockjs')
def connectionLost(self, reason):
del CONNREG.connections[self]
AjaxProtocol.connectionLost(self, 'sockjs', reason)
......
......@@ -48,6 +48,8 @@ log = logging.getLogger( 'Webgui' )
curdir=os.path.abspath(os.path.dirname(sys.argv[0]))
LOGINFILE=os.path.normpath("/".join([curdir, 'Web/resources/login.html']))
GUIFILE=os.path.normpath("/".join([curdir, 'Web/resources/page.html']))
GUIPARTSDIR=os.path.normpath("/".join([curdir, 'Web/resources/parts/']))
from common import uni, GzipRequest, StaticFile, codeOk, permissionDenied, RedirectToHome, neededPermission
import ajax
......@@ -130,6 +132,16 @@ class GuiPage(BasePage):
log.info(path)
html = self.html
html = html.replace("@SCRIPT@", "")
plist = ''
phome = ''
for p in self.core.getPluginList():
plist+="".join(['<a href="/gui/plugin/', str(p), '">', str(p), '</a>\n'])
plug = self.core.getPlugin(p)
if plug:
log.debug("Plugin getWebHome for "+str(p)+" "+str(plug))
phome+=str(plug.getWebHome())
html = html.replace("@PLUGINS@", plist)
html = html.replace("@CONTENT@", phome)
return html
def childFactory(self, ctx, name):
......@@ -177,8 +189,8 @@ class RootPage(BasePage):
if len(pl)>2:
pname=pl[2]
pconf=os.path.normpath("/".join([curdir, 'plugins', pname, 'conf', pname+".conf" ]))
log.debug("trying to read "+str(dconf))
if os.path.isfile(dconf):
log.debug("trying to read "+str(pconf))
if os.path.isfile(fconf):
try:
pcfg=configFile(pconf)
pcfg.readConfig()
......@@ -530,3 +542,44 @@ def getAuthResource(core):
site.core = core
return site
class PageParts(object):
parts = {}
def _getPartFile(self, part):
if part in self.parts.keys():
return self.parts[part]
partfile = ''.join([GUIPARTSDIR, '/', part, '.html'])
log.info(partfile)
if os.path.isfile(partfile):
try:
lf = open(partfile, "r")
html = lf.read()
lf.close()
self.parts[part] = html
return html
except:
pass
return ''
def getColumn(self, title="Title", content=""):
col = self._getPartFile('column')
col = col.replace('@COLTITLE@', title)
col = col.replace('@COLCONTENT@', content)
return col
def getButton(self, title="Button", act="Act"):
btn = self._getPartFile('button')
btn = btn.replace('@BTNNAME@', title)
btn = btn.replace('@BTNACT@', act)
return btn
def getOnOffSwitch(self, sid='myonoffswitch', on='ON', off='OFF'):
swh = self._getPartFile('onoffswitch')
swh = swh.replace('@ON@', on)
swh = swh.replace('@OFF@', off)
swh = swh.replace('@ID@' , sid)
return swh
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment