version 0.1.6, dont check own sites integrity, serving newly added sites, only serve .html files with wrapper, pass query string to innerframe, support for background-color in content.json, websocket api sitepublish and filewrite commands, pass hashchange to innerframe, wrapperPrompt notification support,
This commit is contained in:
parent
a977feec33
commit
024655cf15
11 changed files with 172 additions and 16 deletions
|
@ -3,7 +3,7 @@ import ConfigParser
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.version = "0.1.5"
|
self.version = "0.1.6"
|
||||||
self.parser = self.createArguments()
|
self.parser = self.createArguments()
|
||||||
argv = sys.argv[:] # Copy command line arguments
|
argv = sys.argv[:] # Copy command line arguments
|
||||||
argv = self.parseConfig(argv) # Add arguments from config file
|
argv = self.parseConfig(argv) # Add arguments from config file
|
||||||
|
|
|
@ -150,7 +150,7 @@ class Site:
|
||||||
if changed_files:
|
if changed_files:
|
||||||
for changed_file in changed_files:
|
for changed_file in changed_files:
|
||||||
self.bad_files[changed_file] = True
|
self.bad_files[changed_file] = True
|
||||||
self.checkFiles(quick_check=True) # Quick check files based on file size
|
if not self.settings["own"]: self.checkFiles(quick_check=True) # Quick check files based on file size
|
||||||
if self.bad_files:
|
if self.bad_files:
|
||||||
self.download()
|
self.download()
|
||||||
return changed_files
|
return changed_files
|
||||||
|
@ -457,7 +457,6 @@ class Site:
|
||||||
|
|
||||||
self.log.info("Signing modified content.json...")
|
self.log.info("Signing modified content.json...")
|
||||||
sign_content = json.dumps(content, sort_keys=True)
|
sign_content = json.dumps(content, sort_keys=True)
|
||||||
self.log.debug("Content: %s" % sign_content)
|
|
||||||
sign = CryptBitcoin.sign(sign_content, privatekey)
|
sign = CryptBitcoin.sign(sign_content, privatekey)
|
||||||
content["sign"] = sign
|
content["sign"] = sign
|
||||||
|
|
||||||
|
@ -466,3 +465,4 @@ class Site:
|
||||||
open("%s/content.json" % self.directory, "w").write(json.dumps(content, indent=4, sort_keys=True))
|
open("%s/content.json" % self.directory, "w").write(json.dumps(content, indent=4, sort_keys=True))
|
||||||
|
|
||||||
self.log.info("Site signed!")
|
self.log.info("Site signed!")
|
||||||
|
return True
|
||||||
|
|
|
@ -47,7 +47,10 @@ def need(address, all_file=True):
|
||||||
if not isAddress(address): raise Exception("Not address: %s" % address)
|
if not isAddress(address): raise Exception("Not address: %s" % address)
|
||||||
logging.debug("Added new site: %s" % address)
|
logging.debug("Added new site: %s" % address)
|
||||||
sites[address] = Site(address)
|
sites[address] = Site(address)
|
||||||
sites[address].settings["serving"] = True # Maybe it was deleted before
|
if not sites[address].settings["serving"]: # Maybe it was deleted before
|
||||||
|
sites[address].settings["serving"] = True
|
||||||
|
sites[address].saveSettings()
|
||||||
|
|
||||||
site = sites[address]
|
site = sites[address]
|
||||||
if all_file: site.download()
|
if all_file: site.download()
|
||||||
return site
|
return site
|
||||||
|
|
|
@ -66,7 +66,8 @@ class UiRequest:
|
||||||
|
|
||||||
|
|
||||||
# Send response headers
|
# Send response headers
|
||||||
def sendHeader(self, status=200, content_type="text/html; charset=utf-8", extra_headers=[]):
|
def sendHeader(self, status=200, content_type="text/html", extra_headers=[]):
|
||||||
|
if content_type == "text/html": content_type = "text/html; charset=utf-8"
|
||||||
headers = []
|
headers = []
|
||||||
headers.append(("Version", "HTTP/1.1"))
|
headers.append(("Version", "HTTP/1.1"))
|
||||||
headers.append(("Access-Control-Allow-Origin", "*")) # Allow json access
|
headers.append(("Access-Control-Allow-Origin", "*")) # Allow json access
|
||||||
|
@ -101,6 +102,7 @@ class UiRequest:
|
||||||
|
|
||||||
# Render a file from media with iframe site wrapper
|
# Render a file from media with iframe site wrapper
|
||||||
def actionWrapper(self, path):
|
def actionWrapper(self, path):
|
||||||
|
if "." in path and not path.endswith(".html"): return self.actionSiteMedia("/media"+path) # Only serve html files with frame
|
||||||
if self.env.get("HTTP_X_REQUESTED_WITH"): return self.error403() # No ajax allowed on wrapper
|
if self.env.get("HTTP_X_REQUESTED_WITH"): return self.error403() # No ajax allowed on wrapper
|
||||||
|
|
||||||
match = re.match("/(?P<site>[A-Za-z0-9]+)(?P<inner_path>/.*|$)", path)
|
match = re.match("/(?P<site>[A-Za-z0-9]+)(?P<inner_path>/.*|$)", path)
|
||||||
|
@ -109,19 +111,29 @@ class UiRequest:
|
||||||
if not inner_path: inner_path = "index.html" # If inner path defaults to index.html
|
if not inner_path: inner_path = "index.html" # If inner path defaults to index.html
|
||||||
|
|
||||||
site = self.server.sites.get(match.group("site"))
|
site = self.server.sites.get(match.group("site"))
|
||||||
if site and site.content and not site.bad_files: # Its downloaded
|
if site and site.content and (not site.bad_files or site.settings["own"]): # Its downloaded or own
|
||||||
title = site.content["title"]
|
title = site.content["title"]
|
||||||
else:
|
else:
|
||||||
title = "Loading %s..." % match.group("site")
|
title = "Loading %s..." % match.group("site")
|
||||||
site = SiteManager.need(match.group("site")) # Start download site
|
site = SiteManager.need(match.group("site")) # Start download site
|
||||||
if not site: self.error404()
|
if not site: self.error404()
|
||||||
|
|
||||||
|
|
||||||
self.sendHeader(extra_headers=[("X-Frame-Options", "DENY")])
|
self.sendHeader(extra_headers=[("X-Frame-Options", "DENY")])
|
||||||
|
|
||||||
|
# Wrapper variable inits
|
||||||
|
if self.env.get("QUERY_STRING"):
|
||||||
|
query_string = "?"+self.env["QUERY_STRING"]
|
||||||
|
else:
|
||||||
|
query_string = ""
|
||||||
|
body_style = ""
|
||||||
|
if site.content and site.content.get("background-color"): body_style += "background-color: "+site.content["background-color"]+";"
|
||||||
|
|
||||||
return self.render("src/Ui/template/wrapper.html",
|
return self.render("src/Ui/template/wrapper.html",
|
||||||
inner_path=inner_path,
|
inner_path=inner_path,
|
||||||
address=match.group("site"),
|
address=match.group("site"),
|
||||||
title=title,
|
title=title,
|
||||||
|
body_style=body_style,
|
||||||
|
query_string=query_string,
|
||||||
wrapper_key=site.settings["wrapper_key"],
|
wrapper_key=site.settings["wrapper_key"],
|
||||||
permissions=json.dumps(site.settings["permissions"]),
|
permissions=json.dumps(site.settings["permissions"]),
|
||||||
show_loadingscreen=json.dumps(not os.path.isfile(site.getPath(inner_path))),
|
show_loadingscreen=json.dumps(not os.path.isfile(site.getPath(inner_path))),
|
||||||
|
|
|
@ -91,6 +91,10 @@ class UiWebsocket:
|
||||||
self.actionServerInfo(req["id"], req["params"])
|
self.actionServerInfo(req["id"], req["params"])
|
||||||
elif cmd == "siteUpdate":
|
elif cmd == "siteUpdate":
|
||||||
self.actionSiteUpdate(req["id"], req["params"])
|
self.actionSiteUpdate(req["id"], req["params"])
|
||||||
|
elif cmd == "sitePublish":
|
||||||
|
self.actionSitePublish(req["id"], req["params"])
|
||||||
|
elif cmd == "fileWrite":
|
||||||
|
self.actionFileWrite(req["id"], req["params"])
|
||||||
# Admin commands
|
# Admin commands
|
||||||
elif cmd == "sitePause" and "ADMIN" in permissions:
|
elif cmd == "sitePause" and "ADMIN" in permissions:
|
||||||
self.actionSitePause(req["id"], req["params"])
|
self.actionSitePause(req["id"], req["params"])
|
||||||
|
@ -173,6 +177,60 @@ class UiWebsocket:
|
||||||
self.response(to, ret)
|
self.response(to, ret)
|
||||||
|
|
||||||
|
|
||||||
|
def actionSitePublish(self, to, params):
|
||||||
|
site = self.site
|
||||||
|
if not site.settings["own"]: return self.response(to, "Forbidden, you can only modify your own sites")
|
||||||
|
|
||||||
|
# Signing
|
||||||
|
site.loadContent(True) # Reload content.json, ignore errors to make it up-to-date
|
||||||
|
signed = site.signContent(params[0]) # Sign using private key sent by user
|
||||||
|
if signed:
|
||||||
|
self.cmd("notification", ["done", "Private key correct, site signed!", 5000]) # Display message for 5 sec
|
||||||
|
else:
|
||||||
|
self.cmd("notification", ["error", "Site sign failed: invalid private key."])
|
||||||
|
self.response(to, "Site sign failed")
|
||||||
|
return
|
||||||
|
site.loadContent(True) # Load new content.json, ignore errors
|
||||||
|
|
||||||
|
# Publishing
|
||||||
|
if not site.settings["serving"]: # Enable site if paused
|
||||||
|
site.settings["serving"] = True
|
||||||
|
site.saveSettings()
|
||||||
|
site.announce()
|
||||||
|
|
||||||
|
published = site.publish(5) # Publish to 5 peer
|
||||||
|
|
||||||
|
if published>0: # Successfuly published
|
||||||
|
self.cmd("notification", ["done", "Site published to %s peers." % published, 5000])
|
||||||
|
self.response(to, "ok")
|
||||||
|
site.updateWebsocket() # Send updated site data to local websocket clients
|
||||||
|
else:
|
||||||
|
if len(site.peers) == 0:
|
||||||
|
self.cmd("notification", ["info", "No peers found, but your site is ready to access."])
|
||||||
|
self.response(to, "No peers found, but your site is ready to access.")
|
||||||
|
else:
|
||||||
|
self.cmd("notification", ["error", "Site publish failed."])
|
||||||
|
self.response(to, "Site publish failed.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Write a file to disk
|
||||||
|
def actionFileWrite(self, to, params):
|
||||||
|
if not self.site.settings["own"]: return self.response(to, "Forbidden, you can only modify your own sites")
|
||||||
|
try:
|
||||||
|
import base64
|
||||||
|
content = base64.b64decode(params[1])
|
||||||
|
open(self.site.getPath(params[0]), "wb").write(content)
|
||||||
|
except Exception, err:
|
||||||
|
return self.response(to, "Write error: %s" % err)
|
||||||
|
|
||||||
|
return self.response(to, "ok")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# - Admin actions -
|
# - Admin actions -
|
||||||
|
|
||||||
# List all site info
|
# List all site info
|
||||||
|
|
|
@ -23,6 +23,9 @@ class Wrapper
|
||||||
@site_error = null # Latest failed file download
|
@site_error = null # Latest failed file download
|
||||||
|
|
||||||
window.onload = @onLoad # On iframe loaded
|
window.onload = @onLoad # On iframe loaded
|
||||||
|
$(window).on "hashchange", -> # On hash change
|
||||||
|
src = $("#inner-iframe").attr("src").replace(/#.*/, "")+window.location.hash
|
||||||
|
$("#inner-iframe").attr("src", src)
|
||||||
@
|
@
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +63,8 @@ class Wrapper
|
||||||
@notifications.add("notification-#{message.id}", message.params[0], message.params[1], message.params[2])
|
@notifications.add("notification-#{message.id}", message.params[0], message.params[1], message.params[2])
|
||||||
else if cmd == "wrapperConfirm" # Display confirm message
|
else if cmd == "wrapperConfirm" # Display confirm message
|
||||||
@actionWrapperConfirm(message)
|
@actionWrapperConfirm(message)
|
||||||
|
else if cmd == "wrapperPrompt" # Prompt input
|
||||||
|
@actionWrapperPrompt(message)
|
||||||
else # Send to websocket
|
else # Send to websocket
|
||||||
@ws.send(message) # Pass message to websocket
|
@ws.send(message) # Pass message to websocket
|
||||||
|
|
||||||
|
@ -80,6 +85,30 @@ class Wrapper
|
||||||
@notifications.add("notification-#{message.id}", "ask", body)
|
@notifications.add("notification-#{message.id}", "ask", body)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
actionWrapperPrompt: (message) ->
|
||||||
|
message.params = @toHtmlSafe(message.params) # Escape html
|
||||||
|
if message.params[1] then type = message.params[1] else type = "text"
|
||||||
|
caption = "OK"
|
||||||
|
|
||||||
|
body = $("<span>"+message.params[0]+"</span>")
|
||||||
|
|
||||||
|
input = $("<input type='#{type}' class='input button-#{type}'/>") # Add input
|
||||||
|
input.on "keyup", (e) => # Send on enter
|
||||||
|
if e.keyCode == 13
|
||||||
|
@sendInner {"cmd": "response", "to": message.id, "result": input.val()} # Response to confirm
|
||||||
|
body.append(input)
|
||||||
|
|
||||||
|
button = $("<a href='##{caption}' class='button button-#{caption}'>#{caption}</a>") # Add confirm button
|
||||||
|
button.on "click", => # Response on button click
|
||||||
|
@sendInner {"cmd": "response", "to": message.id, "result": input.val()} # Response to confirm
|
||||||
|
return false
|
||||||
|
body.append(button)
|
||||||
|
|
||||||
|
|
||||||
|
@notifications.add("notification-#{message.id}", "ask", body)
|
||||||
|
|
||||||
|
|
||||||
onOpenWebsocket: (e) =>
|
onOpenWebsocket: (e) =>
|
||||||
@ws.cmd "channelJoin", {"channel": "siteChanged"} # Get info on modifications
|
@ws.cmd "channelJoin", {"channel": "siteChanged"} # Get info on modifications
|
||||||
@log "onOpenWebsocket", @inner_ready, @wrapperWsInited
|
@log "onOpenWebsocket", @inner_ready, @wrapperWsInited
|
||||||
|
@ -112,10 +141,11 @@ class Wrapper
|
||||||
|
|
||||||
# Iframe loaded
|
# Iframe loaded
|
||||||
onLoad: (e) =>
|
onLoad: (e) =>
|
||||||
@log "onLoad", e
|
@log "onLoad"
|
||||||
@inner_loaded = true
|
@inner_loaded = true
|
||||||
if not @inner_ready then @sendInner {"cmd": "wrapperReady"} # Inner frame loaded before wrapper
|
if not @inner_ready then @sendInner {"cmd": "wrapperReady"} # Inner frame loaded before wrapper
|
||||||
if not @site_error then @loading.hideScreen() # Hide loading screen
|
if not @site_error then @loading.hideScreen() # Hide loading screen
|
||||||
|
if window.location.hash then $("#inner-iframe")[0].src += window.location.hash # Hash tag
|
||||||
if @ws.ws.readyState == 1 and not @site_info # Ws opened
|
if @ws.ws.readyState == 1 and not @site_info # Ws opened
|
||||||
@reloadSiteInfo()
|
@reloadSiteInfo()
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ a { color: black }
|
||||||
.notifications { position: absolute; top: 0px; right: 85px; display: inline-block; z-index: 999; white-space: nowrap }
|
.notifications { position: absolute; top: 0px; right: 85px; display: inline-block; z-index: 999; white-space: nowrap }
|
||||||
.notification {
|
.notification {
|
||||||
position: relative; float: right; clear: both; margin: 10px; height: 50px; box-sizing: border-box; overflow: hidden; backface-visibility: hidden; perspective: 1000px;
|
position: relative; float: right; clear: both; margin: 10px; height: 50px; box-sizing: border-box; overflow: hidden; backface-visibility: hidden; perspective: 1000px;
|
||||||
background-color: white; color: #4F4F4F; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px
|
background-color: white; color: #4F4F4F; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; /*border: 1px solid rgba(210, 206, 205, 0.2)*/
|
||||||
}
|
}
|
||||||
.notification-icon {
|
.notification-icon {
|
||||||
display: block; width: 50px; height: 50px; position: absolute; float: left; z-index: 1;
|
display: block; width: 50px; height: 50px; position: absolute; float: left; z-index: 1;
|
||||||
|
@ -53,6 +53,9 @@ a { color: black }
|
||||||
.notification-info .notification-icon { font-size: 22px; font-weight: bold; background-color: #2980b9; line-height: 48px }
|
.notification-info .notification-icon { font-size: 22px; font-weight: bold; background-color: #2980b9; line-height: 48px }
|
||||||
.notification-done .notification-icon { font-size: 22px; background-color: #27ae60 }
|
.notification-done .notification-icon { font-size: 22px; background-color: #27ae60 }
|
||||||
|
|
||||||
|
/* Notification input */
|
||||||
|
.notification .input { padding: 6px; border: 1px solid #DDD; margin-left: 10px; border-bottom: 2px solid #DDD; border-radius: 1px; margin-right: -11px; transition: all 0.3s }
|
||||||
|
.notification .input:focus { border-color: #95a5a6; outline: none }
|
||||||
|
|
||||||
/* Icons (based on http://nicolasgallagher.com/pure-css-gui-icons/demo/) */
|
/* Icons (based on http://nicolasgallagher.com/pure-css-gui-icons/demo/) */
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ a { color: black }
|
||||||
.notifications { position: absolute; top: 0px; right: 85px; display: inline-block; z-index: 999; white-space: nowrap }
|
.notifications { position: absolute; top: 0px; right: 85px; display: inline-block; z-index: 999; white-space: nowrap }
|
||||||
.notification {
|
.notification {
|
||||||
position: relative; float: right; clear: both; margin: 10px; height: 50px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -o-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box ; overflow: hidden; backface-visibility: hidden; -webkit-perspective: 1000px; -moz-perspective: 1000px; -o-perspective: 1000px; -ms-perspective: 1000px; perspective: 1000px ;
|
position: relative; float: right; clear: both; margin: 10px; height: 50px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -o-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box ; overflow: hidden; backface-visibility: hidden; -webkit-perspective: 1000px; -moz-perspective: 1000px; -o-perspective: 1000px; -ms-perspective: 1000px; perspective: 1000px ;
|
||||||
background-color: white; color: #4F4F4F; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px
|
background-color: white; color: #4F4F4F; font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; /*border: 1px solid rgba(210, 206, 205, 0.2)*/
|
||||||
}
|
}
|
||||||
.notification-icon {
|
.notification-icon {
|
||||||
display: block; width: 50px; height: 50px; position: absolute; float: left; z-index: 1;
|
display: block; width: 50px; height: 50px; position: absolute; float: left; z-index: 1;
|
||||||
|
@ -58,6 +58,9 @@ a { color: black }
|
||||||
.notification-info .notification-icon { font-size: 22px; font-weight: bold; background-color: #2980b9; line-height: 48px }
|
.notification-info .notification-icon { font-size: 22px; font-weight: bold; background-color: #2980b9; line-height: 48px }
|
||||||
.notification-done .notification-icon { font-size: 22px; background-color: #27ae60 }
|
.notification-done .notification-icon { font-size: 22px; background-color: #27ae60 }
|
||||||
|
|
||||||
|
/* Notification input */
|
||||||
|
.notification .input { padding: 6px; border: 1px solid #DDD; margin-left: 10px; border-bottom: 2px solid #DDD; -webkit-border-radius: 1px; -moz-border-radius: 1px; -o-border-radius: 1px; -ms-border-radius: 1px; border-radius: 1px ; margin-right: -11px; -webkit-transition: all 0.3s ; -moz-transition: all 0.3s ; -o-transition: all 0.3s ; -ms-transition: all 0.3s ; transition: all 0.3s }
|
||||||
|
.notification .input:focus { border-color: #95a5a6; outline: none }
|
||||||
|
|
||||||
/* Icons (based on http://nicolasgallagher.com/pure-css-gui-icons/demo/) */
|
/* Icons (based on http://nicolasgallagher.com/pure-css-gui-icons/demo/) */
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
ZeroWebsocket.prototype.onOpenWebsocket = function(e) {
|
ZeroWebsocket.prototype.onOpenWebsocket = function(e) {
|
||||||
this.log("Open", e);
|
this.log("Open");
|
||||||
if (this.onOpen != null) {
|
if (this.onOpen != null) {
|
||||||
return this.onOpen(e);
|
return this.onOpen(e);
|
||||||
}
|
}
|
||||||
|
@ -743,6 +743,11 @@ jQuery.extend( jQuery.easing,
|
||||||
this.wrapperWsInited = false;
|
this.wrapperWsInited = false;
|
||||||
this.site_error = null;
|
this.site_error = null;
|
||||||
window.onload = this.onLoad;
|
window.onload = this.onLoad;
|
||||||
|
$(window).on("hashchange", function() {
|
||||||
|
var src;
|
||||||
|
src = $("#inner-iframe").attr("src").replace(/#.*/, "") + window.location.hash;
|
||||||
|
return $("#inner-iframe").attr("src", src);
|
||||||
|
});
|
||||||
this;
|
this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,6 +791,8 @@ jQuery.extend( jQuery.easing,
|
||||||
return this.notifications.add("notification-" + message.id, message.params[0], message.params[1], message.params[2]);
|
return this.notifications.add("notification-" + message.id, message.params[0], message.params[1], message.params[2]);
|
||||||
} else if (cmd === "wrapperConfirm") {
|
} else if (cmd === "wrapperConfirm") {
|
||||||
return this.actionWrapperConfirm(message);
|
return this.actionWrapperConfirm(message);
|
||||||
|
} else if (cmd === "wrapperPrompt") {
|
||||||
|
return this.actionWrapperPrompt(message);
|
||||||
} else {
|
} else {
|
||||||
return this.ws.send(message);
|
return this.ws.send(message);
|
||||||
}
|
}
|
||||||
|
@ -815,6 +822,44 @@ jQuery.extend( jQuery.easing,
|
||||||
return this.notifications.add("notification-" + message.id, "ask", body);
|
return this.notifications.add("notification-" + message.id, "ask", body);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Wrapper.prototype.actionWrapperPrompt = function(message) {
|
||||||
|
var body, button, caption, input, type;
|
||||||
|
message.params = this.toHtmlSafe(message.params);
|
||||||
|
if (message.params[1]) {
|
||||||
|
type = message.params[1];
|
||||||
|
} else {
|
||||||
|
type = "text";
|
||||||
|
}
|
||||||
|
caption = "OK";
|
||||||
|
body = $("<span>" + message.params[0] + "</span>");
|
||||||
|
input = $("<input type='" + type + "' class='input button-" + type + "'/>");
|
||||||
|
input.on("keyup", (function(_this) {
|
||||||
|
return function(e) {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
return _this.sendInner({
|
||||||
|
"cmd": "response",
|
||||||
|
"to": message.id,
|
||||||
|
"result": input.val()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
body.append(input);
|
||||||
|
button = $("<a href='#" + caption + "' class='button button-" + caption + "'>" + caption + "</a>");
|
||||||
|
button.on("click", (function(_this) {
|
||||||
|
return function() {
|
||||||
|
_this.sendInner({
|
||||||
|
"cmd": "response",
|
||||||
|
"to": message.id,
|
||||||
|
"result": input.val()
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
})(this));
|
||||||
|
body.append(button);
|
||||||
|
return this.notifications.add("notification-" + message.id, "ask", body);
|
||||||
|
};
|
||||||
|
|
||||||
Wrapper.prototype.onOpenWebsocket = function(e) {
|
Wrapper.prototype.onOpenWebsocket = function(e) {
|
||||||
this.ws.cmd("channelJoin", {
|
this.ws.cmd("channelJoin", {
|
||||||
"channel": "siteChanged"
|
"channel": "siteChanged"
|
||||||
|
@ -859,7 +904,7 @@ jQuery.extend( jQuery.easing,
|
||||||
};
|
};
|
||||||
|
|
||||||
Wrapper.prototype.onLoad = function(e) {
|
Wrapper.prototype.onLoad = function(e) {
|
||||||
this.log("onLoad", e);
|
this.log("onLoad");
|
||||||
this.inner_loaded = true;
|
this.inner_loaded = true;
|
||||||
if (!this.inner_ready) {
|
if (!this.inner_ready) {
|
||||||
this.sendInner({
|
this.sendInner({
|
||||||
|
@ -869,6 +914,9 @@ jQuery.extend( jQuery.easing,
|
||||||
if (!this.site_error) {
|
if (!this.site_error) {
|
||||||
this.loading.hideScreen();
|
this.loading.hideScreen();
|
||||||
}
|
}
|
||||||
|
if (window.location.hash) {
|
||||||
|
$("#inner-iframe")[0].src += window.location.hash;
|
||||||
|
}
|
||||||
if (this.ws.ws.readyState === 1 && !this.site_info) {
|
if (this.ws.ws.readyState === 1 && !this.site_info) {
|
||||||
return this.reloadSiteInfo();
|
return this.reloadSiteInfo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ class ZeroWebsocket
|
||||||
|
|
||||||
|
|
||||||
onOpenWebsocket: (e) =>
|
onOpenWebsocket: (e) =>
|
||||||
@log "Open", e
|
@log "Open"
|
||||||
if @onOpen? then @onOpen(e)
|
if @onOpen? then @onOpen(e)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||||
<link rel="stylesheet" href="/uimedia/all.css" />
|
<link rel="stylesheet" href="/uimedia/all.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body style="{body_style}">
|
||||||
|
|
||||||
<!-- Fixed button -->
|
<!-- Fixed button -->
|
||||||
<div class='fixbutton'>
|
<div class='fixbutton'>
|
||||||
|
@ -35,8 +35,7 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- Site Iframe -->
|
<!-- Site Iframe -->
|
||||||
<iframe src='/media/{address}/{inner_path}' id='inner-iframe' sandbox="allow-forms allow-scripts allow-top-navigation"></iframe>
|
<iframe src='/media/{address}/{inner_path}{query_string}' id='inner-iframe' sandbox="allow-forms allow-scripts allow-top-navigation"></iframe>
|
||||||
|
|
||||||
|
|
||||||
<!-- Site info -->
|
<!-- Site info -->
|
||||||
<script>address = "{address}"</script>
|
<script>address = "{address}"</script>
|
||||||
|
|
Loading…
Reference in a new issue