[cleanup] remove coffee script files
This commit is contained in:
parent
fee2a4f2c9
commit
574928e625
50 changed files with 0 additions and 4951 deletions
|
@ -1,222 +0,0 @@
|
|||
class ConfigStorage extends Class
|
||||
constructor: (@config) ->
|
||||
@items = []
|
||||
@createSections()
|
||||
@setValues(@config)
|
||||
|
||||
setValues: (values) ->
|
||||
for section in @items
|
||||
for item in section.items
|
||||
if not values[item.key]
|
||||
continue
|
||||
item.value = @formatValue(values[item.key].value)
|
||||
item.default = @formatValue(values[item.key].default)
|
||||
item.pending = values[item.key].pending
|
||||
values[item.key].item = item
|
||||
|
||||
formatValue: (value) ->
|
||||
if not value
|
||||
return false
|
||||
else if typeof(value) == "object"
|
||||
return value.join("\n")
|
||||
else if typeof(value) == "number"
|
||||
return value.toString()
|
||||
else
|
||||
return value
|
||||
|
||||
deformatValue: (value, type) ->
|
||||
if type == "object" and typeof(value) == "string"
|
||||
if not value.length
|
||||
return value = null
|
||||
else
|
||||
return value.split("\n")
|
||||
if type == "boolean" and not value
|
||||
return false
|
||||
else if type == "number"
|
||||
if typeof(value) == "number"
|
||||
return value.toString()
|
||||
else if not value
|
||||
return "0"
|
||||
else
|
||||
return value
|
||||
else
|
||||
return value
|
||||
|
||||
createSections: ->
|
||||
# Web Interface
|
||||
section = @createSection("Web Interface")
|
||||
|
||||
section.items.push
|
||||
key: "open_browser"
|
||||
title: "Open web browser on ZeroNet startup"
|
||||
type: "checkbox"
|
||||
|
||||
# Network
|
||||
section = @createSection("Network")
|
||||
section.items.push
|
||||
key: "offline"
|
||||
title: "Offline mode"
|
||||
type: "checkbox"
|
||||
description: "Disable network communication."
|
||||
|
||||
section.items.push
|
||||
key: "fileserver_ip_type"
|
||||
title: "File server network"
|
||||
type: "select"
|
||||
options: [
|
||||
{title: "IPv4", value: "ipv4"}
|
||||
{title: "IPv6", value: "ipv6"}
|
||||
{title: "Dual (IPv4 & IPv6)", value: "dual"}
|
||||
]
|
||||
description: "Accept incoming peers using IPv4 or IPv6 address. (default: dual)"
|
||||
|
||||
section.items.push
|
||||
key: "fileserver_port"
|
||||
title: "File server port"
|
||||
type: "text"
|
||||
valid_pattern: /[0-9]*/
|
||||
description: "Other peers will use this port to reach your served sites. (default: randomize)"
|
||||
|
||||
section.items.push
|
||||
key: "ip_external"
|
||||
title: "File server external ip"
|
||||
type: "textarea"
|
||||
placeholder: "Detect automatically"
|
||||
description: "Your file server is accessible on these ips. (default: detect automatically)"
|
||||
|
||||
section.items.push
|
||||
title: "Tor"
|
||||
key: "tor"
|
||||
type: "select"
|
||||
options: [
|
||||
{title: "Disable", value: "disable"}
|
||||
{title: "Enable", value: "enable"}
|
||||
{title: "Always", value: "always"}
|
||||
]
|
||||
description: [
|
||||
"Disable: Don't connect to peers on Tor network", h("br"),
|
||||
"Enable: Only use Tor for Tor network peers", h("br"),
|
||||
"Always: Use Tor for every connections to hide your IP address (slower)"
|
||||
]
|
||||
|
||||
section.items.push
|
||||
title: "Use Tor bridges"
|
||||
key: "tor_use_bridges"
|
||||
type: "checkbox"
|
||||
description: "Use obfuscated bridge relays to avoid network level Tor block (even slower)"
|
||||
isHidden: ->
|
||||
return not Page.server_info.tor_has_meek_bridges
|
||||
|
||||
section.items.push
|
||||
title: "Trackers"
|
||||
key: "trackers"
|
||||
type: "textarea"
|
||||
description: "Discover new peers using these adresses"
|
||||
|
||||
section.items.push
|
||||
title: "Trackers files"
|
||||
key: "trackers_file"
|
||||
type: "textarea"
|
||||
description: "Load additional list of torrent trackers dynamically, from a file"
|
||||
placeholder: "Eg.: {data_dir}/trackers.json"
|
||||
value_pos: "fullwidth"
|
||||
|
||||
section.items.push
|
||||
title: "Proxy for tracker connections"
|
||||
key: "trackers_proxy"
|
||||
type: "select"
|
||||
options: [
|
||||
{title: "Custom", value: ""}
|
||||
{title: "Tor", value: "tor"}
|
||||
{title: "Disable", value: "disable"}
|
||||
]
|
||||
isHidden: ->
|
||||
Page.values["tor"] == "always"
|
||||
|
||||
section.items.push
|
||||
title: "Custom socks proxy address for trackers"
|
||||
key: "trackers_proxy"
|
||||
type: "text"
|
||||
placeholder: "Eg.: 127.0.0.1:1080"
|
||||
value_pos: "fullwidth"
|
||||
valid_pattern: /.+:[0-9]+/
|
||||
isHidden: =>
|
||||
Page.values["trackers_proxy"] in ["tor", "disable"]
|
||||
|
||||
# Performance
|
||||
section = @createSection("Performance")
|
||||
|
||||
section.items.push
|
||||
key: "log_level"
|
||||
title: "Level of logging to file"
|
||||
type: "select"
|
||||
options: [
|
||||
{title: "Everything", value: "DEBUG"}
|
||||
{title: "Only important messages", value: "INFO"}
|
||||
{title: "Only errors", value: "ERROR"}
|
||||
]
|
||||
|
||||
section.items.push
|
||||
key: "threads_fs_read"
|
||||
title: "Threads for async file system reads"
|
||||
type: "select"
|
||||
options: [
|
||||
{title: "Sync read", value: 0}
|
||||
{title: "1 thread", value: 1}
|
||||
{title: "2 threads", value: 2}
|
||||
{title: "3 threads", value: 3}
|
||||
{title: "4 threads", value: 4}
|
||||
{title: "5 threads", value: 5}
|
||||
{title: "10 threads", value: 10}
|
||||
]
|
||||
|
||||
section.items.push
|
||||
key: "threads_fs_write"
|
||||
title: "Threads for async file system writes"
|
||||
type: "select"
|
||||
options: [
|
||||
{title: "Sync write", value: 0}
|
||||
{title: "1 thread", value: 1}
|
||||
{title: "2 threads", value: 2}
|
||||
{title: "3 threads", value: 3}
|
||||
{title: "4 threads", value: 4}
|
||||
{title: "5 threads", value: 5}
|
||||
{title: "10 threads", value: 10}
|
||||
]
|
||||
|
||||
section.items.push
|
||||
key: "threads_crypt"
|
||||
title: "Threads for cryptographic functions"
|
||||
type: "select"
|
||||
options: [
|
||||
{title: "Sync execution", value: 0}
|
||||
{title: "1 thread", value: 1}
|
||||
{title: "2 threads", value: 2}
|
||||
{title: "3 threads", value: 3}
|
||||
{title: "4 threads", value: 4}
|
||||
{title: "5 threads", value: 5}
|
||||
{title: "10 threads", value: 10}
|
||||
]
|
||||
|
||||
section.items.push
|
||||
key: "threads_db"
|
||||
title: "Threads for database operations"
|
||||
type: "select"
|
||||
options: [
|
||||
{title: "Sync execution", value: 0}
|
||||
{title: "1 thread", value: 1}
|
||||
{title: "2 threads", value: 2}
|
||||
{title: "3 threads", value: 3}
|
||||
{title: "4 threads", value: 4}
|
||||
{title: "5 threads", value: 5}
|
||||
{title: "10 threads", value: 10}
|
||||
]
|
||||
|
||||
createSection: (title) =>
|
||||
section = {}
|
||||
section.title = title
|
||||
section.items = []
|
||||
@items.push(section)
|
||||
return section
|
||||
|
||||
window.ConfigStorage = ConfigStorage
|
|
@ -1,124 +0,0 @@
|
|||
class ConfigView extends Class
|
||||
constructor: () ->
|
||||
@
|
||||
|
||||
render: ->
|
||||
@config_storage.items.map @renderSection
|
||||
|
||||
renderSection: (section) =>
|
||||
h("div.section", {key: section.title}, [
|
||||
h("h2", section.title),
|
||||
h("div.config-items", section.items.map @renderSectionItem)
|
||||
])
|
||||
|
||||
handleResetClick: (e) =>
|
||||
node = e.currentTarget
|
||||
config_key = node.attributes.config_key.value
|
||||
default_value = node.attributes.default_value?.value
|
||||
Page.cmd "wrapperConfirm", ["Reset #{config_key} value?", "Reset to default"], (res) =>
|
||||
if (res)
|
||||
@values[config_key] = default_value
|
||||
Page.projector.scheduleRender()
|
||||
|
||||
renderSectionItem: (item) =>
|
||||
value_pos = item.value_pos
|
||||
|
||||
if item.type == "textarea"
|
||||
value_pos ?= "fullwidth"
|
||||
else
|
||||
value_pos ?= "right"
|
||||
|
||||
value_changed = @config_storage.formatValue(@values[item.key]) != item.value
|
||||
value_default = @config_storage.formatValue(@values[item.key]) == item.default
|
||||
|
||||
if item.key in ["open_browser", "fileserver_port"] # Value default for some settings makes no sense
|
||||
value_default = true
|
||||
|
||||
marker_title = "Changed from default value: #{item.default} -> #{@values[item.key]}"
|
||||
if item.pending
|
||||
marker_title += " (change pending until client restart)"
|
||||
|
||||
if item.isHidden?()
|
||||
return null
|
||||
|
||||
h("div.config-item", {key: item.title, enterAnimation: Animation.slideDown, exitAnimation: Animation.slideUpInout}, [
|
||||
h("div.title", [
|
||||
h("h3", item.title),
|
||||
h("div.description", item.description)
|
||||
])
|
||||
h("div.value.value-#{value_pos}",
|
||||
if item.type == "select"
|
||||
@renderValueSelect(item)
|
||||
else if item.type == "checkbox"
|
||||
@renderValueCheckbox(item)
|
||||
else if item.type == "textarea"
|
||||
@renderValueTextarea(item)
|
||||
else
|
||||
@renderValueText(item)
|
||||
h("a.marker", {
|
||||
href: "#Reset", title: marker_title,
|
||||
onclick: @handleResetClick, config_key: item.key, default_value: item.default,
|
||||
classes: {default: value_default, changed: value_changed, visible: not value_default or value_changed or item.pending, pending: item.pending}
|
||||
}, "\u2022")
|
||||
)
|
||||
])
|
||||
|
||||
# Values
|
||||
handleInputChange: (e) =>
|
||||
node = e.target
|
||||
config_key = node.attributes.config_key.value
|
||||
@values[config_key] = node.value
|
||||
Page.projector.scheduleRender()
|
||||
|
||||
handleCheckboxChange: (e) =>
|
||||
node = e.currentTarget
|
||||
config_key = node.attributes.config_key.value
|
||||
value = not node.classList.contains("checked")
|
||||
@values[config_key] = value
|
||||
Page.projector.scheduleRender()
|
||||
|
||||
renderValueText: (item) =>
|
||||
value = @values[item.key]
|
||||
if not value
|
||||
value = ""
|
||||
h("input.input-#{item.type}", {type: item.type, config_key: item.key, value: value, placeholder: item.placeholder, oninput: @handleInputChange})
|
||||
|
||||
autosizeTextarea: (e) =>
|
||||
if e.currentTarget
|
||||
# @handleInputChange(e)
|
||||
node = e.currentTarget
|
||||
else
|
||||
node = e
|
||||
height_before = node.style.height
|
||||
if height_before
|
||||
node.style.height = "0px"
|
||||
h = node.offsetHeight
|
||||
scrollh = node.scrollHeight + 20
|
||||
if scrollh > h
|
||||
node.style.height = scrollh + "px"
|
||||
else
|
||||
node.style.height = height_before
|
||||
|
||||
renderValueTextarea: (item) =>
|
||||
value = @values[item.key]
|
||||
if not value
|
||||
value = ""
|
||||
h("textarea.input-#{item.type}.input-text",{
|
||||
type: item.type, config_key: item.key, oninput: @handleInputChange, afterCreate: @autosizeTextarea,
|
||||
updateAnimation: @autosizeTextarea, value: value, placeholder: item.placeholder
|
||||
})
|
||||
|
||||
renderValueCheckbox: (item) =>
|
||||
if @values[item.key] and @values[item.key] != "False"
|
||||
checked = true
|
||||
else
|
||||
checked = false
|
||||
h("div.checkbox", {onclick: @handleCheckboxChange, config_key: item.key, classes: {checked: checked}}, h("div.checkbox-skin"))
|
||||
|
||||
renderValueSelect: (item) =>
|
||||
h("select.input-select", {config_key: item.key, oninput: @handleInputChange},
|
||||
item.options.map (option) =>
|
||||
h("option", {selected: option.value.toString() == @values[item.key], value: option.value}, option.title)
|
||||
)
|
||||
|
||||
window.ConfigView = ConfigView
|
|
@ -1,129 +0,0 @@
|
|||
window.h = maquette.h
|
||||
|
||||
class UiConfig extends ZeroFrame
|
||||
init: ->
|
||||
@save_visible = true
|
||||
@config = null # Setting currently set on the server
|
||||
@values = null # Entered values on the page
|
||||
@config_view = new ConfigView()
|
||||
window.onbeforeunload = =>
|
||||
if @getValuesChanged().length > 0
|
||||
return true
|
||||
else
|
||||
return null
|
||||
|
||||
onOpenWebsocket: =>
|
||||
@cmd("wrapperSetTitle", "Config - ZeroNet")
|
||||
@cmd "serverInfo", {}, (server_info) =>
|
||||
@server_info = server_info
|
||||
@restart_loading = false
|
||||
@updateConfig()
|
||||
|
||||
updateConfig: (cb) =>
|
||||
@cmd "configList", [], (res) =>
|
||||
@config = res
|
||||
@values = {}
|
||||
@config_storage = new ConfigStorage(@config)
|
||||
@config_view.values = @values
|
||||
@config_view.config_storage = @config_storage
|
||||
for key, item of res
|
||||
value = item.value
|
||||
@values[key] = @config_storage.formatValue(value)
|
||||
@projector.scheduleRender()
|
||||
cb?()
|
||||
|
||||
createProjector: =>
|
||||
@projector = maquette.createProjector()
|
||||
@projector.replace($("#content"), @render)
|
||||
@projector.replace($("#bottom-save"), @renderBottomSave)
|
||||
@projector.replace($("#bottom-restart"), @renderBottomRestart)
|
||||
|
||||
getValuesChanged: =>
|
||||
values_changed = []
|
||||
for key, value of @values
|
||||
if @config_storage.formatValue(value) != @config_storage.formatValue(@config[key]?.value)
|
||||
values_changed.push({key: key, value: value})
|
||||
return values_changed
|
||||
|
||||
getValuesPending: =>
|
||||
values_pending = []
|
||||
for key, item of @config
|
||||
if item.pending
|
||||
values_pending.push(key)
|
||||
return values_pending
|
||||
|
||||
saveValues: (cb) =>
|
||||
changed_values = @getValuesChanged()
|
||||
for item, i in changed_values
|
||||
last = i == changed_values.length - 1
|
||||
value = @config_storage.deformatValue(item.value, typeof(@config[item.key].default))
|
||||
default_value = @config_storage.deformatValue(@config[item.key].default, typeof(@config[item.key].default))
|
||||
value_same_as_default = JSON.stringify(default_value) == JSON.stringify(value)
|
||||
|
||||
if @config[item.key].item.valid_pattern and not @config[item.key].item.isHidden?()
|
||||
match = value.match(@config[item.key].item.valid_pattern)
|
||||
if not match or match[0] != value
|
||||
message = "Invalid value of #{@config[item.key].item.title}: #{value} (does not matches #{@config[item.key].item.valid_pattern})"
|
||||
Page.cmd("wrapperNotification", ["error", message])
|
||||
cb(false)
|
||||
break
|
||||
|
||||
if value_same_as_default
|
||||
value = null
|
||||
|
||||
@saveValue(item.key, value, if last then cb else null)
|
||||
|
||||
saveValue: (key, value, cb) =>
|
||||
if key == "open_browser"
|
||||
if value
|
||||
value = "default_browser"
|
||||
else
|
||||
value = "False"
|
||||
|
||||
Page.cmd "configSet", [key, value], (res) =>
|
||||
if res != "ok"
|
||||
Page.cmd "wrapperNotification", ["error", res.error]
|
||||
cb?(true)
|
||||
|
||||
render: =>
|
||||
if not @config
|
||||
return h("div.content")
|
||||
|
||||
h("div.content", [
|
||||
@config_view.render()
|
||||
])
|
||||
|
||||
handleSaveClick: =>
|
||||
@save_loading = true
|
||||
@logStart "Save"
|
||||
@saveValues (success) =>
|
||||
@save_loading = false
|
||||
@logEnd "Save"
|
||||
if success
|
||||
@updateConfig()
|
||||
Page.projector.scheduleRender()
|
||||
return false
|
||||
|
||||
renderBottomSave: =>
|
||||
values_changed = @getValuesChanged()
|
||||
h("div.bottom.bottom-save", {classes: {visible: values_changed.length}}, h("div.bottom-content", [
|
||||
h("div.title", "#{values_changed.length} configuration item value changed"),
|
||||
h("a.button.button-submit.button-save", {href: "#Save", classes: {loading: @save_loading}, onclick: @handleSaveClick}, "Save settings")
|
||||
]))
|
||||
|
||||
handleRestartClick: =>
|
||||
@restart_loading = true
|
||||
Page.cmd("serverShutdown", {restart: true})
|
||||
Page.projector.scheduleRender()
|
||||
return false
|
||||
|
||||
renderBottomRestart: =>
|
||||
values_pending = @getValuesPending()
|
||||
values_changed = @getValuesChanged()
|
||||
h("div.bottom.bottom-restart", {classes: {visible: values_pending.length and not values_changed.length}}, h("div.bottom-content", [
|
||||
h("div.title", "Some changed settings requires restart"),
|
||||
h("a.button.button-submit.button-restart", {href: "#Restart", classes: {loading: @restart_loading}, onclick: @handleRestartClick}, "Restart ZeroNet client")
|
||||
]))
|
||||
|
||||
window.Page = new UiConfig()
|
||||
window.Page.createProjector()
|
|
@ -1,23 +0,0 @@
|
|||
class Class
|
||||
trace: true
|
||||
|
||||
log: (args...) ->
|
||||
return unless @trace
|
||||
return if typeof console is 'undefined'
|
||||
args.unshift("[#{@.constructor.name}]")
|
||||
console.log(args...)
|
||||
@
|
||||
|
||||
logStart: (name, args...) ->
|
||||
return unless @trace
|
||||
@logtimers or= {}
|
||||
@logtimers[name] = +(new Date)
|
||||
@log "#{name}", args..., "(started)" if args.length > 0
|
||||
@
|
||||
|
||||
logEnd: (name, args...) ->
|
||||
ms = +(new Date)-@logtimers[name]
|
||||
@log "#{name}", args..., "(Done in #{ms}ms)"
|
||||
@
|
||||
|
||||
window.Class = Class
|
|
@ -1,74 +0,0 @@
|
|||
# From: http://dev.bizo.com/2011/12/promises-in-javascriptcoffeescript.html
|
||||
|
||||
class Promise
|
||||
@when: (tasks...) ->
|
||||
num_uncompleted = tasks.length
|
||||
args = new Array(num_uncompleted)
|
||||
promise = new Promise()
|
||||
|
||||
for task, task_id in tasks
|
||||
((task_id) ->
|
||||
task.then(() ->
|
||||
args[task_id] = Array.prototype.slice.call(arguments)
|
||||
num_uncompleted--
|
||||
promise.complete.apply(promise, args) if num_uncompleted == 0
|
||||
)
|
||||
)(task_id)
|
||||
|
||||
return promise
|
||||
|
||||
constructor: ->
|
||||
@resolved = false
|
||||
@end_promise = null
|
||||
@result = null
|
||||
@callbacks = []
|
||||
|
||||
resolve: ->
|
||||
if @resolved
|
||||
return false
|
||||
@resolved = true
|
||||
@data = arguments
|
||||
if not arguments.length
|
||||
@data = [true]
|
||||
@result = @data[0]
|
||||
for callback in @callbacks
|
||||
back = callback.apply callback, @data
|
||||
if @end_promise
|
||||
@end_promise.resolve(back)
|
||||
|
||||
fail: ->
|
||||
@resolve(false)
|
||||
|
||||
then: (callback) ->
|
||||
if @resolved == true
|
||||
callback.apply callback, @data
|
||||
return
|
||||
|
||||
@callbacks.push callback
|
||||
|
||||
@end_promise = new Promise()
|
||||
|
||||
window.Promise = Promise
|
||||
|
||||
###
|
||||
s = Date.now()
|
||||
log = (text) ->
|
||||
console.log Date.now()-s, Array.prototype.slice.call(arguments).join(", ")
|
||||
|
||||
log "Started"
|
||||
|
||||
cmd = (query) ->
|
||||
p = new Promise()
|
||||
setTimeout ( ->
|
||||
p.resolve query+" Result"
|
||||
), 100
|
||||
return p
|
||||
|
||||
back = cmd("SELECT * FROM message").then (res) ->
|
||||
log res
|
||||
return "Return from query"
|
||||
.then (res) ->
|
||||
log "Back then", res
|
||||
|
||||
log "Query started", back
|
||||
###
|
|
@ -1,8 +0,0 @@
|
|||
String::startsWith = (s) -> @[...s.length] is s
|
||||
String::endsWith = (s) -> s is '' or @[-s.length..] is s
|
||||
String::repeat = (count) -> new Array( count + 1 ).join(@)
|
||||
|
||||
window.isEmpty = (obj) ->
|
||||
for key of obj
|
||||
return false
|
||||
return true
|
|
@ -1,138 +0,0 @@
|
|||
class Animation
|
||||
slideDown: (elem, props) ->
|
||||
if elem.offsetTop > 2000
|
||||
return
|
||||
|
||||
h = elem.offsetHeight
|
||||
cstyle = window.getComputedStyle(elem)
|
||||
margin_top = cstyle.marginTop
|
||||
margin_bottom = cstyle.marginBottom
|
||||
padding_top = cstyle.paddingTop
|
||||
padding_bottom = cstyle.paddingBottom
|
||||
transition = cstyle.transition
|
||||
|
||||
elem.style.boxSizing = "border-box"
|
||||
elem.style.overflow = "hidden"
|
||||
elem.style.transform = "scale(0.6)"
|
||||
elem.style.opacity = "0"
|
||||
elem.style.height = "0px"
|
||||
elem.style.marginTop = "0px"
|
||||
elem.style.marginBottom = "0px"
|
||||
elem.style.paddingTop = "0px"
|
||||
elem.style.paddingBottom = "0px"
|
||||
elem.style.transition = "none"
|
||||
|
||||
setTimeout (->
|
||||
elem.className += " animate-inout"
|
||||
elem.style.height = h+"px"
|
||||
elem.style.transform = "scale(1)"
|
||||
elem.style.opacity = "1"
|
||||
elem.style.marginTop = margin_top
|
||||
elem.style.marginBottom = margin_bottom
|
||||
elem.style.paddingTop = padding_top
|
||||
elem.style.paddingBottom = padding_bottom
|
||||
), 1
|
||||
|
||||
elem.addEventListener "transitionend", ->
|
||||
elem.classList.remove("animate-inout")
|
||||
elem.style.transition = elem.style.transform = elem.style.opacity = elem.style.height = null
|
||||
elem.style.boxSizing = elem.style.marginTop = elem.style.marginBottom = null
|
||||
elem.style.paddingTop = elem.style.paddingBottom = elem.style.overflow = null
|
||||
elem.removeEventListener "transitionend", arguments.callee, false
|
||||
|
||||
|
||||
slideUp: (elem, remove_func, props) ->
|
||||
if elem.offsetTop > 1000
|
||||
return remove_func()
|
||||
|
||||
elem.className += " animate-back"
|
||||
elem.style.boxSizing = "border-box"
|
||||
elem.style.height = elem.offsetHeight+"px"
|
||||
elem.style.overflow = "hidden"
|
||||
elem.style.transform = "scale(1)"
|
||||
elem.style.opacity = "1"
|
||||
elem.style.pointerEvents = "none"
|
||||
setTimeout (->
|
||||
elem.style.height = "0px"
|
||||
elem.style.marginTop = "0px"
|
||||
elem.style.marginBottom = "0px"
|
||||
elem.style.paddingTop = "0px"
|
||||
elem.style.paddingBottom = "0px"
|
||||
elem.style.transform = "scale(0.8)"
|
||||
elem.style.borderTopWidth = "0px"
|
||||
elem.style.borderBottomWidth = "0px"
|
||||
elem.style.opacity = "0"
|
||||
), 1
|
||||
elem.addEventListener "transitionend", (e) ->
|
||||
if e.propertyName == "opacity" or e.elapsedTime >= 0.6
|
||||
elem.removeEventListener "transitionend", arguments.callee, false
|
||||
remove_func()
|
||||
|
||||
|
||||
slideUpInout: (elem, remove_func, props) ->
|
||||
elem.className += " animate-inout"
|
||||
elem.style.boxSizing = "border-box"
|
||||
elem.style.height = elem.offsetHeight+"px"
|
||||
elem.style.overflow = "hidden"
|
||||
elem.style.transform = "scale(1)"
|
||||
elem.style.opacity = "1"
|
||||
elem.style.pointerEvents = "none"
|
||||
setTimeout (->
|
||||
elem.style.height = "0px"
|
||||
elem.style.marginTop = "0px"
|
||||
elem.style.marginBottom = "0px"
|
||||
elem.style.paddingTop = "0px"
|
||||
elem.style.paddingBottom = "0px"
|
||||
elem.style.transform = "scale(0.8)"
|
||||
elem.style.borderTopWidth = "0px"
|
||||
elem.style.borderBottomWidth = "0px"
|
||||
elem.style.opacity = "0"
|
||||
), 1
|
||||
elem.addEventListener "transitionend", (e) ->
|
||||
if e.propertyName == "opacity" or e.elapsedTime >= 0.6
|
||||
elem.removeEventListener "transitionend", arguments.callee, false
|
||||
remove_func()
|
||||
|
||||
|
||||
showRight: (elem, props) ->
|
||||
elem.className += " animate"
|
||||
elem.style.opacity = 0
|
||||
elem.style.transform = "TranslateX(-20px) Scale(1.01)"
|
||||
setTimeout (->
|
||||
elem.style.opacity = 1
|
||||
elem.style.transform = "TranslateX(0px) Scale(1)"
|
||||
), 1
|
||||
elem.addEventListener "transitionend", ->
|
||||
elem.classList.remove("animate")
|
||||
elem.style.transform = elem.style.opacity = null
|
||||
|
||||
|
||||
show: (elem, props) ->
|
||||
delay = arguments[arguments.length-2]?.delay*1000 or 1
|
||||
elem.style.opacity = 0
|
||||
setTimeout (->
|
||||
elem.className += " animate"
|
||||
), 1
|
||||
setTimeout (->
|
||||
elem.style.opacity = 1
|
||||
), delay
|
||||
elem.addEventListener "transitionend", ->
|
||||
elem.classList.remove("animate")
|
||||
elem.style.opacity = null
|
||||
elem.removeEventListener "transitionend", arguments.callee, false
|
||||
|
||||
hide: (elem, remove_func, props) ->
|
||||
delay = arguments[arguments.length-2]?.delay*1000 or 1
|
||||
elem.className += " animate"
|
||||
setTimeout (->
|
||||
elem.style.opacity = 0
|
||||
), delay
|
||||
elem.addEventListener "transitionend", (e) ->
|
||||
if e.propertyName == "opacity"
|
||||
remove_func()
|
||||
|
||||
addVisibleClass: (elem, props) ->
|
||||
setTimeout ->
|
||||
elem.classList.add("visible")
|
||||
|
||||
window.Animation = new Animation()
|
|
@ -1,3 +0,0 @@
|
|||
window.$ = (selector) ->
|
||||
if selector.startsWith("#")
|
||||
return document.getElementById(selector.replace("#", ""))
|
|
@ -1,85 +0,0 @@
|
|||
class ZeroFrame extends Class
|
||||
constructor: (url) ->
|
||||
@url = url
|
||||
@waiting_cb = {}
|
||||
@wrapper_nonce = document.location.href.replace(/.*wrapper_nonce=([A-Za-z0-9]+).*/, "$1")
|
||||
@connect()
|
||||
@next_message_id = 1
|
||||
@history_state = {}
|
||||
@init()
|
||||
|
||||
|
||||
init: ->
|
||||
@
|
||||
|
||||
|
||||
connect: ->
|
||||
@target = window.parent
|
||||
window.addEventListener("message", @onMessage, false)
|
||||
@cmd("innerReady")
|
||||
|
||||
# Save scrollTop
|
||||
window.addEventListener "beforeunload", (e) =>
|
||||
@log "save scrollTop", window.pageYOffset
|
||||
@history_state["scrollTop"] = window.pageYOffset
|
||||
@cmd "wrapperReplaceState", [@history_state, null]
|
||||
|
||||
# Restore scrollTop
|
||||
@cmd "wrapperGetState", [], (state) =>
|
||||
@history_state = state if state?
|
||||
@log "restore scrollTop", state, window.pageYOffset
|
||||
if window.pageYOffset == 0 and state
|
||||
window.scroll(window.pageXOffset, state.scrollTop)
|
||||
|
||||
|
||||
onMessage: (e) =>
|
||||
message = e.data
|
||||
cmd = message.cmd
|
||||
if cmd == "response"
|
||||
if @waiting_cb[message.to]?
|
||||
@waiting_cb[message.to](message.result)
|
||||
else
|
||||
@log "Websocket callback not found:", message
|
||||
else if cmd == "wrapperReady" # Wrapper inited later
|
||||
@cmd("innerReady")
|
||||
else if cmd == "ping"
|
||||
@response message.id, "pong"
|
||||
else if cmd == "wrapperOpenedWebsocket"
|
||||
@onOpenWebsocket()
|
||||
else if cmd == "wrapperClosedWebsocket"
|
||||
@onCloseWebsocket()
|
||||
else
|
||||
@onRequest cmd, message.params
|
||||
|
||||
|
||||
onRequest: (cmd, message) =>
|
||||
@log "Unknown request", message
|
||||
|
||||
|
||||
response: (to, result) ->
|
||||
@send {"cmd": "response", "to": to, "result": result}
|
||||
|
||||
|
||||
cmd: (cmd, params={}, cb=null) ->
|
||||
@send {"cmd": cmd, "params": params}, cb
|
||||
|
||||
|
||||
send: (message, cb=null) ->
|
||||
message.wrapper_nonce = @wrapper_nonce
|
||||
message.id = @next_message_id
|
||||
@next_message_id += 1
|
||||
@target.postMessage(message, "*")
|
||||
if cb
|
||||
@waiting_cb[message.id] = cb
|
||||
|
||||
|
||||
onOpenWebsocket: =>
|
||||
@log "Websocket open"
|
||||
|
||||
|
||||
onCloseWebsocket: =>
|
||||
@log "Websocket close"
|
||||
|
||||
|
||||
|
||||
window.ZeroFrame = ZeroFrame
|
Loading…
Add table
Add a link
Reference in a new issue