diff --git a/plugins/UiFileManager/media/css/all.css b/plugins/UiFileManager/media/css/all.css
new file mode 100644
index 00000000..cd9e16c6
--- /dev/null
+++ b/plugins/UiFileManager/media/css/all.css
@@ -0,0 +1,211 @@
+
+/* ---- Menu.css ---- */
+
+
+.menu {
+ background-color: white; padding: 10px 0px; position: absolute; top: 0px; max-height: 0px; overflow: hidden; -webkit-transform: translate(-100%, -30px); -moz-transform: translate(-100%, -30px); -o-transform: translate(-100%, -30px); -ms-transform: translate(-100%, -30px); transform: translate(-100%, -30px) ; pointer-events: none;
+ -webkit-box-shadow: 0px 2px 8px rgba(0,0,0,0.3); -moz-box-shadow: 0px 2px 8px rgba(0,0,0,0.3); -o-box-shadow: 0px 2px 8px rgba(0,0,0,0.3); -ms-box-shadow: 0px 2px 8px rgba(0,0,0,0.3); box-shadow: 0px 2px 8px rgba(0,0,0,0.3) ; -webkit-border-radius: 2px; -moz-border-radius: 2px; -o-border-radius: 2px; -ms-border-radius: 2px; border-radius: 2px ; opacity: 0; -webkit-transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; -moz-transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; -o-transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; -ms-transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out ; z-index: 99;
+ display: inline-block; z-index: 999; transform-style: preserve-3d;
+}
+.menu.menu-left { -webkit-transform: translate(0%, -30px); -moz-transform: translate(0%, -30px); -o-transform: translate(0%, -30px); -ms-transform: translate(0%, -30px); transform: translate(0%, -30px) ; }
+.menu.menu-left.visible { -webkit-transform: translate(0%, 0px); -moz-transform: translate(0%, 0px); -o-transform: translate(0%, 0px); -ms-transform: translate(0%, 0px); transform: translate(0%, 0px) ; }
+.menu.visible {
+ opacity: 1; -webkit-transform: translate(-100%, 0px); -moz-transform: translate(-100%, 0px); -o-transform: translate(-100%, 0px); -ms-transform: translate(-100%, 0px); transform: translate(-100%, 0px) ; pointer-events: all;
+ -webkit-transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s cubic-bezier(0.86, 0, 0.07, 1); -moz-transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s cubic-bezier(0.86, 0, 0.07, 1); -o-transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s cubic-bezier(0.86, 0, 0.07, 1); -ms-transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s cubic-bezier(0.86, 0, 0.07, 1); transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s cubic-bezier(0.86, 0, 0.07, 1) ;
+}
+
+.menu-item {
+ display: block; text-decoration: none; color: black; padding: 6px 24px; -webkit-transition: all 0.2s; -moz-transition: all 0.2s; -o-transition: all 0.2s; -ms-transition: all 0.2s; transition: all 0.2s ; border-bottom: none; font-weight: normal;
+ max-height: 150px; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 6; -webkit-box-orient: vertical; display: -webkit-box;
+}
+.menu-item-separator { margin-top: 3px; margin-bottom: 3px; border-top: 1px solid #eee }
+
+.menu-item.noaction { cursor: default }
+.menu-item:hover:not(.noaction) { background-color: #F6F6F6; -webkit-transition: none; -moz-transition: none; -o-transition: none; -ms-transition: none; transition: none ; color: inherit; cursor: pointer; color: black }
+.menu-item:active:not(.noaction), .menu-item:focus:not(.noaction) { background-color: #AF3BFF !important; color: white !important; -webkit-transition: none ; -moz-transition: none ; -o-transition: none ; -ms-transition: none ; transition: none }
+.menu-item.selected:before {
+ content: "L"; display: inline-block; -webkit-transform: rotateZ(45deg) scaleX(-1); -moz-transform: rotateZ(45deg) scaleX(-1); -o-transform: rotateZ(45deg) scaleX(-1); -ms-transform: rotateZ(45deg) scaleX(-1); transform: rotateZ(45deg) scaleX(-1) ;
+ font-weight: bold; position: absolute; margin-left: -14px; font-size: 12px; margin-top: 2px;
+}
+
+.menu-radio { white-space: normal; line-height: 26px }
+.menu-radio a {
+ background-color: #EEE; width: 18.5%;; text-align: center; margin-top: 2px; margin-bottom: 2px; color: #666; font-weight: bold;
+ text-decoration: none; font-size: 13px; -webkit-transition: all 0.3s; -moz-transition: all 0.3s; -o-transition: all 0.3s; -ms-transition: all 0.3s; transition: all 0.3s ; text-transform: uppercase; display: inline-block;
+}
+.menu-radio a:hover, .menu-radio a.selected { -webkit-transition: none; -moz-transition: none; -o-transition: none; -ms-transition: none; transition: none ; background-color: #AF3BFF !important; color: white !important }
+.menu-radio a.long { font-size: 10px; vertical-align: -1px; }
+
+
+/* ---- Selectbar.css ---- */
+
+
+.selectbar.visible { margin-top: 0px; visibility: visible }
+.selectbar {
+ position: fixed; top: 0; left: 0; background-color: white; -webkit-box-shadow: 0px 0px 25px rgba(22, 39, 97, 0.2); -moz-box-shadow: 0px 0px 25px rgba(22, 39, 97, 0.2); -o-box-shadow: 0px 0px 25px rgba(22, 39, 97, 0.2); -ms-box-shadow: 0px 0px 25px rgba(22, 39, 97, 0.2); box-shadow: 0px 0px 25px rgba(22, 39, 97, 0.2) ; margin-top: -75px;
+ -webkit-transition: all 0.3s; -moz-transition: all 0.3s; -o-transition: all 0.3s; -ms-transition: all 0.3s; transition: all 0.3s ; visibility: hidden; z-index: 9999; color: black; border-left: 5px solid #ede1f582; width: 100%;
+ padding: 13px; font-size: 13px; font-weight: lighter; -webkit-backface-visibility: hidden; -moz-backface-visibility: hidden; -o-backface-visibility: hidden; -ms-backface-visibility: hidden; backface-visibility: hidden ;
+}
+
+.selectbar .num { margin-left: 15px; min-width: 30px; text-align: right; display: inline-block; }
+.selectbar .size { margin-left: 10px; color: #9f9ba2; min-width: 75px; display: inline-block; }
+.selectbar .actions { display: inline-block; margin-left: 20px; font-size: 13px; text-transform: uppercase; line-height: 20px; }
+.selectbar .action { padding: 5px 20px; border: 1px solid #edd4ff; margin-left: 10px; -webkit-border-radius: 30px; -moz-border-radius: 30px; -o-border-radius: 30px; -ms-border-radius: 30px; border-radius: 30px ; color: #af3bff; text-decoration: none; -webkit-transition: all 0.3s ; -moz-transition: all 0.3s ; -o-transition: all 0.3s ; -ms-transition: all 0.3s ; transition: all 0.3s }
+.selectbar .action:hover { border-color: #c788f3; -webkit-transition: none; -moz-transition: none; -o-transition: none; -ms-transition: none; transition: none ; color: #9700ff }
+.selectbar .delete { color: #AAA; border-color: #DDD; }
+.selectbar .delete:hover { color: #333; border-color: #AAA }
+.selectbar .action:active { background-color: #af3bff; color: white; border-color: #af3bff; -webkit-transition: none ; -moz-transition: none ; -o-transition: none ; -ms-transition: none ; transition: none }
+.selectbar .cancel { margin: 20px; font-size: 10px; text-decoration: none; color: #999; text-transform: uppercase; }
+.selectbar .cancel:hover { color: #333; -webkit-transition: none ; -moz-transition: none ; -o-transition: none ; -ms-transition: none ; transition: none }
+
+/* ---- UiFileManager.css ---- */
+
+
+body { background-color: #EEEEF5; font-family: "Segoe UI", Helvetica, Arial; height: 95000px; overflow: hidden; }
+body.loaded { height: auto; overflow: auto }
+h1 { font-weight: lighter; }
+
+a { color: #333 }
+a:hover { text-decoration: none }
+input::placeholder { color: rgba(255, 255, 255, 0.3) }
+
+h2 { font-weight: lighter; }
+
+.link { background-color: transparent; outline: 5px solid transparent; -webkit-transition: all 0.3s ; -moz-transition: all 0.3s ; -o-transition: all 0.3s ; -ms-transition: all 0.3s ; transition: all 0.3s }
+.link:active { background-color: #fbf5ff; outline: 5px solid #fbf5ff; -webkit-transition: none ; -moz-transition: none ; -o-transition: none ; -ms-transition: none ; transition: none }
+
+.manager.editing .files { float: left; width: 280px; }
+
+.sidebar-button {
+ display: inline-block; padding: 25px 19px; text-decoration: none; position: absolute;
+ border-right: 1px solid #EEE; line-height: 10px; color: #7801F5; transition: all 0.3s
+}
+.sidebar-button:active { background-color: #f5e7ff; -webkit-transition: none ; -moz-transition: none ; -o-transition: none ; -ms-transition: none ; transition: none }
+/*.sidebar-button:hover { background-color: #fbf5ff; }*/
+.sidebar-button span { -webkit-transition: 1s all; -moz-transition: 1s all; -o-transition: 1s all; -ms-transition: 1s all; transition: 1s all ; transform-origin: 2.5px 7px; display: inline-block; }
+.manager.sidebar_closed .sidebar-button span { -webkit-transform: rotateZ(180deg); -moz-transform: rotateZ(180deg); -o-transform: rotateZ(180deg); -ms-transform: rotateZ(180deg); transform: rotateZ(180deg) ; }
+.manager.sidebar_closed .files { margin-left: -300px; }
+.manager.sidebar_closed .editor { width: 100%; }
+
+.button {
+ padding: 5px 10px; margin-left: 10px; background-color: #752ff2; border-bottom: 2px solid #caadff; background-position: -50px center;
+ -webkit-border-radius: 2px; -moz-border-radius: 2px; -o-border-radius: 2px; -ms-border-radius: 2px; border-radius: 2px ; text-decoration: none; -webkit-transition: all 0.5s ease-out; -moz-transition: all 0.5s ease-out; -o-transition: all 0.5s ease-out; -ms-transition: all 0.5s ease-out; transition: all 0.5s ease-out ; display: inline-block;
+ color: #333; font-size: 12px; vertical-align: 2px; text-transform: uppercase; color: white; max-width: 100px;
+}
+.button:hover { background-color: #9e71ed; -webkit-transition: none; -moz-transition: none; -o-transition: none; -ms-transition: none; transition: none ; }
+.button:active { position: relative; top: 1px }
+.button.loading, .button.disabled { color: rgba(255,255,255,0.7);; pointer-events: none; border-bottom: 2px solid #666; background-color: #999; }
+.button.loading { background: #999 url(../img/loading.gif) no-repeat center center; -webkit-transition: all 0.5s ease-out; -moz-transition: all 0.5s ease-out; -o-transition: all 0.5s ease-out; -ms-transition: all 0.5s ease-out; transition: all 0.5s ease-out ; color: rgba(0,0,0,0); }
+.button.done { background-color: #4dc758; -webkit-transition: all 0.3s; -moz-transition: all 0.3s; -o-transition: all 0.3s; -ms-transition: all 0.3s; transition: all 0.3s ; border-color: #4dc758; pointer-events: none; }
+.button.hidden { max-width: 0px; display: inline-block; padding-left: 0px; padding-right: 0px; margin: 0px; }
+
+/* List */
+
+.files {
+ width: 97%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -o-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box ; color: #555; position: relative; z-index: 1; -webkit-transition: all 0.6s; -moz-transition: all 0.6s; -o-transition: all 0.6s; -ms-transition: all 0.6s; transition: all 0.6s ;
+ font-size: 14px; -webkit-box-shadow: 0px 9px 20px -15px #a5cbec; -moz-box-shadow: 0px 9px 20px -15px #a5cbec; -o-box-shadow: 0px 9px 20px -15px #a5cbec; -ms-box-shadow: 0px 9px 20px -15px #a5cbec; box-shadow: 0px 9px 20px -15px #a5cbec ; max-width: 400px; border: 1px solid #EEEEF5;
+}
+.files .tr { white-space: nowrap }
+.files .td { display: inline-block; width: 60px }
+.files .tbody .td { line-height: 18px; vertical-align: bottom; }
+.files .td.name { min-width: 100px }
+.files .td.size { width: 60px; text-align: right; padding-left: 5px; }
+.files .td.status { text-align: right; }
+.files .td.peer { width: 60px }
+.files .td.uploaded { width: 130px; text-align: right; }
+.files .td.added { width: 90px }
+.files .orderby { color: inherit; text-decoration: none; -webkit-transition: all 0.3s; -moz-transition: all 0.3s; -o-transition: all 0.3s; -ms-transition: all 0.3s; transition: all 0.3s ; outline: 5px solid transparent; }
+.files .orderby:hover { text-decoration: underline; }
+.files .orderby .icon-arrow-down { opacity: 0; -webkit-transition: all 0.3s ease-in-out; -moz-transition: all 0.3s ease-in-out; -o-transition: all 0.3s ease-in-out; -ms-transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out ; }
+.files .orderby.selected .icon-arrow-down { opacity: 0.3; }
+.files .orderby:active { background-color: rgba(133, 239, 255, 0.09); outline: 5px solid rgba(133, 239, 255, 0.09); -webkit-transition: none; -moz-transition: none; -o-transition: none; -ms-transition: none; transition: none ; }
+.files .orderby:hover .icon-arrow-down { opacity: 0.5; }
+.files .orderby:not(.desc) .icon-arrow-down { -webkit-transform: rotateZ(180deg); -moz-transform: rotateZ(180deg); -o-transform: rotateZ(180deg); -ms-transform: rotateZ(180deg); transform: rotateZ(180deg) ; }
+.files .tr.editing .td { background-color: #ede1f582; border-top-color: #ece9ef; }
+.files .thead { /*background: -webkit-linear-gradient(358deg, #e7f1f7, #e9f2f72e);background: -moz-linear-gradient(358deg, #e7f1f7, #e9f2f72e);background: -o-linear-gradient(358deg, #e7f1f7, #e9f2f72e);background: -ms-linear-gradient(358deg, #e7f1f7, #e9f2f72e);background: linear-gradient(358deg, #e7f1f7, #e9f2f72e);*/ }
+.files .thead .td {
+ border-top: none; color: #8984c2; background-color: #f7f7fc;
+ font-size: 12px; /*text-transform: uppercase; background-color: transparent; font-weight: bold;*/
+}
+.files .thead .td a:last-of-type { font-weight: bold; }
+.files .thead .td a { text-decoration: none; }
+.files .thead .td a:hover { text-decoration: underline; }
+.files .tbody { max-height: calc(100vh - 100x); overflow-y: auto; overflow-x: hidden; }
+.files .tr { background-color: white; }
+.files .td { padding: 10px 20px; border-top: 1px solid #EEE; font-size: 13px; white-space: nowrap; }
+.files .td.full { width: 100%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -o-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box ; white-space: pre-line; }
+.files .td.pre { width: 0px; color: transparent; padding-left: 0px; border-left: 2px solid transparent; }
+.files .tbody .td { height: 18px; }
+.files .tbody .td.full { height: auto; }
+.files .td.pre .checkbox-outer { opacity: 0.6; margin-left: -11px; margin-top: -15px; width: 18px; height: 12px; display: inline-block; }
+.files .tr.modified .td.pre { border-left-color: #7801F5 }
+.files .tr.added .td.pre { border-left-color: #00ec93 }
+.files .tr.ignored .td.pre { border-left-color: #999; }
+.files .tr.ignored { opacity: 0.5; }
+.files .tr.optional { background: -webkit-linear-gradient(90deg, #fff6dd, 30%, white, 10%, white);background: -moz-linear-gradient(90deg, #fff6dd, 30%, white, 10%, white);background: -o-linear-gradient(90deg, #fff6dd, 30%, white, 10%, white);background: -ms-linear-gradient(90deg, #fff6dd, 30%, white, 10%, white);background: linear-gradient(90deg, #fff6dd, 30%, white, 10%, white); }
+.files .tr.optional_empty { color: #999; font-style: italic; }
+.files .td.error { background-color: #F44336; color: white; }
+.files .td.site { width: 70px }
+.files .td.site .link { color: inherit; text-decoration: none }
+.files .td.status .percent {
+ -webkit-transition: all 1s ease-in-out; -moz-transition: all 1s ease-in-out; -o-transition: all 1s ease-in-out; -ms-transition: all 1s ease-in-out; transition: all 1s ease-in-out ; display: inline-block; width: 80px; background-color: #EEE; font-size: 10px;
+ height: 15px; line-height: 15px; text-align: center; margin-right: 20px;
+}
+.files .td.name { padding-left: 10px; width: calc(100% - 167px); max-height: 18px; padding-right: 10px; }
+.files .tr.nobuttons .td.name { width: calc(100% - 127px); }
+.files .tr.nobuttons .td.buttons { width: 0px; }
+.files .td.name .title { color: inherit; text-decoration: none }
+.files .td.name .link { display: inline-block; overflow: hidden; text-overflow: ellipsis; vertical-align: -4px; max-width: 100%; }
+.files .pinned .td.name .link { max-width: calc(100% - 40px); }
+.files .thead .td.uploaded { text-align: left }
+.files .thead .td.uploaded .title { padding-left: 7px; }
+.files .peer .icon-profile { background: currentColor; color: #47d094; font-size: 10px; top: 1px; margin-right: 13px }
+.files .peer .icon-profile:before { background: currentColor }
+.files .peer .num { color: #969696; }
+.files .uploaded .uploaded-text { display: inline-block; text-align: right; }
+.files .uploaded .dots-container { display: inline-block; width: 0px; padding-right: 65px;; }
+.files .td.buttons { width: 40px; padding-left: 0px; padding-right: 0px; }
+.files .td.buttons .edit {
+ background-color: #2196f336; -webkit-border-radius: 15px; -moz-border-radius: 15px; -o-border-radius: 15px; -ms-border-radius: 15px; border-radius: 15px ; padding: 1px 9px; font-size: 80%; text-decoration: none; color: #1976D2;
+}
+.files .checkbox-outer { padding: 15px; padding-left: 20px; padding-right: 0px; }
+.files .checkbox {
+ display: inline-block; width: 12px; height: 12px; border: 2px solid #00000014;
+ -webkit-border-radius: 3px; -moz-border-radius: 3px; -o-border-radius: 3px; -ms-border-radius: 3px; border-radius: 3px ; vertical-align: -3px; margin-right: 10px;
+}
+.files .selected .checkbox { border-color: #dedede }
+.files .selected .checkbox:after {
+ background-color: #dedede; content: ""; text-decoration: none; display: block; width: 10px; height: 10px; margin-left: 1px; margin-top: 1px;
+}
+.files .tbody .td.size { font-size: 13px }
+.files .tbody .td.added, #PageFiles .files .td.access { font-size: 12px; color: #999 }
+.files .tr.type-dir .name { font-weight: bold; }
+.files .tr.type-parent .name .link { display: inline-block; width: 100%; padding: 5px; margin-top: -5px; }
+.files .foot .td { color: #a4a4a4; background-color: #f7f7fc; }
+.files .foot .create { float: right; text-decoration: none; position: relative; }
+.files .foot .create .link { color: #8c42ed; text-decoration: none; }
+.files .foot .create .link:active { background-color: #8c42ed3b; outline: 5px solid #8c42ed3b; }
+.files .foot .create .menu { top: 40px; }
+
+
+/* Editor */
+
+.editor { background-color: #F7F7FC; float: left; width: calc(100% - 280px); -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -o-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box ; -webkit-transition: all 0.6s; -moz-transition: all 0.6s; -o-transition: all 0.6s; -ms-transition: all 0.6s; transition: all 0.6s ; }
+.editor .CodeMirror { height: calc(100vh - 73px); visibility: hidden; }
+.editor textarea { width: 100%; height: 800px; white-space: pre; }
+.editor .title { margin-left: 20px; }
+.editor .editor-head {
+ padding: 15px 20px; padding-left: 45px; font-size: 18px; font-weight: lighter; border: 1px solid #EEEEF5;
+ white-space: nowrap; overflow: hidden;
+}
+.editor.loaded .CodeMirror { visibility: inherit; }
+.editor.error .CodeMirror { display: none; }
+.editor .button.save { min-width: 30px; text-align: center; -webkit-transition: all 0.3s; -moz-transition: all 0.3s; -o-transition: all 0.3s; -ms-transition: all 0.3s; transition: all 0.3s ; }
+.editor .button.save.done { min-width: 80px; }
+.editor .error-message { text-align: center; padding: 50px; }
+
+.editor .CodeMirror-foldmarker {
+ line-height: .3; cursor: pointer; background-color: #ffeb3b61; text-shadow: none; font-family: inherit;
+ color: #050505; border: 1px solid #ffdf7f; padding: 0px 5px;
+}
+.editor .CodeMirror-activeline-background { background-color: #F6F6F6 !important; }
\ No newline at end of file
diff --git a/plugins/UiFileManager/media/js/all.js b/plugins/UiFileManager/media/js/all.js
new file mode 100644
index 00000000..eae5fc11
--- /dev/null
+++ b/plugins/UiFileManager/media/js/all.js
@@ -0,0 +1,3013 @@
+
+/* ---- 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, "$1@zeroid.bit");
+ };
+
+ 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