/* ---- lib/Animation.coffee ---- */ (function() { var Animation; Animation = (function() { function Animation() {} Animation.prototype.slideDown = function(elem, props) { var cstyle, h, margin_bottom, margin_top, padding_bottom, padding_top, transition; 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((function() { 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; return elem.style.paddingBottom = padding_bottom; }), 1); return elem.addEventListener("transitionend", function() { 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; return elem.removeEventListener("transitionend", arguments.callee, false); }); }; Animation.prototype.slideUp = function(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((function() { 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"; return elem.style.opacity = "0"; }), 1); return elem.addEventListener("transitionend", function(e) { if (e.propertyName === "opacity" || e.elapsedTime >= 0.6) { elem.removeEventListener("transitionend", arguments.callee, false); return remove_func(); } }); }; Animation.prototype.slideUpInout = function(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((function() { 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"; return elem.style.opacity = "0"; }), 1); return elem.addEventListener("transitionend", function(e) { if (e.propertyName === "opacity" || e.elapsedTime >= 0.6) { elem.removeEventListener("transitionend", arguments.callee, false); return remove_func(); } }); }; Animation.prototype.showRight = function(elem, props) { elem.className += " animate"; elem.style.opacity = 0; elem.style.transform = "TranslateX(-20px) Scale(1.01)"; setTimeout((function() { elem.style.opacity = 1; return elem.style.transform = "TranslateX(0px) Scale(1)"; }), 1); return elem.addEventListener("transitionend", function() { elem.classList.remove("animate"); return elem.style.transform = elem.style.opacity = null; }); }; Animation.prototype.show = function(elem, props) { var delay, ref; delay = ((ref = arguments[arguments.length - 2]) != null ? ref.delay : void 0) * 1000 || 1; elem.style.opacity = 0; setTimeout((function() { return elem.className += " animate"; }), 1); setTimeout((function() { return elem.style.opacity = 1; }), delay); return elem.addEventListener("transitionend", function() { elem.classList.remove("animate"); elem.style.opacity = null; return elem.removeEventListener("transitionend", arguments.callee, false); }); }; Animation.prototype.hide = function(elem, remove_func, props) { var delay, ref; delay = ((ref = arguments[arguments.length - 2]) != null ? ref.delay : void 0) * 1000 || 1; elem.className += " animate"; setTimeout((function() { return elem.style.opacity = 0; }), delay); return elem.addEventListener("transitionend", function(e) { if (e.propertyName === "opacity") { return remove_func(); } }); }; Animation.prototype.addVisibleClass = function(elem, props) { return setTimeout(function() { return elem.classList.add("visible"); }); }; return Animation; })(); window.Animation = new Animation(); }).call(this); /* ---- lib/Class.coffee ---- */ (function() { var Class, slice = [].slice; Class = (function() { function Class() {} Class.prototype.trace = true; Class.prototype.log = function() { var args; args = 1 <= arguments.length ? slice.call(arguments, 0) : []; if (!this.trace) { return; } if (typeof console === 'undefined') { return; } args.unshift("[" + this.constructor.name + "]"); console.log.apply(console, args); return this; }; Class.prototype.logStart = function() { var args, name; name = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; if (!this.trace) { return; } this.logtimers || (this.logtimers = {}); this.logtimers[name] = +(new Date); if (args.length > 0) { this.log.apply(this, ["" + name].concat(slice.call(args), ["(started)"])); } return this; }; Class.prototype.logEnd = function() { var args, ms, name; name = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; ms = +(new Date) - this.logtimers[name]; this.log.apply(this, ["" + name].concat(slice.call(args), ["(Done in " + ms + "ms)"])); return this; }; return Class; })(); window.Class = Class; }).call(this); /* ---- lib/Dollar.coffee ---- */ (function() { window.$ = function(selector) { if (selector.startsWith("#")) { return document.getElementById(selector.replace("#", "")); } }; }).call(this); /* ---- lib/ItemList.coffee ---- */ (function() { var ItemList; ItemList = (function() { function ItemList(item_class1, key1) { this.item_class = item_class1; this.key = key1; this.items = []; this.items_bykey = {}; } ItemList.prototype.sync = function(rows, item_class, key) { var current_obj, i, item, len, results, row; this.items.splice(0, this.items.length); results = []; for (i = 0, len = rows.length; i < len; i++) { row = rows[i]; current_obj = this.items_bykey[row[this.key]]; if (current_obj) { current_obj.row = row; results.push(this.items.push(current_obj)); } else { item = new this.item_class(row, this); this.items_bykey[row[this.key]] = item; results.push(this.items.push(item)); } } return results; }; ItemList.prototype.deleteItem = function(item) { var index; index = this.items.indexOf(item); if (index > -1) { this.items.splice(index, 1); } else { console.log("Can't delete item", item); } return delete this.items_bykey[item.row[this.key]]; }; return ItemList; })(); window.ItemList = ItemList; }).call(this); /* ---- lib/Menu.coffee ---- */ (function() { var Menu, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Menu = (function() { function Menu() { this.render = bind(this.render, this); this.getStyle = bind(this.getStyle, this); this.renderItem = bind(this.renderItem, this); this.handleClick = bind(this.handleClick, this); this.getDirection = bind(this.getDirection, this); this.storeNode = bind(this.storeNode, this); this.toggle = bind(this.toggle, this); this.hide = bind(this.hide, this); this.show = bind(this.show, this); this.visible = false; this.items = []; this.node = null; this.height = 0; this.direction = "bottom"; } Menu.prototype.show = function() { var ref; if ((ref = window.visible_menu) != null) { ref.hide(); } this.visible = true; window.visible_menu = this; return this.direction = this.getDirection(); }; Menu.prototype.hide = function() { return this.visible = false; }; Menu.prototype.toggle = function() { if (this.visible) { this.hide(); } else { this.show(); } return Page.projector.scheduleRender(); }; Menu.prototype.addItem = function(title, cb, selected) { if (selected == null) { selected = false; } return this.items.push([title, cb, selected]); }; Menu.prototype.storeNode = function(node) { this.node = node; if (this.visible) { node.className = node.className.replace("visible", ""); setTimeout(((function(_this) { return function() { node.className += " visible"; return node.attributes.style.value = _this.getStyle(); }; })(this)), 20); node.style.maxHeight = "none"; this.height = node.offsetHeight; node.style.maxHeight = "0px"; return this.direction = this.getDirection(); } }; Menu.prototype.getDirection = function() { if (this.node && this.node.parentNode.getBoundingClientRect().top + this.height + 60 > document.body.clientHeight && this.node.parentNode.getBoundingClientRect().top - this.height > 0) { return "top"; } else { return "bottom"; } }; Menu.prototype.handleClick = function(e) { var cb, i, item, keep_menu, len, ref, selected, title; keep_menu = false; ref = this.items; for (i = 0, len = ref.length; i < len; i++) { item = ref[i]; title = item[0], cb = item[1], selected = item[2]; if (title === e.currentTarget.textContent || e.currentTarget["data-title"] === title) { keep_menu = typeof cb === "function" ? cb(item) : void 0; break; } } if (keep_menu !== true && cb !== null) { this.hide(); } return false; }; Menu.prototype.renderItem = function(item) { var cb, classes, href, onclick, selected, title; title = item[0], cb = item[1], selected = item[2]; if (typeof selected === "function") { selected = selected(); } if (title === "---") { return h("div.menu-item-separator", { key: Time.timestamp() }); } else { if (cb === null) { href = void 0; onclick = this.handleClick; } else if (typeof cb === "string") { href = cb; onclick = true; } else { href = "#" + title; onclick = this.handleClick; } classes = { "selected": selected, "noaction": cb === null }; return h("a.menu-item", { href: href, onclick: onclick, "data-title": title, key: title, classes: classes }, title); } }; Menu.prototype.getStyle = function() { var max_height, style; if (this.visible) { max_height = this.height; } else { max_height = 0; } style = "max-height: " + max_height + "px"; if (this.direction === "top") { style += ";margin-top: " + (0 - this.height - 50) + "px"; } else { style += ";margin-top: 0px"; } return style; }; Menu.prototype.render = function(class_name) { if (class_name == null) { class_name = ""; } if (this.visible || this.node) { return h("div.menu" + class_name, { classes: { "visible": this.visible }, style: this.getStyle(), afterCreate: this.storeNode }, this.items.map(this.renderItem)); } }; return Menu; })(); window.Menu = Menu; document.body.addEventListener("mouseup", function(e) { var menu_node, menu_parents, ref, ref1; if (!window.visible_menu || !window.visible_menu.node) { return false; } menu_node = window.visible_menu.node; menu_parents = [menu_node, menu_node.parentNode]; if ((ref = e.target.parentNode, indexOf.call(menu_parents, ref) < 0) && (ref1 = e.target.parentNode.parentNode, indexOf.call(menu_parents, ref1) < 0)) { window.visible_menu.hide(); return Page.projector.scheduleRender(); } }); }).call(this); /* ---- lib/Promise.coffee ---- */ (function() { var Promise, slice = [].slice; Promise = (function() { Promise.when = function() { var args, fn, i, len, num_uncompleted, promise, task, task_id, tasks; tasks = 1 <= arguments.length ? slice.call(arguments, 0) : []; num_uncompleted = tasks.length; args = new Array(num_uncompleted); promise = new Promise(); fn = function(task_id) { return task.then(function() { args[task_id] = Array.prototype.slice.call(arguments); num_uncompleted--; if (num_uncompleted === 0) { return promise.complete.apply(promise, args); } }); }; for (task_id = i = 0, len = tasks.length; i < len; task_id = ++i) { task = tasks[task_id]; fn(task_id); } return promise; }; function Promise() { this.resolved = false; this.end_promise = null; this.result = null; this.callbacks = []; } Promise.prototype.resolve = function() { var back, callback, i, len, ref; if (this.resolved) { return false; } this.resolved = true; this.data = arguments; if (!arguments.length) { this.data = [true]; } this.result = this.data[0]; ref = this.callbacks; for (i = 0, len = ref.length; i < len; i++) { callback = ref[i]; back = callback.apply(callback, this.data); } if (this.end_promise) { return this.end_promise.resolve(back); } }; Promise.prototype.fail = function() { return this.resolve(false); }; Promise.prototype.then = function(callback) { if (this.resolved === true) { callback.apply(callback, this.data); return; } this.callbacks.push(callback); return this.end_promise = new Promise(); }; return 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 */ }).call(this); /* ---- lib/Prototypes.coffee ---- */ (function() { String.prototype.startsWith = function(s) { return this.slice(0, s.length) === s; }; String.prototype.endsWith = function(s) { return s === '' || this.slice(-s.length) === s; }; String.prototype.repeat = function(count) { return new Array(count + 1).join(this); }; window.isEmpty = function(obj) { var key; for (key in obj) { return false; } return true; }; }).call(this); /* ---- lib/RateLimitCb.coffee ---- */ (function() { var call_after_interval, calling, calling_iterval, last_time, slice = [].slice; last_time = {}; calling = {}; calling_iterval = {}; call_after_interval = {}; window.RateLimitCb = function(interval, fn, args) { var cb; if (args == null) { args = []; } cb = function() { var left; left = interval - (Date.now() - last_time[fn]); if (left <= 0) { delete last_time[fn]; if (calling[fn]) { RateLimitCb(interval, fn, calling[fn]); } return delete calling[fn]; } else { return setTimeout((function() { delete last_time[fn]; if (calling[fn]) { RateLimitCb(interval, fn, calling[fn]); } return delete calling[fn]; }), left); } }; if (last_time[fn]) { return calling[fn] = args; } else { last_time[fn] = Date.now(); return fn.apply(this, [cb].concat(slice.call(args))); } }; window.RateLimit = function(interval, fn) { if (calling_iterval[fn] > interval) { clearInterval(calling[fn]); delete calling[fn]; } if (!calling[fn]) { call_after_interval[fn] = false; fn(); calling_iterval[fn] = interval; return calling[fn] = setTimeout((function() { if (call_after_interval[fn]) { fn(); } delete calling[fn]; return delete call_after_interval[fn]; }), interval); } else { return call_after_interval[fn] = true; } }; /* window.s = Date.now() window.load = (done, num) -> console.log "Loading #{num}...", Date.now()-window.s setTimeout (-> done()), 1000 RateLimit 500, window.load, [0] # Called instantly RateLimit 500, window.load, [1] setTimeout (-> RateLimit 500, window.load, [300]), 300 setTimeout (-> RateLimit 500, window.load, [600]), 600 # Called after 1000ms setTimeout (-> RateLimit 500, window.load, [1000]), 1000 setTimeout (-> RateLimit 500, window.load, [1200]), 1200 # Called after 2000ms setTimeout (-> RateLimit 500, window.load, [3000]), 3000 # Called after 3000ms */ }).call(this); /* ---- lib/Text.coffee ---- */ (function() { var Text, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; Text = (function() { function Text() {} Text.prototype.toColor = function(text, saturation, lightness) { var hash, i, j, ref; if (saturation == null) { saturation = 30; } if (lightness == null) { lightness = 50; } hash = 0; for (i = j = 0, ref = text.length - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) { hash += text.charCodeAt(i) * i; hash = hash % 1777; } return "hsl(" + (hash % 360) + ("," + saturation + "%," + lightness + "%)"); }; Text.prototype.renderMarked = function(text, options) { if (options == null) { options = {}; } options["gfm"] = true; options["breaks"] = true; options["sanitize"] = true; options["renderer"] = marked_renderer; text = marked(text, options); return this.fixHtmlLinks(text); }; Text.prototype.emailLinks = function(text) { return text.replace(/([a-zA-Z0-9]+)@zeroid.bit/g, "<a href='?to=$1' onclick='return Page.message_create.show(\"$1\")'>$1@zeroid.bit</a>"); }; Text.prototype.fixHtmlLinks = function(text) { if (window.is_proxy) { return text.replace(/href="http:\/\/(127.0.0.1|localhost):43110/g, 'href="http://zero'); } else { return text.replace(/href="http:\/\/(127.0.0.1|localhost):43110/g, 'href="'); } }; Text.prototype.fixLink = function(link) { var back; if (window.is_proxy) { back = link.replace(/http:\/\/(127.0.0.1|localhost):43110/, 'http://zero'); return back.replace(/http:\/\/zero\/([^\/]+\.bit)/, "http://$1"); } else { return link.replace(/http:\/\/(127.0.0.1|localhost):43110/, ''); } }; Text.prototype.toUrl = function(text) { return text.replace(/[^A-Za-z0-9]/g, "+").replace(/[+]+/g, "+").replace(/[+]+$/, ""); }; Text.prototype.getSiteUrl = function(address) { if (window.is_proxy) { if (indexOf.call(address, ".") >= 0) { return "http://" + address + "/"; } else { return "http://zero/" + address + "/"; } } else { return "/" + address + "/"; } }; Text.prototype.fixReply = function(text) { return text.replace(/(>.*\n)([^\n>])/gm, "$1\n$2"); }; Text.prototype.toBitcoinAddress = function(text) { return text.replace(/[^A-Za-z0-9]/g, ""); }; Text.prototype.jsonEncode = function(obj) { return unescape(encodeURIComponent(JSON.stringify(obj))); }; Text.prototype.jsonDecode = function(obj) { return JSON.parse(decodeURIComponent(escape(obj))); }; Text.prototype.fileEncode = function(obj) { if (typeof obj === "string") { return btoa(unescape(encodeURIComponent(obj))); } else { return btoa(unescape(encodeURIComponent(JSON.stringify(obj, void 0, '\t')))); } }; Text.prototype.utf8Encode = function(s) { return unescape(encodeURIComponent(s)); }; Text.prototype.utf8Decode = function(s) { return decodeURIComponent(escape(s)); }; Text.prototype.distance = function(s1, s2) { var char, extra_parts, j, key, len, match, next_find, next_find_i, val; s1 = s1.toLocaleLowerCase(); s2 = s2.toLocaleLowerCase(); next_find_i = 0; next_find = s2[0]; match = true; extra_parts = {}; for (j = 0, len = s1.length; j < len; j++) { char = s1[j]; if (char !== next_find) { if (extra_parts[next_find_i]) { extra_parts[next_find_i] += char; } else { extra_parts[next_find_i] = char; } } else { next_find_i++; next_find = s2[next_find_i]; } } if (extra_parts[next_find_i]) { extra_parts[next_find_i] = ""; } extra_parts = (function() { var results; results = []; for (key in extra_parts) { val = extra_parts[key]; results.push(val); } return results; })(); if (next_find_i >= s2.length) { return extra_parts.length + extra_parts.join("").length; } else { return false; } }; Text.prototype.parseQuery = function(query) { var j, key, len, params, part, parts, ref, val; params = {}; parts = query.split('&'); for (j = 0, len = parts.length; j < len; j++) { part = parts[j]; ref = part.split("="), key = ref[0], val = ref[1]; if (val) { params[decodeURIComponent(key)] = decodeURIComponent(val); } else { params["url"] = decodeURIComponent(key); } } return params; }; Text.prototype.encodeQuery = function(params) { var back, key, val; back = []; if (params.url) { back.push(params.url); } for (key in params) { val = params[key]; if (!val || key === "url") { continue; } back.push((encodeURIComponent(key)) + "=" + (encodeURIComponent(val))); } return back.join("&"); }; Text.prototype.highlight = function(text, search) { var back, i, j, len, part, parts; if (!text) { return [""]; } parts = text.split(RegExp(search, "i")); back = []; for (i = j = 0, len = parts.length; j < len; i = ++j) { part = parts[i]; back.push(part); if (i < parts.length - 1) { back.push(h("span.highlight", { key: i }, search)); } } return back; }; Text.prototype.formatSize = function(size) { var size_mb; if (isNaN(parseInt(size))) { return ""; } size_mb = size / 1024 / 1024; if (size_mb >= 1000) { return (size_mb / 1024).toFixed(1) + " GB"; } else if (size_mb >= 100) { return size_mb.toFixed(0) + " MB"; } else if (size / 1024 >= 1000) { return size_mb.toFixed(2) + " MB"; } else { return (parseInt(size) / 1024).toFixed(2) + " KB"; } }; return Text; })(); window.is_proxy = document.location.host === "zero" || window.location.pathname === "/"; window.Text = new Text(); }).call(this); /* ---- lib/Time.coffee ---- */ (function() { var Time; Time = (function() { function Time() {} Time.prototype.since = function(timestamp) { var back, minutes, now, secs; now = +(new Date) / 1000; if (timestamp > 1000000000000) { timestamp = timestamp / 1000; } secs = now - timestamp; if (secs < 60) { back = "Just now"; } else if (secs < 60 * 60) { minutes = Math.round(secs / 60); back = "" + minutes + " minutes ago"; } else if (secs < 60 * 60 * 24) { back = (Math.round(secs / 60 / 60)) + " hours ago"; } else if (secs < 60 * 60 * 24 * 3) { back = (Math.round(secs / 60 / 60 / 24)) + " days ago"; } else { back = "on " + this.date(timestamp); } back = back.replace(/^1 ([a-z]+)s/, "1 $1"); return back; }; Time.prototype.dateIso = function(timestamp) { var tzoffset; if (timestamp == null) { timestamp = null; } if (!timestamp) { timestamp = window.Time.timestamp(); } if (timestamp > 1000000000000) { timestamp = timestamp / 1000; } tzoffset = (new Date()).getTimezoneOffset() * 60; return (new Date((timestamp - tzoffset) * 1000)).toISOString().split("T")[0]; }; Time.prototype.date = function(timestamp, format) { var display, parts; if (timestamp == null) { timestamp = null; } if (format == null) { format = "short"; } if (!timestamp) { timestamp = window.Time.timestamp(); } if (timestamp > 1000000000000) { timestamp = timestamp / 1000; } parts = (new Date(timestamp * 1000)).toString().split(" "); if (format === "short") { display = parts.slice(1, 4); } else if (format === "day") { display = parts.slice(1, 3); } else if (format === "month") { display = [parts[1], parts[3]]; } else if (format === "long") { display = parts.slice(1, 5); } return display.join(" ").replace(/( [0-9]{4})/, ",$1"); }; Time.prototype.weekDay = function(timestamp) { if (timestamp > 1000000000000) { timestamp = timestamp / 1000; } return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][(new Date(timestamp * 1000)).getDay()]; }; Time.prototype.timestamp = function(date) { if (date == null) { date = ""; } if (date === "now" || date === "") { return parseInt(+(new Date) / 1000); } else { return parseInt(Date.parse(date) / 1000); } }; return Time; })(); window.Time = new Time; }).call(this); /* ---- lib/ZeroFrame.coffee ---- */ (function() { var ZeroFrame, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; ZeroFrame = (function(superClass) { extend(ZeroFrame, superClass); function ZeroFrame(url) { this.onCloseWebsocket = bind(this.onCloseWebsocket, this); this.onOpenWebsocket = bind(this.onOpenWebsocket, this); this.onRequest = bind(this.onRequest, this); this.onMessage = bind(this.onMessage, this); this.url = url; this.waiting_cb = {}; this.wrapper_nonce = document.location.href.replace(/.*wrapper_nonce=([A-Za-z0-9]+).*/, "$1"); this.connect(); this.next_message_id = 1; this.history_state = {}; this.init(); } ZeroFrame.prototype.init = function() { return this; }; ZeroFrame.prototype.connect = function() { this.target = window.parent; window.addEventListener("message", this.onMessage, false); this.cmd("innerReady"); window.addEventListener("beforeunload", (function(_this) { return function(e) { _this.log("save scrollTop", window.pageYOffset); _this.history_state["scrollTop"] = window.pageYOffset; return _this.cmd("wrapperReplaceState", [_this.history_state, null]); }; })(this)); return this.cmd("wrapperGetState", [], (function(_this) { return function(state) { if (state != null) { _this.history_state = state; } _this.log("restore scrollTop", state, window.pageYOffset); if (window.pageYOffset === 0 && state) { return window.scroll(window.pageXOffset, state.scrollTop); } }; })(this)); }; ZeroFrame.prototype.onMessage = function(e) { var cmd, message; message = e.data; cmd = message.cmd; if (cmd === "response") { if (this.waiting_cb[message.to] != null) { return this.waiting_cb[message.to](message.result); } else { return this.log("Websocket callback not found:", message); } } else if (cmd === "wrapperReady") { return this.cmd("innerReady"); } else if (cmd === "ping") { return this.response(message.id, "pong"); } else if (cmd === "wrapperOpenedWebsocket") { return this.onOpenWebsocket(); } else if (cmd === "wrapperClosedWebsocket") { return this.onCloseWebsocket(); } else { return this.onRequest(cmd, message.params); } }; ZeroFrame.prototype.onRequest = function(cmd, message) { return this.log("Unknown request", message); }; ZeroFrame.prototype.response = function(to, result) { return this.send({ "cmd": "response", "to": to, "result": result }); }; ZeroFrame.prototype.cmd = function(cmd, params, cb) { if (params == null) { params = {}; } if (cb == null) { cb = null; } return this.send({ "cmd": cmd, "params": params }, cb); }; ZeroFrame.prototype.send = function(message, cb) { if (cb == null) { cb = null; } message.wrapper_nonce = this.wrapper_nonce; message.id = this.next_message_id; this.next_message_id += 1; this.target.postMessage(message, "*"); if (cb) { return this.waiting_cb[message.id] = cb; } }; ZeroFrame.prototype.onOpenWebsocket = function() { return this.log("Websocket open"); }; ZeroFrame.prototype.onCloseWebsocket = function() { return this.log("Websocket close"); }; return ZeroFrame; })(Class); window.ZeroFrame = ZeroFrame; }).call(this); /* ---- lib/maquette.js ---- */ (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['exports'], factory); } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') { // CommonJS factory(exports); } else { // Browser globals factory(root.maquette = {}); } }(this, function (exports) { 'use strict'; ; ; ; ; var NAMESPACE_W3 = 'http://www.w3.org/'; var NAMESPACE_SVG = NAMESPACE_W3 + '2000/svg'; var NAMESPACE_XLINK = NAMESPACE_W3 + '1999/xlink'; // Utilities var emptyArray = []; var extend = function (base, overrides) { var result = {}; Object.keys(base).forEach(function (key) { result[key] = base[key]; }); if (overrides) { Object.keys(overrides).forEach(function (key) { result[key] = overrides[key]; }); } return result; }; // Hyperscript helper functions var same = function (vnode1, vnode2) { if (vnode1.vnodeSelector !== vnode2.vnodeSelector) { return false; } if (vnode1.properties && vnode2.properties) { if (vnode1.properties.key !== vnode2.properties.key) { return false; } return vnode1.properties.bind === vnode2.properties.bind; } return !vnode1.properties && !vnode2.properties; }; var toTextVNode = function (data) { return { vnodeSelector: '', properties: undefined, children: undefined, text: data.toString(), domNode: null }; }; var appendChildren = function (parentSelector, insertions, main) { for (var i = 0; i < insertions.length; i++) { var item = insertions[i]; if (Array.isArray(item)) { appendChildren(parentSelector, item, main); } else { if (item !== null && item !== undefined) { if (!item.hasOwnProperty('vnodeSelector')) { item = toTextVNode(item); } main.push(item); } } } }; // Render helper functions var missingTransition = function () { throw new Error('Provide a transitions object to the projectionOptions to do animations'); }; var DEFAULT_PROJECTION_OPTIONS = { namespace: undefined, eventHandlerInterceptor: undefined, styleApplyer: function (domNode, styleName, value) { // Provides a hook to add vendor prefixes for browsers that still need it. domNode.style[styleName] = value; }, transitions: { enter: missingTransition, exit: missingTransition } }; var applyDefaultProjectionOptions = function (projectorOptions) { return extend(DEFAULT_PROJECTION_OPTIONS, projectorOptions); }; var checkStyleValue = function (styleValue) { if (typeof styleValue !== 'string') { throw new Error('Style values must be strings'); } }; var setProperties = function (domNode, properties, projectionOptions) { if (!properties) { return; } var eventHandlerInterceptor = projectionOptions.eventHandlerInterceptor; var propNames = Object.keys(properties); var propCount = propNames.length; for (var i = 0; i < propCount; i++) { var propName = propNames[i]; /* tslint:disable:no-var-keyword: edge case */ var propValue = properties[propName]; /* tslint:enable:no-var-keyword */ if (propName === 'className') { throw new Error('Property "className" is not supported, use "class".'); } else if (propName === 'class') { if (domNode.className) { // May happen if classes is specified before class domNode.className += ' ' + propValue; } else { domNode.className = propValue; } } else if (propName === 'classes') { // object with string keys and boolean values var classNames = Object.keys(propValue); var classNameCount = classNames.length; for (var j = 0; j < classNameCount; j++) { var className = classNames[j]; if (propValue[className]) { domNode.classList.add(className); } } } else if (propName === 'styles') { // object with string keys and string (!) values var styleNames = Object.keys(propValue); var styleCount = styleNames.length; for (var j = 0; j < styleCount; j++) { var styleName = styleNames[j]; var styleValue = propValue[styleName]; if (styleValue) { checkStyleValue(styleValue); projectionOptions.styleApplyer(domNode, styleName, styleValue); } } } else if (propName === 'key') { continue; } else if (propValue === null || propValue === undefined) { continue; } else { var type = typeof propValue; if (type === 'function') { if (propName.lastIndexOf('on', 0) === 0) { if (eventHandlerInterceptor) { propValue = eventHandlerInterceptor(propName, propValue, domNode, properties); // intercept eventhandlers } if (propName === 'oninput') { (function () { // record the evt.target.value, because IE and Edge sometimes do a requestAnimationFrame between changing value and running oninput var oldPropValue = propValue; propValue = function (evt) { evt.target['oninput-value'] = evt.target.value; // may be HTMLTextAreaElement as well oldPropValue.apply(this, [evt]); }; }()); } domNode[propName] = propValue; } } else if (type === 'string' && propName !== 'value' && propName !== 'innerHTML') { if (projectionOptions.namespace === NAMESPACE_SVG && propName === 'href') { domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue); } else { domNode.setAttribute(propName, propValue); } } else { domNode[propName] = propValue; } } } }; var updateProperties = function (domNode, previousProperties, properties, projectionOptions) { if (!properties) { return; } var propertiesUpdated = false; var propNames = Object.keys(properties); var propCount = propNames.length; for (var i = 0; i < propCount; i++) { var propName = propNames[i]; // assuming that properties will be nullified instead of missing is by design var propValue = properties[propName]; var previousValue = previousProperties[propName]; if (propName === 'class') { if (previousValue !== propValue) { throw new Error('"class" property may not be updated. Use the "classes" property for conditional css classes.'); } } else if (propName === 'classes') { var classList = domNode.classList; var classNames = Object.keys(propValue); var classNameCount = classNames.length; for (var j = 0; j < classNameCount; j++) { var className = classNames[j]; var on = !!propValue[className]; var previousOn = !!previousValue[className]; if (on === previousOn) { continue; } propertiesUpdated = true; if (on) { classList.add(className); } else { classList.remove(className); } } } else if (propName === 'styles') { var styleNames = Object.keys(propValue); var styleCount = styleNames.length; for (var j = 0; j < styleCount; j++) { var styleName = styleNames[j]; var newStyleValue = propValue[styleName]; var oldStyleValue = previousValue[styleName]; if (newStyleValue === oldStyleValue) { continue; } propertiesUpdated = true; if (newStyleValue) { checkStyleValue(newStyleValue); projectionOptions.styleApplyer(domNode, styleName, newStyleValue); } else { projectionOptions.styleApplyer(domNode, styleName, ''); } } } else { if (!propValue && typeof previousValue === 'string') { propValue = ''; } if (propName === 'value') { if (domNode[propName] !== propValue && domNode['oninput-value'] !== propValue) { domNode[propName] = propValue; // Reset the value, even if the virtual DOM did not change domNode['oninput-value'] = undefined; } // else do not update the domNode, otherwise the cursor position would be changed if (propValue !== previousValue) { propertiesUpdated = true; } } else if (propValue !== previousValue) { var type = typeof propValue; if (type === 'function') { throw new Error('Functions may not be updated on subsequent renders (property: ' + propName + '). Hint: declare event handler functions outside the render() function.'); } if (type === 'string' && propName !== 'innerHTML') { if (projectionOptions.namespace === NAMESPACE_SVG && propName === 'href') { domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue); } else { domNode.setAttribute(propName, propValue); } } else { if (domNode[propName] !== propValue) { domNode[propName] = propValue; } } propertiesUpdated = true; } } } return propertiesUpdated; }; var findIndexOfChild = function (children, sameAs, start) { if (sameAs.vnodeSelector !== '') { // Never scan for text-nodes for (var i = start; i < children.length; i++) { if (same(children[i], sameAs)) { return i; } } } return -1; }; var nodeAdded = function (vNode, transitions) { if (vNode.properties) { var enterAnimation = vNode.properties.enterAnimation; if (enterAnimation) { if (typeof enterAnimation === 'function') { enterAnimation(vNode.domNode, vNode.properties); } else { transitions.enter(vNode.domNode, vNode.properties, enterAnimation); } } } }; var nodeToRemove = function (vNode, transitions) { var domNode = vNode.domNode; if (vNode.properties) { var exitAnimation = vNode.properties.exitAnimation; if (exitAnimation) { domNode.style.pointerEvents = 'none'; var removeDomNode = function () { if (domNode.parentNode) { domNode.parentNode.removeChild(domNode); } }; if (typeof exitAnimation === 'function') { exitAnimation(domNode, removeDomNode, vNode.properties); return; } else { transitions.exit(vNode.domNode, vNode.properties, exitAnimation, removeDomNode); return; } } } if (domNode.parentNode) { domNode.parentNode.removeChild(domNode); } }; var checkDistinguishable = function (childNodes, indexToCheck, parentVNode, operation) { var childNode = childNodes[indexToCheck]; if (childNode.vnodeSelector === '') { return; // Text nodes need not be distinguishable } var properties = childNode.properties; var key = properties ? properties.key === undefined ? properties.bind : properties.key : undefined; if (!key) { for (var i = 0; i < childNodes.length; i++) { if (i !== indexToCheck) { var node = childNodes[i]; if (same(node, childNode)) { if (operation === 'added') { throw new Error(parentVNode.vnodeSelector + ' had a ' + childNode.vnodeSelector + ' child ' + 'added, but there is now more than one. You must add unique key properties to make them distinguishable.'); } else { throw new Error(parentVNode.vnodeSelector + ' had a ' + childNode.vnodeSelector + ' child ' + 'removed, but there were more than one. You must add unique key properties to make them distinguishable.'); } } } } } }; var createDom; var updateDom; var updateChildren = function (vnode, domNode, oldChildren, newChildren, projectionOptions) { if (oldChildren === newChildren) { return false; } oldChildren = oldChildren || emptyArray; newChildren = newChildren || emptyArray; var oldChildrenLength = oldChildren.length; var newChildrenLength = newChildren.length; var transitions = projectionOptions.transitions; var oldIndex = 0; var newIndex = 0; var i; var textUpdated = false; while (newIndex < newChildrenLength) { var oldChild = oldIndex < oldChildrenLength ? oldChildren[oldIndex] : undefined; var newChild = newChildren[newIndex]; if (oldChild !== undefined && same(oldChild, newChild)) { textUpdated = updateDom(oldChild, newChild, projectionOptions) || textUpdated; oldIndex++; } else { var findOldIndex = findIndexOfChild(oldChildren, newChild, oldIndex + 1); if (findOldIndex >= 0) { // Remove preceding missing children for (i = oldIndex; i < findOldIndex; i++) { nodeToRemove(oldChildren[i], transitions); checkDistinguishable(oldChildren, i, vnode, 'removed'); } textUpdated = updateDom(oldChildren[findOldIndex], newChild, projectionOptions) || textUpdated; oldIndex = findOldIndex + 1; } else { // New child createDom(newChild, domNode, oldIndex < oldChildrenLength ? oldChildren[oldIndex].domNode : undefined, projectionOptions); nodeAdded(newChild, transitions); checkDistinguishable(newChildren, newIndex, vnode, 'added'); } } newIndex++; } if (oldChildrenLength > oldIndex) { // Remove child fragments for (i = oldIndex; i < oldChildrenLength; i++) { nodeToRemove(oldChildren[i], transitions); checkDistinguishable(oldChildren, i, vnode, 'removed'); } } return textUpdated; }; var addChildren = function (domNode, children, projectionOptions) { if (!children) { return; } for (var i = 0; i < children.length; i++) { createDom(children[i], domNode, undefined, projectionOptions); } }; var initPropertiesAndChildren = function (domNode, vnode, projectionOptions) { addChildren(domNode, vnode.children, projectionOptions); // children before properties, needed for value property of <select>. if (vnode.text) { domNode.textContent = vnode.text; } setProperties(domNode, vnode.properties, projectionOptions); if (vnode.properties && vnode.properties.afterCreate) { vnode.properties.afterCreate(domNode, projectionOptions, vnode.vnodeSelector, vnode.properties, vnode.children); } }; createDom = function (vnode, parentNode, insertBefore, projectionOptions) { var domNode, i, c, start = 0, type, found; var vnodeSelector = vnode.vnodeSelector; if (vnodeSelector === '') { domNode = vnode.domNode = document.createTextNode(vnode.text); if (insertBefore !== undefined) { parentNode.insertBefore(domNode, insertBefore); } else { parentNode.appendChild(domNode); } } else { for (i = 0; i <= vnodeSelector.length; ++i) { c = vnodeSelector.charAt(i); if (i === vnodeSelector.length || c === '.' || c === '#') { type = vnodeSelector.charAt(start - 1); found = vnodeSelector.slice(start, i); if (type === '.') { domNode.classList.add(found); } else if (type === '#') { domNode.id = found; } else { if (found === 'svg') { projectionOptions = extend(projectionOptions, { namespace: NAMESPACE_SVG }); } if (projectionOptions.namespace !== undefined) { domNode = vnode.domNode = document.createElementNS(projectionOptions.namespace, found); } else { domNode = vnode.domNode = document.createElement(found); } if (insertBefore !== undefined) { parentNode.insertBefore(domNode, insertBefore); } else { parentNode.appendChild(domNode); } } start = i + 1; } } initPropertiesAndChildren(domNode, vnode, projectionOptions); } }; updateDom = function (previous, vnode, projectionOptions) { var domNode = previous.domNode; var textUpdated = false; if (previous === vnode) { return false; // By contract, VNode objects may not be modified anymore after passing them to maquette } var updated = false; if (vnode.vnodeSelector === '') { if (vnode.text !== previous.text) { var newVNode = document.createTextNode(vnode.text); domNode.parentNode.replaceChild(newVNode, domNode); vnode.domNode = newVNode; textUpdated = true; return textUpdated; } } else { if (vnode.vnodeSelector.lastIndexOf('svg', 0) === 0) { projectionOptions = extend(projectionOptions, { namespace: NAMESPACE_SVG }); } if (previous.text !== vnode.text) { updated = true; if (vnode.text === undefined) { domNode.removeChild(domNode.firstChild); // the only textnode presumably } else { domNode.textContent = vnode.text; } } updated = updateChildren(vnode, domNode, previous.children, vnode.children, projectionOptions) || updated; updated = updateProperties(domNode, previous.properties, vnode.properties, projectionOptions) || updated; if (vnode.properties && vnode.properties.afterUpdate) { vnode.properties.afterUpdate(domNode, projectionOptions, vnode.vnodeSelector, vnode.properties, vnode.children); } } if (updated && vnode.properties && vnode.properties.updateAnimation) { vnode.properties.updateAnimation(domNode, vnode.properties, previous.properties); } vnode.domNode = previous.domNode; return textUpdated; }; var createProjection = function (vnode, projectionOptions) { return { update: function (updatedVnode) { if (vnode.vnodeSelector !== updatedVnode.vnodeSelector) { throw new Error('The selector for the root VNode may not be changed. (consider using dom.merge and add one extra level to the virtual DOM)'); } updateDom(vnode, updatedVnode, projectionOptions); vnode = updatedVnode; }, domNode: vnode.domNode }; }; ; // The other two parameters are not added here, because the Typescript compiler creates surrogate code for desctructuring 'children'. exports.h = function (selector) { var properties = arguments[1]; if (typeof selector !== 'string') { throw new Error(); } var childIndex = 1; if (properties && !properties.hasOwnProperty('vnodeSelector') && !Array.isArray(properties) && typeof properties === 'object') { childIndex = 2; } else { // Optional properties argument was omitted properties = undefined; } var text = undefined; var children = undefined; var argsLength = arguments.length; // Recognize a common special case where there is only a single text node if (argsLength === childIndex + 1) { var onlyChild = arguments[childIndex]; if (typeof onlyChild === 'string') { text = onlyChild; } else if (onlyChild !== undefined && onlyChild.length === 1 && typeof onlyChild[0] === 'string') { text = onlyChild[0]; } } if (text === undefined) { children = []; for (; childIndex < arguments.length; childIndex++) { var child = arguments[childIndex]; if (child === null || child === undefined) { continue; } else if (Array.isArray(child)) { appendChildren(selector, child, children); } else if (child.hasOwnProperty('vnodeSelector')) { children.push(child); } else { children.push(toTextVNode(child)); } } } return { vnodeSelector: selector, properties: properties, children: children, text: text === '' ? undefined : text, domNode: null }; }; /** * Contains simple low-level utility functions to manipulate the real DOM. */ exports.dom = { /** * Creates a real DOM tree from `vnode`. The [[Projection]] object returned will contain the resulting DOM Node in * its [[Projection.domNode|domNode]] property. * This is a low-level method. Users wil typically use a [[Projector]] instead. * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]] * objects may only be rendered once. * @param projectionOptions - Options to be used to create and update the projection. * @returns The [[Projection]] which also contains the DOM Node that was created. */ create: function (vnode, projectionOptions) { projectionOptions = applyDefaultProjectionOptions(projectionOptions); createDom(vnode, document.createElement('div'), undefined, projectionOptions); return createProjection(vnode, projectionOptions); }, /** * Appends a new childnode to the DOM which is generated from a [[VNode]]. * This is a low-level method. Users wil typically use a [[Projector]] instead. * @param parentNode - The parent node for the new childNode. * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]] * objects may only be rendered once. * @param projectionOptions - Options to be used to create and update the [[Projection]]. * @returns The [[Projection]] that was created. */ append: function (parentNode, vnode, projectionOptions) { projectionOptions = applyDefaultProjectionOptions(projectionOptions); createDom(vnode, parentNode, undefined, projectionOptions); return createProjection(vnode, projectionOptions); }, /** * Inserts a new DOM node which is generated from a [[VNode]]. * This is a low-level method. Users wil typically use a [[Projector]] instead. * @param beforeNode - The node that the DOM Node is inserted before. * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. * NOTE: [[VNode]] objects may only be rendered once. * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]]. * @returns The [[Projection]] that was created. */ insertBefore: function (beforeNode, vnode, projectionOptions) { projectionOptions = applyDefaultProjectionOptions(projectionOptions); createDom(vnode, beforeNode.parentNode, beforeNode, projectionOptions); return createProjection(vnode, projectionOptions); }, /** * Merges a new DOM node which is generated from a [[VNode]] with an existing DOM Node. * This means that the virtual DOM and the real DOM will have one overlapping element. * Therefore the selector for the root [[VNode]] will be ignored, but its properties and children will be applied to the Element provided. * This is a low-level method. Users wil typically use a [[Projector]] instead. * @param domNode - The existing element to adopt as the root of the new virtual DOM. Existing attributes and childnodes are preserved. * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]] objects * may only be rendered once. * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]]. * @returns The [[Projection]] that was created. */ merge: function (element, vnode, projectionOptions) { projectionOptions = applyDefaultProjectionOptions(projectionOptions); vnode.domNode = element; initPropertiesAndChildren(element, vnode, projectionOptions); return createProjection(vnode, projectionOptions); } }; /** * Creates a [[CalculationCache]] object, useful for caching [[VNode]] trees. * In practice, caching of [[VNode]] trees is not needed, because achieving 60 frames per second is almost never a problem. * For more information, see [[CalculationCache]]. * * @param <Result> The type of the value that is cached. */ exports.createCache = function () { var cachedInputs = undefined; var cachedOutcome = undefined; var result = { invalidate: function () { cachedOutcome = undefined; cachedInputs = undefined; }, result: function (inputs, calculation) { if (cachedInputs) { for (var i = 0; i < inputs.length; i++) { if (cachedInputs[i] !== inputs[i]) { cachedOutcome = undefined; } } } if (!cachedOutcome) { cachedOutcome = calculation(); cachedInputs = inputs; } return cachedOutcome; } }; return result; }; /** * Creates a {@link Mapping} instance that keeps an array of result objects synchronized with an array of source objects. * See {@link http://maquettejs.org/docs/arrays.html|Working with arrays}. * * @param <Source> The type of source items. A database-record for instance. * @param <Target> The type of target items. A [[Component]] for instance. * @param getSourceKey `function(source)` that must return a key to identify each source object. The result must either be a string or a number. * @param createResult `function(source, index)` that must create a new result object from a given source. This function is identical * to the `callback` argument in `Array.map(callback)`. * @param updateResult `function(source, target, index)` that updates a result to an updated source. */ exports.createMapping = function (getSourceKey, createResult, updateResult) { var keys = []; var results = []; return { results: results, map: function (newSources) { var newKeys = newSources.map(getSourceKey); var oldTargets = results.slice(); var oldIndex = 0; for (var i = 0; i < newSources.length; i++) { var source = newSources[i]; var sourceKey = newKeys[i]; if (sourceKey === keys[oldIndex]) { results[i] = oldTargets[oldIndex]; updateResult(source, oldTargets[oldIndex], i); oldIndex++; } else { var found = false; for (var j = 1; j < keys.length; j++) { var searchIndex = (oldIndex + j) % keys.length; if (keys[searchIndex] === sourceKey) { results[i] = oldTargets[searchIndex]; updateResult(newSources[i], oldTargets[searchIndex], i); oldIndex = searchIndex + 1; found = true; break; } } if (!found) { results[i] = createResult(source, i); } } } results.length = newSources.length; keys = newKeys; } }; }; /** * Creates a [[Projector]] instance using the provided projectionOptions. * * For more information, see [[Projector]]. * * @param projectionOptions Options that influence how the DOM is rendered and updated. */ exports.createProjector = function (projectorOptions) { var projector; var projectionOptions = applyDefaultProjectionOptions(projectorOptions); projectionOptions.eventHandlerInterceptor = function (propertyName, eventHandler, domNode, properties) { return function () { // intercept function calls (event handlers) to do a render afterwards. projector.scheduleRender(); return eventHandler.apply(properties.bind || this, arguments); }; }; var renderCompleted = true; var scheduled; var stopped = false; var projections = []; var renderFunctions = []; // matches the projections array var doRender = function () { scheduled = undefined; if (!renderCompleted) { return; // The last render threw an error, it should be logged in the browser console. } renderCompleted = false; for (var i = 0; i < projections.length; i++) { var updatedVnode = renderFunctions[i](); projections[i].update(updatedVnode); } renderCompleted = true; }; projector = { scheduleRender: function () { if (!scheduled && !stopped) { scheduled = requestAnimationFrame(doRender); } }, stop: function () { if (scheduled) { cancelAnimationFrame(scheduled); scheduled = undefined; } stopped = true; }, resume: function () { stopped = false; renderCompleted = true; projector.scheduleRender(); }, append: function (parentNode, renderMaquetteFunction) { projections.push(exports.dom.append(parentNode, renderMaquetteFunction(), projectionOptions)); renderFunctions.push(renderMaquetteFunction); }, insertBefore: function (beforeNode, renderMaquetteFunction) { projections.push(exports.dom.insertBefore(beforeNode, renderMaquetteFunction(), projectionOptions)); renderFunctions.push(renderMaquetteFunction); }, merge: function (domNode, renderMaquetteFunction) { projections.push(exports.dom.merge(domNode, renderMaquetteFunction(), projectionOptions)); renderFunctions.push(renderMaquetteFunction); }, replace: function (domNode, renderMaquetteFunction) { var vnode = renderMaquetteFunction(); createDom(vnode, domNode.parentNode, domNode, projectionOptions); domNode.parentNode.removeChild(domNode); projections.push(createProjection(vnode, projectionOptions)); renderFunctions.push(renderMaquetteFunction); }, detach: function (renderMaquetteFunction) { for (var i = 0; i < renderFunctions.length; i++) { if (renderFunctions[i] === renderMaquetteFunction) { renderFunctions.splice(i, 1); return projections.splice(i, 1)[0]; } } throw new Error('renderMaquetteFunction was not found'); } }; return projector; }; })); /* ---- Config.coffee ---- */ (function() { window.BINARY_EXTENSIONS = ["3dm", "3ds", "3g2", "3gp", "7z", "a", "aac", "adp", "ai", "aif", "aiff", "alz", "ape", "apk", "appimage", "ar", "arj", "asc", "asf", "au", "avi", "bak", "baml", "bh", "bin", "bk", "bmp", "btif", "bz2", "bzip2", "cab", "caf", "cgm", "class", "cmx", "cpio", "cr2", "cur", "dat", "dcm", "deb", "dex", "djvu", "dll", "dmg", "dng", "doc", "docm", "docx", "dot", "dotm", "dra", "DS_Store", "dsk", "dts", "dtshd", "dvb", "dwg", "dxf", "ecelp4800", "ecelp7470", "ecelp9600", "egg", "eol", "eot", "epub", "exe", "f4v", "fbs", "fh", "fla", "flac", "flatpak", "fli", "flv", "fpx", "fst", "fvt", "g3", "gh", "gif", "gpg", "graffle", "gz", "gzip", "h261", "h263", "h264", "icns", "ico", "ief", "img", "ipa", "iso", "jar", "jpeg", "jpg", "jpgv", "jpm", "jxr", "key", "ktx", "lha", "lib", "lvp", "lz", "lzh", "lzma", "lzo", "m3u", "m4a", "m4v", "mar", "mdi", "mht", "mid", "midi", "mj2", "mka", "mkv", "mmr", "mng", "mobi", "mov", "movie", "mp3", "mp4", "mp4a", "mpeg", "mpg", "mpga", "msgpack", "mxu", "nef", "npx", "numbers", "nupkg", "o", "oga", "ogg", "ogv", "otf", "pages", "pbm", "pcx", "pdb", "pdf", "pea", "pgm", "pic", "png", "pnm", "pot", "potm", "potx", "ppa", "ppam", "ppm", "pps", "ppsm", "ppsx", "ppt", "pptm", "pptx", "psd", "pya", "pyc", "pyo", "pyv", "qt", "rar", "ras", "raw", "resources", "rgb", "rip", "rlc", "rmf", "rmvb", "rpm", "rtf", "rz", "s3m", "s7z", "scpt", "sgi", "shar", "sig", "sil", "sketch", "slk", "smv", "snap", "snk", "so", "stl", "sub", "suo", "swf", "tar", "tbz2", "tbz", "tga", "tgz", "thmx", "tif", "tiff", "tlz", "ttc", "ttf", "txz", "udf", "uvh", "uvi", "uvm", "uvp", "uvs", "uvu", "viv", "vob", "war", "wav", "wax", "wbmp", "wdp", "weba", "webm", "webp", "whl", "wim", "wm", "wma", "wmv", "wmx", "woff2", "woff", "wrm", "wvx", "xbm", "xif", "xla", "xlam", "xls", "xlsb", "xlsm", "xlsx", "xlt", "xltm", "xltx", "xm", "xmind", "xpi", "xpm", "xwd", "xz", "z", "zip", "zipx"]; }).call(this); /* ---- FileEditor.coffee ---- */ (function() { var FileEditor, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; FileEditor = (function(superClass) { extend(FileEditor, superClass); function FileEditor(inner_path1) { this.inner_path = inner_path1; this.save = bind(this.save, this); this.handleSaveClick = bind(this.handleSaveClick, this); this.handleSidebarButtonClick = bind(this.handleSidebarButtonClick, this); this.foldJson = bind(this.foldJson, this); this.storeCmNode = bind(this.storeCmNode, this); this.isModified = bind(this.isModified, this); this.need_update = true; this.on_loaded = new Promise(); this.is_loading = false; this.content = ""; this.node_cm = null; this.cm = null; this.error = null; this.is_loaded = false; this.is_modified = false; this.is_saving = false; this.mode = "Loading"; } FileEditor.prototype.update = function() { var is_required; is_required = Page.url_params.get("edit_mode") !== "new"; return Page.cmd("fileGet", { inner_path: this.inner_path, required: is_required }, (function(_this) { return function(res) { if (res != null ? res.error : void 0) { _this.error = res.error; _this.content = res.error; _this.log("Error loading: " + _this.error); } else { if (res) { _this.content = res; } else { _this.content = ""; _this.mode = "Create"; } } if (!_this.content) { _this.cm.getDoc().clearHistory(); } _this.cm.setValue(_this.content); if (!_this.error) { _this.is_loaded = true; } return Page.projector.scheduleRender(); }; })(this)); }; FileEditor.prototype.isModified = function() { return this.content !== this.cm.getValue(); }; FileEditor.prototype.storeCmNode = function(node) { return this.node_cm = node; }; FileEditor.prototype.getMode = function(inner_path) { var ext, types; ext = inner_path.split(".").pop(); types = { "py": "python", "json": "application/json", "js": "javascript", "coffee": "coffeescript", "html": "htmlmixed", "htm": "htmlmixed", "php": "htmlmixed", "rs": "rust", "css": "css", "md": "markdown", "xml": "xml", "svg": "xml" }; return types[ext]; }; FileEditor.prototype.foldJson = function(from, to) { var count, e, endToken, internal, parsed, prevLine, startToken, toParse; this.log("foldJson", from, to); startToken = '{'; endToken = '}'; prevLine = this.cm.getLine(from.line); if (prevLine.lastIndexOf('[') > prevLine.lastIndexOf('{')) { startToken = '['; endToken = ']'; } internal = this.cm.getRange(from, to); toParse = startToken + internal + endToken; try { parsed = JSON.parse(toParse); count = Object.keys(parsed).length; } catch (error) { e = error; null; } if (count) { return "\u21A4" + count + "\u21A6"; } else { return "\u2194"; } }; FileEditor.prototype.createCodeMirror = function() { var mode, options; mode = this.getMode(this.inner_path); this.log("Creating CodeMirror", this.inner_path, mode); options = { value: "Loading...", mode: mode, lineNumbers: true, styleActiveLine: true, matchBrackets: true, keyMap: "sublime", theme: "mdn-like", extraKeys: { "Ctrl-Space": "autocomplete" }, foldGutter: true, gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] }; if (mode === "application/json") { options.gutters.unshift("CodeMirror-lint-markers"); options.lint = true; options.foldOptions = { widget: this.foldJson }; } this.cm = CodeMirror(this.node_cm, options); return this.cm.on("changes", (function(_this) { return function(changes) { if (_this.is_loaded && !_this.is_modified) { _this.is_modified = true; return Page.projector.scheduleRender(); } }; })(this)); }; FileEditor.prototype.loadEditor = function() { var script; if (!this.is_loading) { document.getElementsByTagName("head")[0].insertAdjacentHTML("beforeend", "<link rel=\"stylesheet\" href=\"codemirror/all.css\" />"); script = document.createElement('script'); script.src = "codemirror/all.js"; script.onload = (function(_this) { return function() { _this.createCodeMirror(); return _this.on_loaded.resolve(); }; })(this); document.head.appendChild(script); } return this.on_loaded; }; FileEditor.prototype.handleSidebarButtonClick = function() { Page.is_sidebar_closed = !Page.is_sidebar_closed; return false; }; FileEditor.prototype.handleSaveClick = function() { var mark, num_errors; num_errors = ((function() { var i, len, ref, results; ref = Page.file_editor.cm.getAllMarks(); results = []; for (i = 0, len = ref.length; i < len; i++) { mark = ref[i]; if (mark.className === "CodeMirror-lint-mark-error") { results.push(mark); } } return results; })()).length; if (num_errors > 0) { Page.cmd("wrapperConfirm", ["<b>Warning:</b> The file looks invalid.", "Save anyway"], this.save); } else { this.save(); } return false; }; FileEditor.prototype.save = function() { Page.projector.scheduleRender(); this.is_saving = true; return Page.cmd("fileWrite", [this.inner_path, Text.fileEncode(this.cm.getValue())], (function(_this) { return function(res) { _this.is_saving = false; if (res.error) { Page.cmd("wrapperNotification", ["error", "Error saving " + res.error]); } else { _this.is_save_done = true; setTimeout((function() { _this.is_save_done = false; return Page.projector.scheduleRender(); }), 2000); _this.content = _this.cm.getValue(); _this.is_modified = false; if (_this.mode === "Create") { _this.mode = "Edit"; } Page.file_list.need_update = true; } return Page.projector.scheduleRender(); }; })(this)); }; FileEditor.prototype.render = function() { var ref; if (this.need_update) { this.loadEditor().then((function(_this) { return function() { return _this.update(); }; })(this)); this.need_update = false; } return h("div.editor", { afterCreate: this.storeCmNode, classes: { error: this.error, loaded: this.is_loaded } }, [ h("a.sidebar-button", { href: "#Sidebar", onclick: this.handleSidebarButtonClick }, h("span", "\u2039")), h("div.editor-head", [ (ref = this.mode) === "Edit" || ref === "Create" ? h("a.save.button", { href: "#Save", classes: { loading: this.is_saving, done: this.is_save_done, disabled: !this.is_modified }, onclick: this.handleSaveClick }, this.is_save_done ? "Save: done!" : "Save") : void 0, h("span.title", this.mode, ": ", this.inner_path) ]), this.error ? h("div.error-message", h("h2", "Unable to load the file: " + this.error), h("a", { href: Page.file_list.getHref(this.inner_path) }, "View in browser")) : void 0 ]); }; return FileEditor; })(Class); window.FileEditor = FileEditor; }).call(this); /* ---- FileItemList.coffee ---- */ (function() { var FileItemList, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; FileItemList = (function(superClass) { extend(FileItemList, superClass); function FileItemList(inner_path1) { this.inner_path = inner_path1; this.sort = bind(this.sort, this); this.getOptionalInfo = bind(this.getOptionalInfo, this); this.hasPermissionDelete = bind(this.hasPermissionDelete, this); this.isAdded = bind(this.isAdded, this); this.isModified = bind(this.isModified, this); this.getFileType = bind(this.getFileType, this); this.addOptionalFilesToItems = bind(this.addOptionalFilesToItems, this); this.updateOptionalFiles = bind(this.updateOptionalFiles, this); this.updateAddedFiles = bind(this.updateAddedFiles, this); this.updateModifiedFiles = bind(this.updateModifiedFiles, this); this.items = []; this.updating = false; this.files_modified = {}; this.dirs_modified = {}; this.files_added = {}; this.dirs_added = {}; this.files_optional = {}; this.items_by_name = {}; } FileItemList.prototype.update = function(cb) { this.updating = true; this.logStart("Updating dirlist"); return Page.cmd("dirList", { inner_path: this.inner_path, stats: true }, (function(_this) { return function(res) { var i, len, pattern_ignore, ref, ref1, ref2, ref3, row; if (res.error) { _this.error = res.error; } else { _this.error = null; pattern_ignore = RegExp("^" + ((ref = Page.site_info.content) != null ? ref.ignore : void 0)); _this.items.splice(0, _this.items.length); _this.items_by_name = {}; for (i = 0, len = res.length; i < len; i++) { row = res[i]; row.type = _this.getFileType(row); row.inner_path = _this.inner_path + row.name; if (((ref1 = Page.site_info.content) != null ? ref1.ignore : void 0) && row.inner_path.match(pattern_ignore)) { row.ignored = true; } _this.items.push(row); _this.items_by_name[row.name] = row; } _this.sort(); } if ((ref2 = Page.site_info) != null ? (ref3 = ref2.settings) != null ? ref3.own : void 0 : void 0) { _this.updateAddedFiles(); } return _this.updateOptionalFiles(function() { _this.updating = false; if (typeof cb === "function") { cb(); } _this.logEnd("Updating dirlist", _this.inner_path); Page.projector.scheduleRender(); return _this.updateModifiedFiles(function() { return Page.projector.scheduleRender(); }); }); }; })(this)); }; FileItemList.prototype.updateModifiedFiles = function(cb) { return Page.cmd("siteListModifiedFiles", [], (function(_this) { return function(res) { var dir_inner_path, dir_part, dir_parts, i, inner_path, j, len, len1, ref, ref1; _this.files_modified = {}; _this.dirs_modified = {}; ref = res.modified_files; for (i = 0, len = ref.length; i < len; i++) { inner_path = ref[i]; _this.files_modified[inner_path] = true; dir_inner_path = ""; dir_parts = inner_path.split("/"); ref1 = dir_parts.slice(0, -1); for (j = 0, len1 = ref1.length; j < len1; j++) { dir_part = ref1[j]; if (dir_inner_path) { dir_inner_path += "/" + dir_part; } else { dir_inner_path = dir_part; } _this.dirs_modified[dir_inner_path] = true; } } return typeof cb === "function" ? cb() : void 0; }; })(this)); }; FileItemList.prototype.updateAddedFiles = function() { return Page.cmd("fileGet", "content.json", (function(_this) { return function(res) { var content, dirs_content, file, file_name, i, j, len, len1, match, pattern, ref, ref1, results; if (!res) { return false; } content = JSON.parse(res); if (content.files == null) { return false; } _this.files_added = {}; ref = _this.items; for (i = 0, len = ref.length; i < len; i++) { file = ref[i]; if (file.name === "content.json" || file.is_dir) { continue; } if (!content.files[_this.inner_path + file.name]) { _this.files_added[_this.inner_path + file.name] = true; } } _this.dirs_added = {}; dirs_content = {}; for (file_name in Object.assign({}, content.files, content.files_optional)) { if (!file_name.startsWith(_this.inner_path)) { continue; } pattern = new RegExp(_this.inner_path + "(.*?)/"); match = file_name.match(pattern); if (!match) { continue; } dirs_content[match[1]] = true; } ref1 = _this.items; results = []; for (j = 0, len1 = ref1.length; j < len1; j++) { file = ref1[j]; if (!file.is_dir) { continue; } if (!dirs_content[file.name]) { results.push(_this.dirs_added[_this.inner_path + file.name] = true); } else { results.push(void 0); } } return results; }; })(this)); }; FileItemList.prototype.updateOptionalFiles = function(cb) { return Page.cmd("optionalFileList", { filter: "" }, (function(_this) { return function(res) { var i, len, optional_file; _this.files_optional = {}; for (i = 0, len = res.length; i < len; i++) { optional_file = res[i]; _this.files_optional[optional_file.inner_path] = optional_file; } _this.addOptionalFilesToItems(); return typeof cb === "function" ? cb() : void 0; }; })(this)); }; FileItemList.prototype.addOptionalFilesToItems = function() { var dir_name, file_name, inner_path, is_added, optional_file, ref, ref1, row; is_added = false; ref = this.files_optional; for (inner_path in ref) { optional_file = ref[inner_path]; if (optional_file.inner_path.startsWith(this.inner_path)) { if (this.getDirectory(optional_file.inner_path) === this.inner_path) { file_name = this.getFileName(optional_file.inner_path); if (!this.items_by_name[file_name]) { row = { "name": file_name, "type": "file", "optional_empty": true, "size": optional_file.size, "is_dir": false, "inner_path": optional_file.inner_path }; this.items.push(row); this.items_by_name[file_name] = row; is_added = true; } } else { dir_name = (ref1 = optional_file.inner_path.replace(this.inner_path, "").match(/(.*?)\//, "")) != null ? ref1[1] : void 0; if (dir_name && !this.items_by_name[dir_name]) { row = { "name": dir_name, "type": "dir", "optional_empty": true, "size": 0, "is_dir": true, "inner_path": optional_file.inner_path }; this.items.push(row); this.items_by_name[dir_name] = row; is_added = true; } } } } if (is_added) { return this.sort(); } }; FileItemList.prototype.getFileType = function(file) { if (file.is_dir) { return "dir"; } else { return "unknown"; } }; FileItemList.prototype.getDirectory = function(inner_path) { if (inner_path.indexOf("/") !== -1) { return inner_path.replace(/^(.*\/)(.*?)$/, "$1"); } else { return ""; } }; FileItemList.prototype.getFileName = function(inner_path) { return inner_path.replace(/^(.*\/)(.*?)$/, "$2"); }; FileItemList.prototype.isModified = function(inner_path) { return this.files_modified[inner_path] || this.dirs_modified[inner_path]; }; FileItemList.prototype.isAdded = function(inner_path) { return this.files_added[inner_path] || this.dirs_added[inner_path]; }; FileItemList.prototype.hasPermissionDelete = function(file) { var optional_info, ref, ref1, ref2; if ((ref = file.type) === "dir" || ref === "parent") { return false; } if (file.inner_path === "content.json") { return false; } optional_info = this.getOptionalInfo(file.inner_path); if (optional_info && optional_info.downloaded_percent > 0) { return true; } else { return (ref1 = Page.site_info) != null ? (ref2 = ref1.settings) != null ? ref2.own : void 0 : void 0; } }; FileItemList.prototype.getOptionalInfo = function(inner_path) { return this.files_optional[inner_path]; }; FileItemList.prototype.sort = function() { return this.items.sort(function(a, b) { return (b.is_dir - a.is_dir) || a.name.localeCompare(b.name); }); }; return FileItemList; })(Class); window.FileItemList = FileItemList; }).call(this); /* ---- FileList.coffee ---- */ (function() { var FileList, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; FileList = (function(superClass) { extend(FileList, superClass); function FileList(site, inner_path1, is_owner) { this.site = site; this.inner_path = inner_path1; this.is_owner = is_owner != null ? is_owner : false; this.render = bind(this.render, this); this.renderFoot = bind(this.renderFoot, this); this.renderItems = bind(this.renderItems, this); this.renderItem = bind(this.renderItem, this); this.renderItemCheckbox = bind(this.renderItemCheckbox, this); this.renderHead = bind(this.renderHead, this); this.renderSelectbar = bind(this.renderSelectbar, this); this.handleSelectbarRemoveOptional = bind(this.handleSelectbarRemoveOptional, this); this.handleSelectbarDelete = bind(this.handleSelectbarDelete, this); this.handleSelectbarCancel = bind(this.handleSelectbarCancel, this); this.handleRowMouseenter = bind(this.handleRowMouseenter, this); this.handleSelectMousedown = bind(this.handleSelectMousedown, this); this.handleSelectEnd = bind(this.handleSelectEnd, this); this.handleSelectClick = bind(this.handleSelectClick, this); this.handleNewDirectoryClick = bind(this.handleNewDirectoryClick, this); this.handleNewFileClick = bind(this.handleNewFileClick, this); this.handleMenuCreateClick = bind(this.handleMenuCreateClick, this); this.checkSelectedItems = bind(this.checkSelectedItems, this); this.getEditHref = bind(this.getEditHref, this); this.getListHref = bind(this.getListHref, this); this.getHref = bind(this.getHref, this); this.update = bind(this.update, this); this.need_update = true; this.error = null; this.url_root = "/list/" + this.site + "/"; if (this.inner_path) { this.inner_path += "/"; this.url_root += this.inner_path; } this.log("inited", this.url_root); this.item_list = new FileItemList(this.inner_path); this.item_list.items = this.item_list.items; this.menu_create = new Menu(); this.select_action = null; this.selected = {}; this.selected_items_num = 0; this.selected_items_size = 0; this.selected_optional_empty_num = 0; } FileList.prototype.isSelectedAll = function() { return false; }; FileList.prototype.update = function() { return this.item_list.update((function(_this) { return function() { return document.body.classList.add("loaded"); }; })(this)); }; FileList.prototype.getHref = function(inner_path) { return "/" + this.site + "/" + inner_path; }; FileList.prototype.getListHref = function(inner_path) { return "/list/" + this.site + "/" + inner_path; }; FileList.prototype.getEditHref = function(inner_path, mode) { var href; if (mode == null) { mode = null; } href = this.url_root + "?file=" + inner_path; if (mode) { href += "&edit_mode=" + mode; } return href; }; FileList.prototype.checkSelectedItems = function() { var i, item, len, optional_info, ref, results; this.selected_items_num = 0; this.selected_items_size = 0; this.selected_optional_empty_num = 0; ref = this.item_list.items; results = []; for (i = 0, len = ref.length; i < len; i++) { item = ref[i]; if (this.selected[item.inner_path]) { this.selected_items_num += 1; this.selected_items_size += item.size; optional_info = this.item_list.getOptionalInfo(item.inner_path); if (optional_info && !optional_info.downloaded_percent > 0) { results.push(this.selected_optional_empty_num += 1); } else { results.push(void 0); } } else { results.push(void 0); } } return results; }; FileList.prototype.handleMenuCreateClick = function() { this.menu_create.items = []; this.menu_create.items.push(["File", this.handleNewFileClick]); this.menu_create.items.push(["Directory", this.handleNewDirectoryClick]); this.menu_create.toggle(); return false; }; FileList.prototype.handleNewFileClick = function() { Page.cmd("wrapperPrompt", "New file name:", (function(_this) { return function(file_name) { return window.top.location.href = _this.getEditHref(_this.inner_path + file_name, "new"); }; })(this)); return false; }; FileList.prototype.handleNewDirectoryClick = function() { Page.cmd("wrapperPrompt", "New directory name:", (function(_this) { return function(res) { return alert("directory name " + res); }; })(this)); return false; }; FileList.prototype.handleSelectClick = function(e) { return false; }; FileList.prototype.handleSelectEnd = function(e) { document.body.removeEventListener('mouseup', this.handleSelectEnd); return this.select_action = null; }; FileList.prototype.handleSelectMousedown = function(e) { var inner_path; inner_path = e.currentTarget.attributes.inner_path.value; if (this.selected[inner_path]) { delete this.selected[inner_path]; this.select_action = "deselect"; } else { this.selected[inner_path] = true; this.select_action = "select"; } this.checkSelectedItems(); document.body.addEventListener('mouseup', this.handleSelectEnd); e.stopPropagation(); Page.projector.scheduleRender(); return false; }; FileList.prototype.handleRowMouseenter = function(e) { var inner_path; if (e.buttons && this.select_action) { inner_path = e.target.attributes.inner_path.value; if (this.select_action === "select") { this.selected[inner_path] = true; } else { delete this.selected[inner_path]; } this.checkSelectedItems(); Page.projector.scheduleRender(); } return false; }; FileList.prototype.handleSelectbarCancel = function() { this.selected = {}; this.checkSelectedItems(); Page.projector.scheduleRender(); return false; }; FileList.prototype.handleSelectbarDelete = function(e, remove_optional) { var inner_path, optional_info; if (remove_optional == null) { remove_optional = false; } for (inner_path in this.selected) { optional_info = this.item_list.getOptionalInfo(inner_path); delete this.selected[inner_path]; if (optional_info && !remove_optional) { Page.cmd("optionalFileDelete", inner_path); } else { Page.cmd("fileDelete", inner_path); } } this.need_update = true; Page.projector.scheduleRender(); this.checkSelectedItems(); return false; }; FileList.prototype.handleSelectbarRemoveOptional = function(e) { return this.handleSelectbarDelete(e, true); }; FileList.prototype.renderSelectbar = function() { return h("div.selectbar", { classes: { visible: this.selected_items_num > 0 } }, [ "Selected:", h("span.info", [h("span.num", this.selected_items_num + " files"), h("span.size", "(" + (Text.formatSize(this.selected_items_size)) + ")")]), h("div.actions", [ this.selected_optional_empty_num > 0 ? h("a.action.delete.remove_optional", { href: "#", onclick: this.handleSelectbarRemoveOptional }, "Delete and remove optional") : h("a.action.delete", { href: "#", onclick: this.handleSelectbarDelete }, "Delete") ]), h("a.cancel.link", { href: "#", onclick: this.handleSelectbarCancel }, "Cancel") ]); }; FileList.prototype.renderHead = function() { var i, inner_path_parent, len, parent_dir, parent_links, ref; parent_links = []; inner_path_parent = ""; ref = this.inner_path.split("/"); for (i = 0, len = ref.length; i < len; i++) { parent_dir = ref[i]; if (!parent_dir) { continue; } if (inner_path_parent) { inner_path_parent += "/"; } inner_path_parent += "" + parent_dir; parent_links.push([ " / ", h("a", { href: this.getListHref(inner_path_parent) }, parent_dir) ]); } return h("div.tr.thead", h("div.td.full", h("a", { href: this.getListHref("") }, "root"), parent_links)); }; FileList.prototype.renderItemCheckbox = function(item) { if (!this.item_list.hasPermissionDelete(item)) { return [" "]; } return h("a.checkbox-outer", { href: "#Select", onmousedown: this.handleSelectMousedown, onclick: this.handleSelectClick, inner_path: item.inner_path }, h("span.checkbox")); }; FileList.prototype.renderItem = function(item) { var classes, downloaded_percent, ext, href, href_edit, inner_path, is_added, is_dir, is_editable, is_editing, is_modified, obj, optional_info, ref, ref1, style, title; if (item.type === "parent") { href = this.url_root.replace(/^(.*)\/.{2,255}?$/, "$1/"); } else if (item.type === "dir") { href = this.url_root + item.name; } else { href = this.url_root.replace(/^\/list\//, "/") + item.name; } inner_path = this.inner_path + item.name; href_edit = this.getEditHref(inner_path); is_dir = (ref = item.type) === "dir" || ref === "parent"; ext = item.name.split(".").pop(); is_editing = inner_path === ((ref1 = Page.file_editor) != null ? ref1.inner_path : void 0); is_editable = !is_dir && item.size < 1024 * 1024 && indexOf.call(window.BINARY_EXTENSIONS, ext) < 0; is_modified = this.item_list.isModified(inner_path); is_added = this.item_list.isAdded(inner_path); optional_info = this.item_list.getOptionalInfo(inner_path); style = ""; title = ""; if (optional_info) { downloaded_percent = optional_info.downloaded_percent; if (!downloaded_percent) { downloaded_percent = 0; } style += "background: linear-gradient(90deg, #fff6dd, " + downloaded_percent + "%, white, " + downloaded_percent + "%, white);"; is_added = false; } if (item.ignored) { is_added = false; } if (is_modified) { title += " (modified)"; } if (is_added) { title += " (new)"; } if (optional_info || item.optional_empty) { title += " (optional)"; } if (item.ignored) { title += " (ignored from content.json)"; } classes = ( obj = {}, obj["type-" + item.type] = true, obj.editing = is_editing, obj.nobuttons = !is_editable, obj.selected = this.selected[inner_path], obj.modified = is_modified, obj.added = is_added, obj.ignored = item.ignored, obj.optional = optional_info, obj.optional_empty = item.optional_empty, obj ); return h("div.tr", { key: item.name, classes: classes, style: style, onmouseenter: this.handleRowMouseenter, inner_path: inner_path }, [ h("div.td.pre", { title: title }, this.renderItemCheckbox(item)), h("div.td.name", h("a.link", { href: href }, item.name)), h("div.td.buttons", is_editable ? h("a.edit", { href: href_edit }, Page.site_info.settings.own ? "Edit" : "View") : void 0), h("div.td.size", is_dir ? "[DIR]" : Text.formatSize(item.size)) ]); }; FileList.prototype.renderItems = function() { return [ this.item_list.error && !this.item_list.items.length && !this.item_list.updating ? [ h("div.tr", { key: "error" }, h("div.td.full.error", this.item_list.error)) ] : void 0, this.inner_path ? this.renderItem({ "name": "..", type: "parent", size: 0 }) : void 0, this.item_list.items.map(this.renderItem) ]; }; FileList.prototype.renderFoot = function() { var dirs, file, files, foot_text, item, ref, ref1, ref2, ref3, total_size; files = (function() { var i, len, ref, ref1, results; ref = this.item_list.items; results = []; for (i = 0, len = ref.length; i < len; i++) { item = ref[i]; if ((ref1 = item.type) !== "parent" && ref1 !== "dir") { results.push(item); } } return results; }).call(this); dirs = (function() { var i, len, ref, results; ref = this.item_list.items; results = []; for (i = 0, len = ref.length; i < len; i++) { item = ref[i]; if (item.type === "dir") { results.push(item); } } return results; }).call(this); if (files.length) { total_size = ((function() { var i, len, results; results = []; for (i = 0, len = files.length; i < len; i++) { file = files[i]; results.push(item.size); } return results; })()).reduce(function(a, b) { return a + b; }); } else { total_size = 0; } foot_text = "Total: "; foot_text += dirs.length + " dir, " + files.length + " file in " + (Text.formatSize(total_size)); return [ dirs.length || files.length || ((ref = Page.site_info) != null ? (ref1 = ref.settings) != null ? ref1.own : void 0 : void 0) ? h("div.tr.foot-info.foot", h("div.td.full", [ this.item_list.updating ? "Updating file list..." : dirs.length || files.length ? foot_text : void 0, ((ref2 = Page.site_info) != null ? (ref3 = ref2.settings) != null ? ref3.own : void 0 : void 0) ? h("div.create", [ h("a.link", { href: "#Create+new+file", onclick: this.handleNewFileClick }, "+ New"), this.menu_create.render() ]) : void 0 ])) : void 0 ]; }; FileList.prototype.render = function() { if (this.need_update) { this.update(); this.need_update = false; if (!this.item_list.items) { return []; } } return h("div.files", [this.renderSelectbar(), this.renderHead(), h("div.tbody", this.renderItems()), this.renderFoot()]); }; return FileList; })(Class); window.FileList = FileList; }).call(this); /* ---- UiFileManager.coffee ---- */ (function() { var UiFileManager, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; window.h = maquette.h; UiFileManager = (function(superClass) { extend(UiFileManager, superClass); function UiFileManager() { this.render = bind(this.render, this); this.createProjector = bind(this.createProjector, this); this.onRequest = bind(this.onRequest, this); this.checkBodyWidth = bind(this.checkBodyWidth, this); return UiFileManager.__super__.constructor.apply(this, arguments); } UiFileManager.prototype.init = function() { this.url_params = new URLSearchParams(window.location.search); this.list_site = this.url_params.get("site"); this.list_address = this.url_params.get("address"); this.list_inner_path = this.url_params.get("inner_path"); this.editor_inner_path = this.url_params.get("file"); this.file_list = new FileList(this.list_site, this.list_inner_path); this.site_info = null; this.server_info = null; this.is_sidebar_closed = false; if (this.editor_inner_path) { this.file_editor = new FileEditor(this.editor_inner_path); } window.onbeforeunload = (function(_this) { return function() { var ref; if ((ref = _this.file_editor) != null ? ref.isModified() : void 0) { return true; } else { return null; } }; })(this); window.onresize = (function(_this) { return function() { return _this.checkBodyWidth(); }; })(this); this.checkBodyWidth(); this.cmd("wrapperSetViewport", "width=device-width, initial-scale=0.8"); this.cmd("serverInfo", {}, (function(_this) { return function(server_info) { return _this.server_info = server_info; }; })(this)); return this.cmd("siteInfo", {}, (function(_this) { return function(site_info) { _this.cmd("wrapperSetTitle", "List: /" + _this.list_inner_path + " - " + site_info.content.title + " - ZeroNet"); _this.site_info = site_info; if (_this.file_editor) { _this.file_editor.on_loaded.then(function() { _this.file_editor.cm.setOption("readOnly", !site_info.settings.own); return _this.file_editor.mode = site_info.settings.own ? "Edit" : "View"; }); } return _this.projector.scheduleRender(); }; })(this)); }; UiFileManager.prototype.checkBodyWidth = function() { var ref, ref1; if (!this.file_editor) { return false; } if (document.body.offsetWidth < 960 && !this.is_sidebar_closed) { this.is_sidebar_closed = true; return (ref = this.projector) != null ? ref.scheduleRender() : void 0; } else if (document.body.offsetWidth > 960 && this.is_sidebar_closed) { this.is_sidebar_closed = false; return (ref1 = this.projector) != null ? ref1.scheduleRender() : void 0; } }; UiFileManager.prototype.onRequest = function(cmd, message) { if (cmd === "setSiteInfo") { this.site_info = message; RateLimitCb(1000, (function(_this) { return function(cb_done) { return _this.file_list.update(cb_done); }; })(this)); return this.projector.scheduleRender(); } else if (cmd === "setServerInfo") { this.server_info = message; return this.projector.scheduleRender(); } else { return this.log("Unknown incoming message:", cmd); } }; UiFileManager.prototype.createProjector = function() { this.projector = maquette.createProjector(); return this.projector.replace($("#content"), this.render); }; UiFileManager.prototype.render = function() { return h("div.content#content", [ h("div.manager", { classes: { editing: this.file_editor, sidebar_closed: this.is_sidebar_closed } }, [this.file_list.render(), this.file_editor ? this.file_editor.render() : void 0]) ]); }; return UiFileManager; })(ZeroFrame); window.Page = new UiFileManager(); window.Page.createProjector(); }).call(this);