├── .gitignore ├── favicon.png ├── img ├── icon.png ├── logo.png ├── logo-white.svg └── logo.svg ├── css ├── fonts │ ├── roboto-light.eot │ ├── roboto-light.ttf │ ├── roboto-light.woff │ ├── roboto-regular.eot │ ├── roboto-regular.ttf │ ├── roboto-regular.woff │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── grids-responsive-min.css ├── simplemde.min.css ├── pure-min.css ├── blog.css └── font-awesome.min.css ├── config-example.json ├── manifest.json ├── LICENSE ├── README.md ├── js ├── dropdown.js └── moment.min.js ├── index.html └── app ├── solid.js └── app.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | config.json 3 | posts/ 4 | -------------------------------------------------------------------------------- /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/favicon.png -------------------------------------------------------------------------------- /img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/img/icon.png -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/img/logo.png -------------------------------------------------------------------------------- /css/fonts/roboto-light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/roboto-light.eot -------------------------------------------------------------------------------- /css/fonts/roboto-light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/roboto-light.ttf -------------------------------------------------------------------------------- /css/fonts/roboto-light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/roboto-light.woff -------------------------------------------------------------------------------- /css/fonts/roboto-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/roboto-regular.eot -------------------------------------------------------------------------------- /css/fonts/roboto-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/roboto-regular.ttf -------------------------------------------------------------------------------- /css/fonts/roboto-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/roboto-regular.woff -------------------------------------------------------------------------------- /css/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /css/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /css/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /css/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deiu/solid-plume/HEAD/css/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /config-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "owners": [""], 3 | "title": "Plume", 4 | "tagline": "Light as a feather", 5 | "picture": "img/logo.svg", 6 | "fadeText": true, 7 | "showSources": true, 8 | "cacheUnit": "days", 9 | "defaultPath": "posts", 10 | "postsURL": "" 11 | } -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Plume", 3 | "icons": [ 4 | { 5 | "src": "img/favicon.png", 6 | "sizes": "256x256", 7 | "type": "image/icon.png", 8 | "density": "4.0" 9 | } 10 | ], 11 | "start_url": "index.html", 12 | "display": "standalone", 13 | "orientation": "portrait" 14 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Andrei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /img/logo-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 10 | 19 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | 10 | 20 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plume 2 | 3 | 4 | 5 | *Plume* is a 100% client-side blogging platform, built using [Solid standards](https://github.com/solid/), in which data is decoupled from the application itself. This means that you can host the application on any Web server, without having to install anything -- no database, no messing around with Node.js, it has 0 dependencies! It also means that other similar applications will be able to reuse the data resulting from your posts, without having to go through a complicated API. 6 | 7 | Plume uses [Markdown](https://en.wikipedia.org/wiki/Markdown) to provide you with the easiest and fastest experience for writing beautiful articles. 8 | 9 | It currently does not support dynamic configuration of data spaces, which means you will have to either run it on your own Web server, or manually upload it to your account -- you can use [https://databox.me]( https://databox.me) as storage. The next version will allow you to run it from Github, like all the other [Solid apps](https://github.com/solid/solid-apps) we currently offer. 10 | 11 | ## Configuration 12 | 13 | Before being able to use Plume, you will have to manually set some config values. First you need to copy/rename the `config-example.json` file to `config.json`. Then you need to set the `postsURL` value to have it point to an **existing** container on a [Solid-friendly server](https://github.com/solid/solid-platform) that holds your blog posts. Finally, you should also set the `owners` variable by adding your own WebID, in order to be able to access the editor UI and to create new posts. 14 | 15 | Here is an example of the configuration file: 16 | 17 | ``` 18 | { 19 | "owners": ["https://example.org/profile#me"], 20 | "title": "Plume", 21 | "tagline": "Light as a feather", 22 | "picture": "img/logo.svg", 23 | "fadeText": true, 24 | "showSources": true, 25 | "cacheUnit": "days", 26 | "defaultPath": "posts", 27 | "postsURL": "https://account.databox.me/Public/blog/posts/" 28 | } 29 | ``` 30 | 31 | Here is what each config parameter means: 32 | 33 | * `owner`: a list of URLs (WebIDs) of the people who can post on the blog 34 | * `title`: the title of the blog 35 | * `tagline`: tagline/subtitle 36 | * `picture`: the picture to display on the blog's header 37 | * `fadeText`: true/false - shortens the posts length when viewing the full blog 38 | * `showSources`: true/false - it will add a button/link that points to the source of the blog post (the actual resource) 39 | * `cacheUnit`: minutes/hours/days/ - validity of certain cached data (you shouldn't really need to change it) 40 | * `defaultPath`: this value will be suggested to the user if the blog needs to be initialized 41 | * `postsURL`: the URL of the folder (container) holding the posts for the blog 42 | -------------------------------------------------------------------------------- /js/dropdown.js: -------------------------------------------------------------------------------- 1 | (function (window, document) { 2 | 'use strict'; 3 | 4 | // Enable drop-down menus in Pure 5 | // Inspired by YUI3 gallery-simple-menu by Julien LeComte 6 | // [https://github.com/yui/yui3-gallery/blob/master/src/gallery-simple-menu/js/simple-menu.js] 7 | 8 | function PureDropdown(dropdownParent) { 9 | 10 | var PREFIX = 'pure-', 11 | ACTIVE_CLASS_NAME = PREFIX + 'menu-active', 12 | ARIA_ROLE = 'role', 13 | ARIA_HIDDEN = 'aria-hidden', 14 | MENU_OPEN = 0, 15 | MENU_CLOSED = 1, 16 | MENU_PARENT_CLASS_NAME = 'pure-menu-has-children', 17 | MENU_ACTIVE_SELECTOR = '.pure-menu-active', 18 | MENU_LINK_SELECTOR = '.pure-menu-link', 19 | MENU_SELECTOR = '.pure-menu-children', 20 | DISMISS_EVENT = (window.hasOwnProperty && 21 | window.hasOwnProperty('ontouchstart')) ? 22 | 'touchstart' : 'mousedown', 23 | 24 | ARROW_KEYS_ENABLED = true, 25 | 26 | ddm = this; // drop down menu 27 | 28 | this._state = MENU_CLOSED; 29 | 30 | this.show = function () { 31 | if (this._state !== MENU_OPEN) { 32 | this._dropdownParent.classList.add(ACTIVE_CLASS_NAME); 33 | this._menu.setAttribute(ARIA_HIDDEN, false); 34 | this._state = MENU_OPEN; 35 | } 36 | }; 37 | 38 | this.hide = function () { 39 | if (this._state !== MENU_CLOSED) { 40 | this._dropdownParent.classList.remove(ACTIVE_CLASS_NAME); 41 | this._menu.setAttribute(ARIA_HIDDEN, true); 42 | this._link.focus(); 43 | this._state = MENU_CLOSED; 44 | } 45 | }; 46 | 47 | this.toggle = function () { 48 | this[this._state === MENU_CLOSED ? 'show' : 'hide'](); 49 | }; 50 | 51 | this.halt = function (e) { 52 | e.stopPropagation(); 53 | e.preventDefault(); 54 | }; 55 | 56 | this._dropdownParent = dropdownParent; 57 | this._link = this._dropdownParent.querySelector(MENU_LINK_SELECTOR); 58 | this._menu = this._dropdownParent.querySelector(MENU_SELECTOR); 59 | this._firstMenuLink = this._menu.querySelector(MENU_LINK_SELECTOR); 60 | 61 | // Set ARIA attributes 62 | this._link.setAttribute('aria-haspopup', 'true'); 63 | this._menu.setAttribute(ARIA_ROLE, 'menu'); 64 | this._menu.setAttribute('aria-labelledby', this._link.getAttribute('id')); 65 | this._menu.setAttribute('aria-hidden', 'true'); 66 | [].forEach.call( 67 | this._menu.querySelectorAll('li'), 68 | function(el){ 69 | el.setAttribute(ARIA_ROLE, 'presentation'); 70 | } 71 | ); 72 | [].forEach.call( 73 | this._menu.querySelectorAll('a'), 74 | function(el){ 75 | el.setAttribute(ARIA_ROLE, 'menuitem'); 76 | } 77 | ); 78 | 79 | // Toggle on click 80 | this._link.addEventListener('click', function (e) { 81 | e.stopPropagation(); 82 | e.preventDefault(); 83 | ddm.toggle(); 84 | }); 85 | 86 | // Keyboard navigation 87 | document.addEventListener('keydown', function (e) { 88 | var currentLink, 89 | previousSibling, 90 | nextSibling, 91 | previousLink, 92 | nextLink; 93 | 94 | // if the menu isn't active, ignore 95 | if (ddm._state !== MENU_OPEN) { 96 | return; 97 | } 98 | 99 | // if the menu is the parent of an open, active submenu, ignore 100 | if (ddm._menu.querySelector(MENU_ACTIVE_SELECTOR)) { 101 | return; 102 | } 103 | 104 | currentLink = ddm._menu.querySelector(':focus'); 105 | 106 | // Dismiss an open menu on ESC 107 | if (e.keyCode === 27) { 108 | /* Esc */ 109 | ddm.halt(e); 110 | ddm.hide(); 111 | } 112 | // Go to the next link on down arrow 113 | else if (ARROW_KEYS_ENABLED && e.keyCode === 40) { 114 | /* Down arrow */ 115 | ddm.halt(e); 116 | // get the nextSibling (an LI) of the current link's LI 117 | nextSibling = (currentLink) ? currentLink.parentNode.nextSibling : null; 118 | // if the nextSibling is a text node (not an element), go to the next one 119 | while (nextSibling && nextSibling.nodeType !== 1) { 120 | nextSibling = nextSibling.nextSibling; 121 | } 122 | nextLink = (nextSibling) ? nextSibling.querySelector('.pure-menu-link') : null; 123 | // if there is no currently focused link, focus the first one 124 | if (!currentLink) { 125 | ddm._menu.querySelector('.pure-menu-link').focus(); 126 | } 127 | else if (nextLink) { 128 | nextLink.focus(); 129 | } 130 | } 131 | // Go to the previous link on up arrow 132 | else if (ARROW_KEYS_ENABLED && e.keyCode === 38) { 133 | /* Up arrow */ 134 | ddm.halt(e); 135 | // get the currently focused link 136 | previousSibling = (currentLink) ? currentLink.parentNode.previousSibling : null; 137 | while (previousSibling && previousSibling.nodeType !== 1) { 138 | previousSibling = previousSibling.previousSibling; 139 | } 140 | previousLink = (previousSibling) ? previousSibling.querySelector('.pure-menu-link') : null; 141 | // if there is no currently focused link, focus the last link 142 | if (!currentLink) { 143 | ddm._menu.querySelector('.pure-menu-item:last-child .pure-menu-link').focus(); 144 | } 145 | // else if there is a previous item, go to the previous item 146 | else if (previousLink) { 147 | previousLink.focus(); 148 | } 149 | } 150 | }); 151 | 152 | // Dismiss an open menu on outside event 153 | document.addEventListener(DISMISS_EVENT, function (e) { 154 | var target = e.target; 155 | if (target !== ddm._link && !ddm._menu.contains(target)) { 156 | ddm.hide(); 157 | ddm._link.blur(); 158 | } 159 | }); 160 | 161 | } 162 | 163 | function initDropdowns() { 164 | var dropdownParents = document.querySelectorAll('.pure-menu-has-children'); 165 | for (var i = 0; i < dropdownParents.length; i++) { 166 | var ddm = new PureDropdown(dropdownParents[i]); 167 | } 168 | } 169 | 170 | initDropdowns(); 171 | 172 | }(this, this.document)); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Plume 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 29 | 34 | 35 |
36 | 37 | 45 | 46 | 50 | 51 | 81 | 82 | 83 |
84 | 85 | 86 |
87 | 88 | 89 | 93 | 94 | 95 | 102 | 103 | 104 | 112 | 113 | 114 | 121 |
122 |
123 | 124 |
125 |
126 |

What is a WebID?

127 |

128 | A WebID is a URL for you. It allows you to set up a reusable identity 129 | and a profile, with friends, pictures and all kinds of things. 130 |

131 |

132 | Unlike social networks, with WebID you reuse your identity and personal 133 | data in a decentralized, privacy-friendly way, across multiple applications 134 | and services on the Web. It works like having an account on a social 135 | networking site, but it isn't restricted to just that site. It is very 136 | open because the information can connect to other people, apps, projects 137 | and so on, without everyone having to join the same social networking site. 138 | (more information) 139 |

140 |

141 | When you create a WebID account, you may also get storage space on the 142 | selected server. The amount of available space can vary from server to 143 | server. Additionally, a common list of workspaces (i.e. dedicated folders) 144 | maye be created by default, such as Public, Private, 145 | Family, Work, etc. 146 |

147 | 148 |
149 |
150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /css/grids-responsive-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.6.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yahoo/pure/blob/master/LICENSE.md 6 | */ 7 | @media screen and (min-width:35.5em){.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-1-2,.pure-u-sm-1-3,.pure-u-sm-2-3,.pure-u-sm-1-4,.pure-u-sm-3-4,.pure-u-sm-1-5,.pure-u-sm-2-5,.pure-u-sm-3-5,.pure-u-sm-4-5,.pure-u-sm-5-5,.pure-u-sm-1-6,.pure-u-sm-5-6,.pure-u-sm-1-8,.pure-u-sm-3-8,.pure-u-sm-5-8,.pure-u-sm-7-8,.pure-u-sm-1-12,.pure-u-sm-5-12,.pure-u-sm-7-12,.pure-u-sm-11-12,.pure-u-sm-1-24,.pure-u-sm-2-24,.pure-u-sm-3-24,.pure-u-sm-4-24,.pure-u-sm-5-24,.pure-u-sm-6-24,.pure-u-sm-7-24,.pure-u-sm-8-24,.pure-u-sm-9-24,.pure-u-sm-10-24,.pure-u-sm-11-24,.pure-u-sm-12-24,.pure-u-sm-13-24,.pure-u-sm-14-24,.pure-u-sm-15-24,.pure-u-sm-16-24,.pure-u-sm-17-24,.pure-u-sm-18-24,.pure-u-sm-19-24,.pure-u-sm-20-24,.pure-u-sm-21-24,.pure-u-sm-22-24,.pure-u-sm-23-24,.pure-u-sm-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-sm-1-24{width:4.1667%;*width:4.1357%}.pure-u-sm-1-12,.pure-u-sm-2-24{width:8.3333%;*width:8.3023%}.pure-u-sm-1-8,.pure-u-sm-3-24{width:12.5%;*width:12.469%}.pure-u-sm-1-6,.pure-u-sm-4-24{width:16.6667%;*width:16.6357%}.pure-u-sm-1-5{width:20%;*width:19.969%}.pure-u-sm-5-24{width:20.8333%;*width:20.8023%}.pure-u-sm-1-4,.pure-u-sm-6-24{width:25%;*width:24.969%}.pure-u-sm-7-24{width:29.1667%;*width:29.1357%}.pure-u-sm-1-3,.pure-u-sm-8-24{width:33.3333%;*width:33.3023%}.pure-u-sm-3-8,.pure-u-sm-9-24{width:37.5%;*width:37.469%}.pure-u-sm-2-5{width:40%;*width:39.969%}.pure-u-sm-5-12,.pure-u-sm-10-24{width:41.6667%;*width:41.6357%}.pure-u-sm-11-24{width:45.8333%;*width:45.8023%}.pure-u-sm-1-2,.pure-u-sm-12-24{width:50%;*width:49.969%}.pure-u-sm-13-24{width:54.1667%;*width:54.1357%}.pure-u-sm-7-12,.pure-u-sm-14-24{width:58.3333%;*width:58.3023%}.pure-u-sm-3-5{width:60%;*width:59.969%}.pure-u-sm-5-8,.pure-u-sm-15-24{width:62.5%;*width:62.469%}.pure-u-sm-2-3,.pure-u-sm-16-24{width:66.6667%;*width:66.6357%}.pure-u-sm-17-24{width:70.8333%;*width:70.8023%}.pure-u-sm-3-4,.pure-u-sm-18-24{width:75%;*width:74.969%}.pure-u-sm-19-24{width:79.1667%;*width:79.1357%}.pure-u-sm-4-5{width:80%;*width:79.969%}.pure-u-sm-5-6,.pure-u-sm-20-24{width:83.3333%;*width:83.3023%}.pure-u-sm-7-8,.pure-u-sm-21-24{width:87.5%;*width:87.469%}.pure-u-sm-11-12,.pure-u-sm-22-24{width:91.6667%;*width:91.6357%}.pure-u-sm-23-24{width:95.8333%;*width:95.8023%}.pure-u-sm-1,.pure-u-sm-1-1,.pure-u-sm-5-5,.pure-u-sm-24-24{width:100%}}@media screen and (min-width:48em){.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-1-2,.pure-u-md-1-3,.pure-u-md-2-3,.pure-u-md-1-4,.pure-u-md-3-4,.pure-u-md-1-5,.pure-u-md-2-5,.pure-u-md-3-5,.pure-u-md-4-5,.pure-u-md-5-5,.pure-u-md-1-6,.pure-u-md-5-6,.pure-u-md-1-8,.pure-u-md-3-8,.pure-u-md-5-8,.pure-u-md-7-8,.pure-u-md-1-12,.pure-u-md-5-12,.pure-u-md-7-12,.pure-u-md-11-12,.pure-u-md-1-24,.pure-u-md-2-24,.pure-u-md-3-24,.pure-u-md-4-24,.pure-u-md-5-24,.pure-u-md-6-24,.pure-u-md-7-24,.pure-u-md-8-24,.pure-u-md-9-24,.pure-u-md-10-24,.pure-u-md-11-24,.pure-u-md-12-24,.pure-u-md-13-24,.pure-u-md-14-24,.pure-u-md-15-24,.pure-u-md-16-24,.pure-u-md-17-24,.pure-u-md-18-24,.pure-u-md-19-24,.pure-u-md-20-24,.pure-u-md-21-24,.pure-u-md-22-24,.pure-u-md-23-24,.pure-u-md-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-md-1-24{width:4.1667%;*width:4.1357%}.pure-u-md-1-12,.pure-u-md-2-24{width:8.3333%;*width:8.3023%}.pure-u-md-1-8,.pure-u-md-3-24{width:12.5%;*width:12.469%}.pure-u-md-1-6,.pure-u-md-4-24{width:16.6667%;*width:16.6357%}.pure-u-md-1-5{width:20%;*width:19.969%}.pure-u-md-5-24{width:20.8333%;*width:20.8023%}.pure-u-md-1-4,.pure-u-md-6-24{width:25%;*width:24.969%}.pure-u-md-7-24{width:29.1667%;*width:29.1357%}.pure-u-md-1-3,.pure-u-md-8-24{width:33.3333%;*width:33.3023%}.pure-u-md-3-8,.pure-u-md-9-24{width:37.5%;*width:37.469%}.pure-u-md-2-5{width:40%;*width:39.969%}.pure-u-md-5-12,.pure-u-md-10-24{width:41.6667%;*width:41.6357%}.pure-u-md-11-24{width:45.8333%;*width:45.8023%}.pure-u-md-1-2,.pure-u-md-12-24{width:50%;*width:49.969%}.pure-u-md-13-24{width:54.1667%;*width:54.1357%}.pure-u-md-7-12,.pure-u-md-14-24{width:58.3333%;*width:58.3023%}.pure-u-md-3-5{width:60%;*width:59.969%}.pure-u-md-5-8,.pure-u-md-15-24{width:62.5%;*width:62.469%}.pure-u-md-2-3,.pure-u-md-16-24{width:66.6667%;*width:66.6357%}.pure-u-md-17-24{width:70.8333%;*width:70.8023%}.pure-u-md-3-4,.pure-u-md-18-24{width:75%;*width:74.969%}.pure-u-md-19-24{width:79.1667%;*width:79.1357%}.pure-u-md-4-5{width:80%;*width:79.969%}.pure-u-md-5-6,.pure-u-md-20-24{width:83.3333%;*width:83.3023%}.pure-u-md-7-8,.pure-u-md-21-24{width:87.5%;*width:87.469%}.pure-u-md-11-12,.pure-u-md-22-24{width:91.6667%;*width:91.6357%}.pure-u-md-23-24{width:95.8333%;*width:95.8023%}.pure-u-md-1,.pure-u-md-1-1,.pure-u-md-5-5,.pure-u-md-24-24{width:100%}}@media screen and (min-width:64em){.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-1-2,.pure-u-lg-1-3,.pure-u-lg-2-3,.pure-u-lg-1-4,.pure-u-lg-3-4,.pure-u-lg-1-5,.pure-u-lg-2-5,.pure-u-lg-3-5,.pure-u-lg-4-5,.pure-u-lg-5-5,.pure-u-lg-1-6,.pure-u-lg-5-6,.pure-u-lg-1-8,.pure-u-lg-3-8,.pure-u-lg-5-8,.pure-u-lg-7-8,.pure-u-lg-1-12,.pure-u-lg-5-12,.pure-u-lg-7-12,.pure-u-lg-11-12,.pure-u-lg-1-24,.pure-u-lg-2-24,.pure-u-lg-3-24,.pure-u-lg-4-24,.pure-u-lg-5-24,.pure-u-lg-6-24,.pure-u-lg-7-24,.pure-u-lg-8-24,.pure-u-lg-9-24,.pure-u-lg-10-24,.pure-u-lg-11-24,.pure-u-lg-12-24,.pure-u-lg-13-24,.pure-u-lg-14-24,.pure-u-lg-15-24,.pure-u-lg-16-24,.pure-u-lg-17-24,.pure-u-lg-18-24,.pure-u-lg-19-24,.pure-u-lg-20-24,.pure-u-lg-21-24,.pure-u-lg-22-24,.pure-u-lg-23-24,.pure-u-lg-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-lg-1-24{width:4.1667%;*width:4.1357%}.pure-u-lg-1-12,.pure-u-lg-2-24{width:8.3333%;*width:8.3023%}.pure-u-lg-1-8,.pure-u-lg-3-24{width:12.5%;*width:12.469%}.pure-u-lg-1-6,.pure-u-lg-4-24{width:16.6667%;*width:16.6357%}.pure-u-lg-1-5{width:20%;*width:19.969%}.pure-u-lg-5-24{width:20.8333%;*width:20.8023%}.pure-u-lg-1-4,.pure-u-lg-6-24{width:25%;*width:24.969%}.pure-u-lg-7-24{width:29.1667%;*width:29.1357%}.pure-u-lg-1-3,.pure-u-lg-8-24{width:33.3333%;*width:33.3023%}.pure-u-lg-3-8,.pure-u-lg-9-24{width:37.5%;*width:37.469%}.pure-u-lg-2-5{width:40%;*width:39.969%}.pure-u-lg-5-12,.pure-u-lg-10-24{width:41.6667%;*width:41.6357%}.pure-u-lg-11-24{width:45.8333%;*width:45.8023%}.pure-u-lg-1-2,.pure-u-lg-12-24{width:50%;*width:49.969%}.pure-u-lg-13-24{width:54.1667%;*width:54.1357%}.pure-u-lg-7-12,.pure-u-lg-14-24{width:58.3333%;*width:58.3023%}.pure-u-lg-3-5{width:60%;*width:59.969%}.pure-u-lg-5-8,.pure-u-lg-15-24{width:62.5%;*width:62.469%}.pure-u-lg-2-3,.pure-u-lg-16-24{width:66.6667%;*width:66.6357%}.pure-u-lg-17-24{width:70.8333%;*width:70.8023%}.pure-u-lg-3-4,.pure-u-lg-18-24{width:75%;*width:74.969%}.pure-u-lg-19-24{width:79.1667%;*width:79.1357%}.pure-u-lg-4-5{width:80%;*width:79.969%}.pure-u-lg-5-6,.pure-u-lg-20-24{width:83.3333%;*width:83.3023%}.pure-u-lg-7-8,.pure-u-lg-21-24{width:87.5%;*width:87.469%}.pure-u-lg-11-12,.pure-u-lg-22-24{width:91.6667%;*width:91.6357%}.pure-u-lg-23-24{width:95.8333%;*width:95.8023%}.pure-u-lg-1,.pure-u-lg-1-1,.pure-u-lg-5-5,.pure-u-lg-24-24{width:100%}}@media screen and (min-width:80em){.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-1-2,.pure-u-xl-1-3,.pure-u-xl-2-3,.pure-u-xl-1-4,.pure-u-xl-3-4,.pure-u-xl-1-5,.pure-u-xl-2-5,.pure-u-xl-3-5,.pure-u-xl-4-5,.pure-u-xl-5-5,.pure-u-xl-1-6,.pure-u-xl-5-6,.pure-u-xl-1-8,.pure-u-xl-3-8,.pure-u-xl-5-8,.pure-u-xl-7-8,.pure-u-xl-1-12,.pure-u-xl-5-12,.pure-u-xl-7-12,.pure-u-xl-11-12,.pure-u-xl-1-24,.pure-u-xl-2-24,.pure-u-xl-3-24,.pure-u-xl-4-24,.pure-u-xl-5-24,.pure-u-xl-6-24,.pure-u-xl-7-24,.pure-u-xl-8-24,.pure-u-xl-9-24,.pure-u-xl-10-24,.pure-u-xl-11-24,.pure-u-xl-12-24,.pure-u-xl-13-24,.pure-u-xl-14-24,.pure-u-xl-15-24,.pure-u-xl-16-24,.pure-u-xl-17-24,.pure-u-xl-18-24,.pure-u-xl-19-24,.pure-u-xl-20-24,.pure-u-xl-21-24,.pure-u-xl-22-24,.pure-u-xl-23-24,.pure-u-xl-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-xl-1-24{width:4.1667%;*width:4.1357%}.pure-u-xl-1-12,.pure-u-xl-2-24{width:8.3333%;*width:8.3023%}.pure-u-xl-1-8,.pure-u-xl-3-24{width:12.5%;*width:12.469%}.pure-u-xl-1-6,.pure-u-xl-4-24{width:16.6667%;*width:16.6357%}.pure-u-xl-1-5{width:20%;*width:19.969%}.pure-u-xl-5-24{width:20.8333%;*width:20.8023%}.pure-u-xl-1-4,.pure-u-xl-6-24{width:25%;*width:24.969%}.pure-u-xl-7-24{width:29.1667%;*width:29.1357%}.pure-u-xl-1-3,.pure-u-xl-8-24{width:33.3333%;*width:33.3023%}.pure-u-xl-3-8,.pure-u-xl-9-24{width:37.5%;*width:37.469%}.pure-u-xl-2-5{width:40%;*width:39.969%}.pure-u-xl-5-12,.pure-u-xl-10-24{width:41.6667%;*width:41.6357%}.pure-u-xl-11-24{width:45.8333%;*width:45.8023%}.pure-u-xl-1-2,.pure-u-xl-12-24{width:50%;*width:49.969%}.pure-u-xl-13-24{width:54.1667%;*width:54.1357%}.pure-u-xl-7-12,.pure-u-xl-14-24{width:58.3333%;*width:58.3023%}.pure-u-xl-3-5{width:60%;*width:59.969%}.pure-u-xl-5-8,.pure-u-xl-15-24{width:62.5%;*width:62.469%}.pure-u-xl-2-3,.pure-u-xl-16-24{width:66.6667%;*width:66.6357%}.pure-u-xl-17-24{width:70.8333%;*width:70.8023%}.pure-u-xl-3-4,.pure-u-xl-18-24{width:75%;*width:74.969%}.pure-u-xl-19-24{width:79.1667%;*width:79.1357%}.pure-u-xl-4-5{width:80%;*width:79.969%}.pure-u-xl-5-6,.pure-u-xl-20-24{width:83.3333%;*width:83.3023%}.pure-u-xl-7-8,.pure-u-xl-21-24{width:87.5%;*width:87.469%}.pure-u-xl-11-12,.pure-u-xl-22-24{width:91.6667%;*width:91.6357%}.pure-u-xl-23-24{width:95.8333%;*width:95.8023%}.pure-u-xl-1,.pure-u-xl-1-1,.pure-u-xl-5-5,.pure-u-xl-24-24{width:100%}} -------------------------------------------------------------------------------- /css/simplemde.min.css: -------------------------------------------------------------------------------- 1 | /** 2 | * simplemde v1.8.1 3 | * Copyright Next Step Webs, Inc. 4 | * @link https://github.com/NextStepWebs/simplemde-markdown-editor 5 | * @license MIT 6 | */ 7 | .CodeMirror{color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror,.CodeMirror-scroll{min-height:300px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected,.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0}.CodeMirror{height:auto;border:1px solid #ddd;border-bottom-left-radius:4px;border-bottom-right-radius:4px;padding:10px;font:inherit;z-index:1}.CodeMirror-fullscreen{background:#fff;position:fixed!important;top:50px;left:0;right:0;bottom:0;height:auto;z-index:9}.CodeMirror-sided{width:50%!important}.editor-toolbar{position:relative;opacity:.6;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;padding:0 10px;border-top:1px solid #bbb;border-left:1px solid #bbb;border-right:1px solid #bbb;border-top-left-radius:4px;border-top-right-radius:4px}.editor-toolbar:after,.editor-toolbar:before{display:block;content:' ';height:1px}.editor-toolbar:before{margin-bottom:8px}.editor-toolbar:after{margin-top:8px}.editor-toolbar:hover,.editor-wrapper input.title:focus,.editor-wrapper input.title:hover{opacity:.8}.editor-toolbar.fullscreen{width:100%;height:50px;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-top:10px;padding-bottom:10px;box-sizing:border-box;background:#fff;border:0;position:fixed;top:0;left:0;opacity:1;z-index:9}.editor-toolbar.fullscreen::before{width:20px;height:50px;background:-moz-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,1)),color-stop(100%,rgba(255,255,255,0)));background:-webkit-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-o-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:linear-gradient(to right,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);position:fixed;top:0;left:0;margin:0;padding:0}.editor-toolbar.fullscreen::after{width:20px;height:50px;background:-moz-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,0)),color-stop(100%,rgba(255,255,255,1)));background:-webkit-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-o-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-ms-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:linear-gradient(to right,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);position:fixed;top:0;right:0;margin:0;padding:0}.editor-toolbar a{display:inline-block;text-align:center;text-decoration:none!important;color:#2c3e50!important;width:30px;height:30px;margin:0;border:1px solid transparent;border-radius:3px;cursor:pointer}.editor-toolbar a.active,.editor-toolbar a:hover{background:#fcfcfc;border-color:#95a5a6}.editor-toolbar a:before{line-height:30px}.editor-toolbar i.separator{display:inline-block;width:0;border-left:1px solid #d9d9d9;border-right:1px solid #fff;color:transparent;text-indent:-10px;margin:0 6px}.editor-toolbar a.fa-header-x:after{font-family:Arial,"Helvetica Neue",Helvetica,sans-serif;font-size:65%;vertical-align:text-bottom;position:relative;top:2px}.editor-toolbar a.fa-header-1:after{content:"1"}.editor-toolbar a.fa-header-2:after{content:"2"}.editor-toolbar a.fa-header-3:after{content:"3"}.editor-toolbar a.fa-header-bigger:after{content:"▲"}.editor-toolbar a.fa-header-smaller:after{content:"▼"}.editor-toolbar.disabled-for-preview a:not(.no-disable){pointer-events:none;background:#fff;border-color:transparent;text-shadow:inherit}@media only screen and (max-width:700px){.editor-toolbar a.no-mobile{display:none}}.editor-statusbar{padding:8px 10px;font-size:12px;color:#959694;text-align:right}.editor-statusbar span{display:inline-block;min-width:4em;margin-left:1em}.editor-preview,.editor-preview-side{padding:10px;background:#fafafa;overflow:auto;display:none;box-sizing:border-box}.editor-statusbar .lines:before{content:'lines: '}.editor-statusbar .words:before{content:'words: '}.editor-preview{position:absolute;width:100%;height:100%;top:0;left:0;z-index:2}.editor-preview-side{position:fixed;bottom:0;width:50%;top:50px;right:0;z-index:9999;border:1px solid #ddd}.editor-preview-active,.editor-preview-active-side{display:block}.editor-preview-side>p,.editor-preview>p{margin-top:0}.editor-preview pre,.editor-preview-side pre{background:#eee;margin-bottom:10px}.editor-preview table td,.editor-preview table th,.editor-preview-side table td,.editor-preview-side table th{border:1px solid #ddd;padding:5px}.CodeMirror .CodeMirror-code .cm-tag{color:#63a35c}.CodeMirror .CodeMirror-code .cm-attribute{color:#795da3}.CodeMirror .CodeMirror-code .cm-string{color:#183691}.CodeMirror .CodeMirror-selected{background:#d9d9d9}.CodeMirror .CodeMirror-code .cm-header-1{font-size:200%;line-height:200%}.CodeMirror .CodeMirror-code .cm-header-2{font-size:160%;line-height:160%}.CodeMirror .CodeMirror-code .cm-header-3{font-size:125%;line-height:125%}.CodeMirror .CodeMirror-code .cm-header-4{font-size:110%;line-height:110%}.CodeMirror .CodeMirror-code .cm-comment{background:rgba(0,0,0,.05);border-radius:2px}.CodeMirror .CodeMirror-code .cm-link{color:#7f8c8d}.CodeMirror .CodeMirror-code .cm-url{color:#aab2b3}.CodeMirror .CodeMirror-code .cm-strikethrough{text-decoration:line-through}.CodeMirror .cm-spell-error:not(.cm-url):not(.cm-comment):not(.cm-tag):not(.cm-word){background:rgba(255,0,0,.15)} -------------------------------------------------------------------------------- /css/pure-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.6.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yahoo/pure/blob/master/LICENSE.md 6 | */ 7 | /*! 8 | normalize.css v^3.0 | MIT License | git.io/normalize 9 | Copyright (c) Nicolas Gallagher and Jonathan Neal 10 | */ 11 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap;-ms-align-content:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *="pure-u"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000\9}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked input[type=file],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-list,.pure-menu-item{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-link,.pure-menu-heading{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-separator{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-allow-hover:hover>.pure-menu-children,.pure-menu-active>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;padding:.5em 0}.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar{display:none}.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-link,.pure-menu-disabled,.pure-menu-heading{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent}.pure-menu-active>.pure-menu-link,.pure-menu-link:hover,.pure-menu-link:focus{background-color:#eee}.pure-menu-selected .pure-menu-link,.pure-menu-selected .pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0} -------------------------------------------------------------------------------- /css/blog.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS Document */ 3 | 4 | @font-face { 5 | font-family: 'Roboto'; 6 | font-style: normal; 7 | font-weight: 300; 8 | src: url('fonts/roboto-light.eot') format('embedded-opentype'),url('fonts/roboto-light.woff') format('woff'), url('fonts/roboto-light.ttf') format('truetype'); 9 | } 10 | @font-face { 11 | font-family: 'Roboto'; 12 | font-style: normal; 13 | font-weight: 400; 14 | src: url('fonts/roboto-regular.eot') format('embedded-opentype'),url('fonts/roboto-regular.woff') format('woff'), url('fonts/roboto-regular.ttf') format('truetype'); 15 | } 16 | 17 | html { 18 | font-family: 'Roboto', sans-serif; 19 | } 20 | 21 | * { 22 | -webkit-box-sizing: border-box; 23 | -moz-box-sizing: border-box; 24 | box-sizing: border-box; 25 | } 26 | 27 | a { 28 | text-decoration: none; 29 | color: #3D92C9; 30 | } 31 | a:hover, 32 | a:focus { 33 | text-decoration: underline; 34 | } 35 | 36 | h3 { 37 | font-weight: 100; 38 | } 39 | 40 | .separator { 41 | position: relative; 42 | margin: 35px 0; 43 | height: 1px; 44 | background: #ccc; 45 | background: -webkit-gradient(linear, 0 0, 100% 0, from(#fff), to(#fff), color-stop(50%, #ccc)); 46 | } 47 | 48 | .link { 49 | color: inherit; 50 | } 51 | 52 | /* NOTIFICATIONS */ 53 | .note { 54 | position: fixed; 55 | z-index: 101; 56 | top: 0; 57 | left: 0; 58 | right: 0; 59 | background: #eee; 60 | color: #fff; 61 | text-align: center; 62 | font-size: 1.5em; 63 | font-weight: 200; 64 | line-height: 2em; 65 | overflow-y: hidden; 66 | -webkit-box-shadow: 0 0 5px black; 67 | -moz-box-shadow: 0 0 5px black; 68 | box-shadow: 0 0 5px black; 69 | transition: opacity 2s linear; 70 | } 71 | 72 | /* LAYOUT CSS */ 73 | .pure-img-responsive { 74 | max-width: 100%; 75 | height: auto; 76 | } 77 | 78 | #layout { 79 | padding: 0; 80 | display: flex; 81 | justify-content: center; 82 | } 83 | 84 | .sidebar { 85 | background: #333; 86 | color: #fff; 87 | } 88 | 89 | .plume-logo { 90 | height: 1em; 91 | } 92 | 93 | .blog-info { 94 | margin-top: 2em; 95 | } 96 | 97 | .blog-title, 98 | .blog-tagline, 99 | .blog-picture { 100 | margin: 0; 101 | } 102 | /*.blog-title { 103 | color: #333; 104 | font-weight: 300; 105 | padding: 0.2em; 106 | } 107 | 108 | .blog-tagline { 109 | font-weight: 300; 110 | color: #777; 111 | }*/ 112 | .blog-picture { 113 | height: 100px; 114 | width: auto; 115 | } 116 | 117 | /* LOADING */ 118 | .loading { 119 | position: relative; 120 | padding: 50px; 121 | } 122 | .loading>p { 123 | position: relative; 124 | top: 50px; 125 | color: #777; 126 | } 127 | .loadingbox { 128 | width: 50px; 129 | height: 50px; 130 | margin: auto; 131 | position: absolute; 132 | left: 0; 133 | right: 0; 134 | top: 0; 135 | bottom: 0; 136 | } 137 | .loadingbox:before { 138 | content: ''; 139 | width: 50px; 140 | height: 5px; 141 | background: #000; 142 | opacity: 0.1; 143 | position: absolute; 144 | top: 59px; 145 | left: 0; 146 | border-radius: 50%; 147 | animation: shadow .5s linear infinite; 148 | } 149 | .loadingbox:after { 150 | content: ''; 151 | width: 50px; 152 | height: 50px; 153 | background: #B0CADB; 154 | animation: animate .5s linear infinite; 155 | position: absolute; 156 | top: 0; 157 | left: 0; 158 | border-radius: 3px; 159 | } 160 | @keyframes animate { 161 | 17% { 162 | border-bottom-right-radius: 3px; 163 | } 164 | 25% { 165 | transform: translateY(9px) rotate(22.5deg); 166 | } 167 | 50% { 168 | transform: translateY(18px) scale(1, 0.9) rotate(45deg); 169 | border-bottom-right-radius: 40px; 170 | } 171 | 75% { 172 | transform: translateY(9px) rotate(67.5deg); 173 | } 174 | 100% { 175 | transform: translateY(0) rotate(90deg); 176 | } 177 | } 178 | @keyframes shadow { 179 | 0%, 180 | 100% { 181 | transform: scale(1, 1); 182 | } 183 | 50% { 184 | transform: scale(1.2, 1); 185 | } 186 | } 187 | 188 | /* EDITOR */ 189 | .CodeMirror, .CodeMirror-scroll { 190 | min-height: 200px; 191 | } 192 | .editor { 193 | padding-top: 1em; 194 | color: #444; 195 | } 196 | .editor-title { 197 | font-size: 2em; 198 | min-width: 100%; 199 | max-width: 100%; 200 | padding: 0.5em 0; 201 | border-radius: 3px; 202 | outline: none; 203 | border: 0; 204 | border-bottom: 1px dotted #ccc; 205 | } 206 | .editor-title:focus { 207 | background: #ffc; 208 | padding-left: 10px; 209 | } 210 | .editor-meta { 211 | padding-top: 5px; 212 | } 213 | .editor-tags a { 214 | margin-left: 5px; 215 | color: #ccc; 216 | cursor: pointer; 217 | } 218 | .editor-add-tag { 219 | width: 70px; 220 | border: 0; 221 | border-bottom: 1px dotted #777; 222 | } 223 | span.editor-title:empty::before { 224 | content: 'Title'; 225 | color: #ccc; 226 | } 227 | span.editor-title:empty:focus::before { 228 | content: 'Title'; 229 | color: #777; 230 | } 231 | a.editor-author, a.editor-author:visited { 232 | color: #3D92C9; 233 | } 234 | .editor header { 235 | margin-bottom: 10px; 236 | } 237 | .editor footer { 238 | margin-top: 10px; 239 | } 240 | 241 | .editor-body { 242 | margin-bottom: 1em; 243 | border-radius: 3px; 244 | outline: none; 245 | border: 1px solid #E6E6E6; 246 | font-size: 1em; 247 | min-height: 100px; 248 | color: #777; 249 | } 250 | 251 | .small { 252 | font-size: 50%; 253 | } 254 | 255 | .button-xsmall { 256 | font-size: 50%; 257 | } 258 | .button { 259 | display: inline-block; 260 | padding: 20px 10px; 261 | margin-right: 5px; 262 | background: #fff; 263 | border-radius: 4px; 264 | font-weight: normal; 265 | font-size: 14px; 266 | color: #777; 267 | letter-spacing: 1px; 268 | line-height: 1px; 269 | text-transform: uppercase; 270 | border: 1px solid #777; 271 | } 272 | .success { 273 | background: #1CB841!important; 274 | color: #fff; 275 | border: 1px solid #1CB841; 276 | } 277 | .danger { 278 | background: #CA3C3C!important; 279 | color: #fff; 280 | border: 0; 281 | } 282 | .danger-text { 283 | color: #CA3C3C!important; 284 | } 285 | 286 | .clickable { 287 | cursor: pointer; 288 | } 289 | 290 | /* DROPDOWN */ 291 | .pure-menu-children { 292 | list-style: none; 293 | position: absolute!important; 294 | left: initial; 295 | top: initial; 296 | margin: 0; 297 | padding: 0; 298 | width: 70px; 299 | z-index: 3; 300 | } 301 | .pure-menu-has-children>.pure-menu-link:after { 302 | content: "\25BE"; 303 | font-size: 80%; 304 | padding-left: 0.5em; 305 | } 306 | 307 | /* COLOR PICKER */ 308 | .color-0 { background: #999!important; } 309 | .color-1 { background: #ffbf00!important; } 310 | .color-2 { background: #df2d4f!important; } 311 | .color-3 { background: #4d85d1!important; } 312 | .color-4 { background: #5aba59!important; } 313 | .color-5 { background: #8156a7!important; } 314 | 315 | /* ACTION BUTTONS */ 316 | 317 | .action-button { 318 | background-color: #fff; 319 | color: #777; 320 | letter-spacing: 0.05em; 321 | text-transform: uppercase; 322 | font-size: 60%; 323 | padding: 1em 1.5em; 324 | text-decoration: none; 325 | border: 1px solid #777; 326 | border-radius: 2px; 327 | margin-right: 5px; 328 | cursor: pointer; 329 | } 330 | .action-button:hover { 331 | text-decoration: none; 332 | } 333 | .action-button img { 334 | position: relative; 335 | height: 20px; 336 | top: 7px; 337 | } 338 | 339 | .dialog { 340 | width: 300px; 341 | position: fixed; 342 | padding: 2em; 343 | text-align: center; 344 | font-weight: 200; 345 | background: #fff; 346 | z-index: 10; 347 | top: 50%; 348 | left: 50%; 349 | border: 1px solid #ccc; 350 | box-shadow: 0 0 4px #eee; 351 | border-radius: 5px; 352 | -webkit-transform: translateX(-50%) translateY(-50%); 353 | -moz-transform: translateX(-50%) translateY(-50%); 354 | -ms-transform: translateX(-50%) translateY(-50%); 355 | transform: translateX(-50%) translateY(-50%); 356 | } 357 | .dialog p { 358 | width: 100%; 359 | } 360 | .dialog footer { 361 | position: relative; 362 | margin-top: 30px; 363 | } 364 | 365 | .post-edit { 366 | background: #129FEA; 367 | height: 25px; 368 | width: 25px; 369 | -webkit-mask: url(../img/logo.svg) no-repeat 50% 50%; 370 | mask: url(../img/logo.svg) no-repeat 50% 50%; 371 | } 372 | .post-title { 373 | font-size: 1.7em!important; 374 | font-weight: bold; 375 | color: #333; 376 | margin-top: 1.5em; 377 | } 378 | 379 | .post-title>a,.post-title>a:hover,.post-title>a:visited { 380 | color: #333; 381 | text-decoration: none; 382 | } 383 | .post-title>a:hover { 384 | box-shadow: inset 0 0px 0 white, inset 0 -1px 0 #333; 385 | } 386 | .post-author { 387 | /*font-size: 1.2em;*/ 388 | } 389 | .post-author:hover, .post-author:visited { 390 | color: rgb(61, 146, 201); 391 | } 392 | .post-avatar { 393 | border-radius: 50px; 394 | float: left; 395 | height: 40px; 396 | width: 40px; 397 | margin-right: 1em; 398 | } 399 | .post-date { 400 | font-weight: 200; 401 | } 402 | .post-body { 403 | color: #444; 404 | line-height: 1.6em; 405 | font-weight: 200; 406 | } 407 | .post-body>a,.post-body>a:hover,.post-body>a:visited { 408 | color: #3D92C9; 409 | text-decoration: none; 410 | } 411 | .post-body img { 412 | max-width: 100%; 413 | max-height: 100%; 414 | } 415 | .post-meta { 416 | color: #999; 417 | font-size: 0.8em; 418 | line-height: 1.3em; 419 | margin: 0; 420 | } 421 | 422 | .post-category { 423 | margin: 0 0.1em; 424 | padding: 0.3em 1em; 425 | color: #fff!important; 426 | background: #999; 427 | font-size: 80%; 428 | cursor: pointer; 429 | } 430 | 431 | .post-images { 432 | margin: 1em 0; 433 | } 434 | .post-image-meta { 435 | margin-top: -3.5em; 436 | margin-left: 1em; 437 | color: #fff; 438 | text-shadow: 0 1px 1px #333; 439 | } 440 | 441 | .fade-out { 442 | background-color: rgba(238,212,119,0.25); 443 | transition: background-color 1.5s linear; 444 | -moz-transition: background-color 1.5s linear; 445 | -webkit-transition: background-color 1.5s linear; 446 | -ms-transition: background-color 1.5s linear; 447 | } 448 | 449 | .fade-bottom { 450 | position: relative; 451 | bottom: 4em; 452 | height: 4em; 453 | margin-bottom: -2em; 454 | padding-top: 4em; 455 | color: #777; 456 | background: -webkit-linear-gradient( 457 | rgba(255, 255, 255, 0) 0%, 458 | rgba(255, 255, 255, 1) 100% 459 | ); 460 | background-image: -moz-linear-gradient( 461 | rgba(255, 255, 255, 0) 0%, 462 | rgba(255, 255, 255, 1) 100% 463 | ); 464 | background-image: -o-linear-gradient( 465 | rgba(255, 255, 255, 0) 0%, 466 | rgba(255, 255, 255, 1) 100% 467 | ); 468 | background-image: linear-gradient( 469 | rgba(255, 255, 255, 0) 0%, 470 | rgba(255, 255, 255, 1) 100% 471 | ); 472 | background-image: -ms-linear-gradient( 473 | rgba(255, 255, 255, 0) 0%, 474 | rgba(255, 255, 255, 1) 100% 475 | ); 476 | } 477 | 478 | .less { 479 | overflow: hidden; 480 | text-overflow: ellipsis; 481 | height: 300px!important; 482 | } 483 | 484 | pre { 485 | background: #F9F9F9; 486 | font-size: 1rem; 487 | padding: 0.5rem; 488 | } 489 | 490 | .footer { 491 | text-align: center; 492 | padding: 1em 0; 493 | } 494 | .footer ul { 495 | -webkit-padding-start: 0px; 496 | } 497 | .footer a { 498 | color: #777; 499 | font-size: 80%; 500 | } 501 | .footer .pure-menu a:hover, 502 | .footer .pure-menu a:focus { 503 | background: none; 504 | } 505 | 506 | .dark { 507 | color: #333!important; 508 | } 509 | .grey { 510 | color: #999; 511 | } 512 | 513 | .hidden { 514 | display: none; 515 | } 516 | 517 | .inline-block { 518 | display: inline-block; 519 | } 520 | 521 | .fixed-nav { 522 | margin: 0; 523 | position: fixed; 524 | top: 0; 525 | left: 0; 526 | width: 100%; 527 | -webkit-transform: translateY(0); 528 | -ms-transform: translateY(0); 529 | transform: translateY(0); 530 | } 531 | 532 | .spacer { 533 | height: 1em; 534 | } 535 | 536 | .float-right { 537 | float: right; 538 | } 539 | 540 | .float-left { 541 | float: left; 542 | } 543 | 544 | .center-text { 545 | text-align: center; 546 | } 547 | 548 | .center { 549 | position: relative; 550 | top: 50%; 551 | transform: translateY(-50%); 552 | } 553 | 554 | .underline:hover { 555 | text-decoration: underline; 556 | } 557 | 558 | .no-decoration, .no-decoration:hover, .no-decoration:visited { 559 | text-decoration: none; 560 | } 561 | 562 | .pure-img-responsive { 563 | max-width: 100%; 564 | height: auto; 565 | } 566 | 567 | .overlay { 568 | visibility: hidden; 569 | position: absolute; 570 | left: 0px; 571 | top: 0px; 572 | width:100%; 573 | height:100%; 574 | font-weight: 200; 575 | background: rgba(0, 0, 0, 0.6); 576 | z-index: 1000; 577 | } 578 | 579 | .overlay-text { 580 | min-width:300px; 581 | margin: 10% 5% auto; 582 | background-color: #fff; 583 | border:1px solid #ccc; 584 | padding:15px 15px 40px 15px; 585 | } 586 | 587 | .content { 588 | margin: 0 auto; 589 | padding: 0 1em; 590 | line-height: 1.6em; 591 | position: relative; 592 | top: 0; 593 | right: 0; 594 | -moz-transition: all 300ms; 595 | -o-transition: all 300ms; 596 | -webkit-transition: all 300ms; 597 | transition: all 300ms; 598 | } 599 | .content h1 { 600 | line-height: 1em; 601 | font-size: 1.3em; 602 | } 603 | 604 | .content h2 { 605 | line-height: 1em; 606 | font-size: 1.1em; 607 | } 608 | 609 | .header { 610 | margin: 0; 611 | color: #333; 612 | text-align: center; 613 | padding: 2em 2em 0 2em; 614 | top: auto; 615 | } 616 | .header h1 { 617 | margin: 0.2em 0; 618 | font-size: 2.5em; 619 | font-weight: 300; 620 | line-height: 0.8em; 621 | } 622 | .header h2 { 623 | font-weight: 300; 624 | color: #999; 625 | padding: 0; 626 | margin-top: 0; 627 | } 628 | 629 | /* NEW LAYOUT FOR MENU */ 630 | nav#global-nav { 631 | background-color: #333; 632 | bottom: 0; 633 | max-width: 220px; 634 | overflow: auto; 635 | position: fixed; 636 | top: 0; 637 | left: -220px; 638 | width: 100%; 639 | z-index: 9; 640 | -moz-transition: all 300ms; 641 | -o-transition: all 300ms; 642 | -webkit-transition: all 300ms; 643 | transition: all 300ms; 644 | } 645 | body.active nav#global-nav { 646 | -moz-transform: translateX(220px); 647 | -ms-transform: translateX(220px); 648 | -webkit-transform: translateX(220px); 649 | transform: translateX(220px); 650 | } 651 | nav#global-nav ul { 652 | margin: 0; 653 | padding: 0; 654 | } 655 | nav#global-nav ul li { 656 | border-bottom: 1px solid #474747; 657 | padding: 0; 658 | margin: 0; 659 | width: 100%; 660 | } 661 | nav#global-nav ul li a { 662 | display: block; 663 | background-color: #474747; 664 | color: #fff; 665 | text-decoration: none; 666 | font-size: 1.2em; 667 | font-weight: 200; 668 | letter-spacing: 1px; 669 | border: 0; 670 | margin-right: 0; 671 | padding: 1em; 672 | } 673 | nav#global-nav ul li a:hover, nav#global-nav ul li a:focus { 674 | background-color: #474747; 675 | } 676 | nav#global-nav ul li a:active { 677 | color: #3D92C9; 678 | } 679 | nav#global-nav img { 680 | position: relative; 681 | color: #fff; 682 | height: 30px; 683 | top: 7px; 684 | } 685 | 686 | /* Menu button */ 687 | 688 | #menu-button { 689 | background-color: rgba(0, 0, 0, 0.1); 690 | border: 0; 691 | color: #333; 692 | cursor: pointer; 693 | display: block; 694 | line-height: 1; 695 | width: 4em; 696 | height: 4em; 697 | left: 0.5em; 698 | top: 0.5em; 699 | padding: 0; 700 | position: relative; 701 | text-align: center; 702 | z-index: 8; 703 | -moz-transition: all 300ms; 704 | -o-transition: all 300ms; 705 | -webkit-transition: all 300ms; 706 | transition: all 300ms; 707 | } 708 | #menu-button:hover, #menu-button:active { 709 | background: #777; 710 | 711 | } 712 | #menu-button span.menu-icon { 713 | display: block; 714 | pointer-events: none; 715 | font-size: 3em; 716 | text-shadow: 2px 2px 2px #333; 717 | } 718 | #menu-button span.menu-icon svg rect { 719 | fill: #333; 720 | } 721 | #menu-button:hover span.menu-icon svg rect { 722 | fill: #fff; 723 | } 724 | #menu-button span.menu-text { 725 | display: block; 726 | font-size: 0.8em; 727 | margin-top: 0.2em; 728 | } 729 | 730 | /* Utilities */ 731 | .visuallyhidden { 732 | border: 0; 733 | clip: rect(0 0 0 0); 734 | height: 1px; 735 | margin: -1px; 736 | overflow: hidden; 737 | padding: 0; 738 | position: absolute; 739 | width: 1px; 740 | } 741 | 742 | 743 | @media (min-width: 48em) { 744 | .header, 745 | .content { 746 | padding-left: 2em; 747 | padding-right: 2em; 748 | } 749 | 750 | .blog-picture { 751 | display: inline; 752 | } 753 | 754 | .sidebar { 755 | position: fixed; 756 | top: 0; 757 | bottom: 0; 758 | } 759 | 760 | 761 | .menu-link { 762 | position: fixed; 763 | } 764 | #layout.active .menu-link { 765 | left: 150px; 766 | } 767 | 768 | .post-body { 769 | font-size: 125%; 770 | } 771 | 772 | } 773 | 774 | @media (max-width: 48em) { 775 | .header h1 { 776 | font-size: 1.7em; 777 | } 778 | .header h2 { 779 | font-size: 1.3em; 780 | } 781 | 782 | #menu-button { 783 | width: 3em; 784 | height: 3em; 785 | } 786 | 787 | article>footer { 788 | text-align: center; 789 | } 790 | } 791 | -------------------------------------------------------------------------------- /app/solid.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | The MIT License (MIT) 4 | 5 | Copyright (c) 2015 Solid 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | 25 | Solid.js is a Javascript library for Solid applications. This library currently 26 | depends on rdflib.js. Please make sure to load the rdflib.js script before 27 | loading solid.js. 28 | 29 | If you would like to know more about the solid Solid project, please see 30 | https://github.com/solid/ 31 | 32 | */ 33 | 34 | // WebID authentication and signup 35 | var Solid = Solid || {}; 36 | Solid.auth = (function(window) { 37 | 'use strict'; 38 | 39 | // default (preferred) authentication endpoint 40 | var authEndpoint = 'https://databox.me/'; 41 | var signupEndpoint = 'https://solid.github.io/solid-idps/'; 42 | 43 | // attempt to find the current user's WebID from the User header if authenticated 44 | // resolve(webid) - string 45 | var login = function(url) { 46 | url = url || window.location.origin+window.location.pathname; 47 | var promise = new Promise(function(resolve, reject) { 48 | var http = new XMLHttpRequest(); 49 | http.open('HEAD', url); 50 | http.withCredentials = true; 51 | http.onreadystatechange = function() { 52 | if (this.readyState == this.DONE) { 53 | if (this.status === 200) { 54 | var user = this.getResponseHeader('User'); 55 | if (user && user.length > 0 && user.slice(0, 4) == 'http') { 56 | return resolve(user); 57 | } 58 | } 59 | // authenticate to a known endpoint 60 | var http = new XMLHttpRequest(); 61 | http.open('HEAD', authEndpoint); 62 | http.withCredentials = true; 63 | http.onreadystatechange = function() { 64 | if (this.readyState == this.DONE) { 65 | if (this.status === 200) { 66 | var user = this.getResponseHeader('User'); 67 | if (user && user.length > 0 && user.slice(0, 4) == 'http') { 68 | return resolve(user); 69 | } 70 | } 71 | return reject({status: this.status, xhr: this}); 72 | } 73 | }; 74 | http.send(); 75 | } 76 | }; 77 | http.send(); 78 | }); 79 | 80 | return promise; 81 | }; 82 | 83 | // Open signup window 84 | var signup = function(url) { 85 | url = url || signupEndpoint; 86 | var leftPosition, topPosition; 87 | var width = 1024; 88 | var height = 600; 89 | // set borders 90 | leftPosition = (window.screen.width / 2) - ((width / 2) + 10); 91 | // set title and status bars 92 | topPosition = (window.screen.height / 2) - ((height / 2) + 50); 93 | window.open(url+"?origin="+encodeURIComponent(window.location.origin), "Solid signup", "resizable,scrollbars,status,width="+width+",height="+height+",left="+ leftPosition + ",top=" + topPosition); 94 | 95 | var promise = new Promise(function(resolve, reject) { 96 | console.log("Starting listener"); 97 | listen().then(function(webid) { 98 | return resolve(webid); 99 | }).catch(function(err){ 100 | return reject(err); 101 | }); 102 | }); 103 | 104 | return promise; 105 | }; 106 | 107 | // Listen to login messages from child window/iframe 108 | var listen = function() { 109 | var promise = new Promise(function(resolve, reject){ 110 | console.log("In listen()"); 111 | var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent"; 112 | var eventListener = window[eventMethod]; 113 | var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message"; 114 | eventListener(messageEvent,function(e) { 115 | var u = e.data; 116 | if (u.slice(0,5) == 'User:') { 117 | var user = u.slice(5, u.length); 118 | if (user && user.length > 0 && user.slice(0,4) == 'http') { 119 | return resolve(user); 120 | } else { 121 | return reject(user); 122 | } 123 | } 124 | },true); 125 | }); 126 | 127 | return promise; 128 | }; 129 | 130 | // return public methods 131 | return { 132 | login: login, 133 | signup: signup, 134 | listen: listen, 135 | }; 136 | }(this)); 137 | // Identity / WebID 138 | var Solid = Solid || {}; 139 | Solid.identity = (function(window) { 140 | 'use strict'; 141 | 142 | // common vocabs 143 | var RDF = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#"); 144 | var OWL = $rdf.Namespace("http://www.w3.org/2002/07/owl#"); 145 | var PIM = $rdf.Namespace("http://www.w3.org/ns/pim/space#"); 146 | var FOAF = $rdf.Namespace("http://xmlns.com/foaf/0.1/"); 147 | var DCT = $rdf.Namespace("http://purl.org/dc/terms/"); 148 | 149 | // fetch user profile (follow sameAs links) and return promise with a graph 150 | // resolve(graph) 151 | var getProfile = function(url) { 152 | var promise = new Promise(function(resolve, reject) { 153 | // Load main profile 154 | Solid.web.get(url).then( 155 | function(graph) { 156 | // set WebID 157 | var webid = graph.any($rdf.sym(url), FOAF('primaryTopic')); 158 | // find additional resources to load 159 | var sameAs = graph.statementsMatching(webid, OWL('sameAs'), undefined); 160 | var seeAlso = graph.statementsMatching(webid, OWL('seeAlso'), undefined); 161 | var prefs = graph.statementsMatching(webid, PIM('preferencesFile'), undefined); 162 | var toLoad = sameAs.length + seeAlso.length + prefs.length; 163 | 164 | // sync promises externally instead of using Promise.all() which fails if one GET fails 165 | var syncAll = function() { 166 | if (toLoad === 0) { 167 | return resolve(graph); 168 | } 169 | } 170 | // Load sameAs files 171 | if (sameAs.length > 0) { 172 | sameAs.forEach(function(same){ 173 | Solid.web.get(same.object.value, same.object.value).then( 174 | function(g) { 175 | Solid.utils.appendGraph(graph, g); 176 | toLoad--; 177 | syncAll(); 178 | } 179 | ).catch( 180 | function(err){ 181 | toLoad--; 182 | syncAll(); 183 | }); 184 | }); 185 | } 186 | // Load seeAlso files 187 | if (seeAlso.length > 0) { 188 | seeAlso.forEach(function(see){ 189 | Solid.web.get(see.object.value).then( 190 | function(g) { 191 | Solid.utils.appendGraph(graph, g, see.object.value); 192 | toLoad--; 193 | syncAll(); 194 | } 195 | ).catch( 196 | function(err){ 197 | toLoad--; 198 | syncAll(); 199 | }); 200 | }); 201 | } 202 | // Load preferences files 203 | if (prefs.length > 0) { 204 | prefs.forEach(function(pref){ 205 | Solid.web.get(pref.object.value).then( 206 | function(g) { 207 | Solid.utils.appendGraph(graph, g, pref.object.value); 208 | toLoad--; 209 | syncAll(); 210 | } 211 | ).catch( 212 | function(err){ 213 | toLoad--; 214 | syncAll(); 215 | }); 216 | }); 217 | } 218 | } 219 | ) 220 | .catch( 221 | function(err) { 222 | reject(err); 223 | } 224 | ); 225 | }); 226 | 227 | return promise; 228 | }; 229 | 230 | // Find the user's workspaces 231 | // Return an object with the list of objects (workspaces) 232 | var getWorkspaces = function(webid, graph) { 233 | var promise = new Promise(function(resolve, reject){ 234 | if (!graph) { 235 | // fetch profile and call function again 236 | getProfile(webid).then(function(g) { 237 | getWorkspaces(webid, g).then(function(ws) { 238 | return resolve(ws); 239 | }).catch(function(err) { 240 | return reject(err); 241 | }); 242 | }).catch(function(err){ 243 | return reject(err); 244 | }); 245 | } else { 246 | // find workspaces 247 | var workspaces = []; 248 | var ws = graph.statementsMatching($rdf.sym(webid), PIM('workspace'), undefined); 249 | if (ws.length === 0) { 250 | return resolve(workspaces); 251 | } 252 | ws.forEach(function(w){ 253 | // try to get some additional info - i.e. desc/title 254 | var workspace = {}; 255 | var title = graph.any(w.object, DCT('title')); 256 | if (title && title.value) { 257 | workspace.title = title.value; 258 | } 259 | workspace.url = w.object.uri; 260 | workspace.statements = graph.statementsMatching(w.object, undefined, undefined); 261 | workspaces.push(workspace); 262 | }); 263 | return resolve(workspaces); 264 | } 265 | }); 266 | 267 | return promise; 268 | }; 269 | 270 | // return public methods 271 | return { 272 | getProfile: getProfile, 273 | getWorkspaces: getWorkspaces 274 | }; 275 | }(this)); 276 | // Events 277 | Solid = Solid || {}; 278 | Solid.status = (function(window) { 279 | 'use strict'; 280 | 281 | // Get current online status 282 | var isOnline = function() { 283 | return window.navigator.onLine; 284 | }; 285 | 286 | // Is offline 287 | var onOffline = function(callback) { 288 | window.addEventListener("offline", callback, false); 289 | }; 290 | // Is online 291 | var onOnline = function(callback) { 292 | window.addEventListener("online", callback, false); 293 | }; 294 | 295 | // return public methods 296 | return { 297 | isOnline: isOnline, 298 | onOffline: onOffline, 299 | onOnline: onOnline, 300 | }; 301 | }(this)); 302 | // Helper functions 303 | var Solid = Solid || {}; 304 | Solid.utils = (function(window) { 305 | 'use strict'; 306 | 307 | // parse a Link header 308 | var parseLinkHeader = function(link) { 309 | var linkexp = /<[^>]*>\s*(\s*;\s*[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|$)/g; 310 | var paramexp = /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g; 311 | 312 | var matches = link.match(linkexp); 313 | var rels = {}; 314 | for (var i = 0; i < matches.length; i++) { 315 | var split = matches[i].split('>'); 316 | var href = split[0].substring(1); 317 | var ps = split[1]; 318 | var s = ps.match(paramexp); 319 | for (var j = 0; j < s.length; j++) { 320 | var p = s[j]; 321 | var paramsplit = p.split('='); 322 | var name = paramsplit[0]; 323 | var rel = paramsplit[1].replace(/["']/g, ''); 324 | rels[rel] = href; 325 | } 326 | } 327 | return rels; 328 | }; 329 | 330 | // append statements from one graph object to another 331 | var appendGraph = function(toGraph, fromGraph, docURI) { 332 | var why = (docURI)?$rdf.sym(docURI):undefined; 333 | fromGraph.statementsMatching(undefined, undefined, undefined, why).forEach(function(st) { 334 | toGraph.add(st.subject, st.predicate, st.object, st.why); 335 | }); 336 | }; 337 | 338 | return { 339 | parseLinkHeader: parseLinkHeader, 340 | appendGraph: appendGraph, 341 | }; 342 | }(this)); 343 | // LDP operations 344 | var Solid = Solid || {}; 345 | Solid.web = (function(window) { 346 | 'use strict'; 347 | 348 | // Init some defaults; 349 | var PROXY = "https://databox.me/,proxy?uri={uri}"; 350 | var TIMEOUT = 5000; 351 | 352 | $rdf.Fetcher.crossSiteProxyTemplate = PROXY; 353 | // common vocabs 354 | var LDP = $rdf.Namespace("http://www.w3.org/ns/ldp#"); 355 | 356 | // return metadata for a given request 357 | var parseResponseMeta = function(resp) { 358 | var h = Solid.utils.parseLinkHeader(resp.getResponseHeader('Link')); 359 | var meta = {}; 360 | meta.url = (resp.getResponseHeader('Location'))?resp.getResponseHeader('Location'):resp.responseURL; 361 | meta.acl = h['acl']; 362 | meta.meta = (h['meta'])?h['meta']:h['describedBy']; 363 | meta.user = (resp.getResponseHeader('User'))?resp.getResponseHeader('User'):''; 364 | meta.websocket = (resp.getResponseHeader('Updates-Via'))?resp.getResponseHeader('Updates-Via'):''; 365 | meta.exists = false; 366 | meta.exists = (resp.status === 200)?true:false; 367 | meta.xhr = resp; 368 | return meta; 369 | }; 370 | 371 | // check if a resource exists and return useful Solid info (acl, meta, type, etc) 372 | // resolve(metaObj) 373 | var head = function(url) { 374 | var promise = new Promise(function(resolve) { 375 | var http = new XMLHttpRequest(); 376 | http.open('HEAD', url); 377 | http.onreadystatechange = function() { 378 | if (this.readyState == this.DONE) { 379 | resolve(parseResponseMeta(this)); 380 | } 381 | }; 382 | http.send(); 383 | }); 384 | 385 | return promise; 386 | }; 387 | 388 | // fetch an RDF resource 389 | // resolve(graph) | reject(this) 390 | var get = function(url) { 391 | var promise = new Promise(function(resolve, reject) { 392 | var g = new $rdf.graph(); 393 | var f = new $rdf.fetcher(g, TIMEOUT); 394 | 395 | var docURI = (url.indexOf('#') >= 0)?url.slice(0, url.indexOf('#')):url; 396 | f.nowOrWhenFetched(docURI,undefined,function(ok, body, xhr) { 397 | if (!ok) { 398 | reject({status: xhr.status, xhr: xhr}); 399 | } else { 400 | resolve(g); 401 | } 402 | }); 403 | }); 404 | 405 | return promise; 406 | }; 407 | 408 | // create new resource 409 | // resolve(metaObj) | reject 410 | var post = function(url, slug, data, isContainer) { 411 | var resType = (isContainer)?LDP('BasicContainer').uri:LDP('Resource').uri; 412 | var promise = new Promise(function(resolve, reject) { 413 | var http = new XMLHttpRequest(); 414 | http.open('POST', url); 415 | http.setRequestHeader('Content-Type', 'text/turtle'); 416 | http.setRequestHeader('Link', '<'+resType+'>; rel="type"'); 417 | if (slug && slug.length > 0) { 418 | http.setRequestHeader('Slug', slug); 419 | } 420 | http.withCredentials = true; 421 | http.onreadystatechange = function() { 422 | if (this.readyState == this.DONE) { 423 | if (this.status === 200 || this.status === 201) { 424 | resolve(parseResponseMeta(this)); 425 | } else { 426 | reject({status: this.status, xhr: this}); 427 | } 428 | } 429 | }; 430 | if (data && data.length > 0) { 431 | http.send(data); 432 | } else { 433 | http.send(); 434 | } 435 | }); 436 | 437 | return promise; 438 | }; 439 | 440 | // update/create resource using HTTP PUT 441 | // resolve(metaObj) | reject 442 | var put = function(url, data) { 443 | var promise = new Promise(function(resolve, reject) { 444 | var http = new XMLHttpRequest(); 445 | http.open('PUT', url); 446 | http.setRequestHeader('Content-Type', 'text/turtle'); 447 | http.withCredentials = true; 448 | http.onreadystatechange = function() { 449 | if (this.readyState == this.DONE) { 450 | if (this.status === 200 || this.status === 201) { 451 | return resolve(parseResponseMeta(this)); 452 | } else { 453 | reject({status: this.status, xhr: this}); 454 | } 455 | } 456 | }; 457 | if (data) { 458 | http.send(data); 459 | } else { 460 | http.send(); 461 | } 462 | }); 463 | 464 | return promise; 465 | }; 466 | 467 | // delete a resource 468 | // resolve(true) | reject 469 | var del = function(url) { 470 | var promise = new Promise(function(resolve, reject) { 471 | var http = new XMLHttpRequest(); 472 | http.open('DELETE', url); 473 | http.withCredentials = true; 474 | http.onreadystatechange = function() { 475 | if (this.readyState == this.DONE) { 476 | if (this.status === 200) { 477 | return resolve(true); 478 | } else { 479 | reject({status: this.status, xhr: this}); 480 | } 481 | } 482 | }; 483 | http.send(); 484 | }); 485 | 486 | return promise; 487 | } 488 | 489 | // return public methods 490 | return { 491 | head: head, 492 | get: get, 493 | post: post, 494 | put: put, 495 | del: del, 496 | }; 497 | }(this)); 498 | -------------------------------------------------------------------------------- /css/font-awesome.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | @font-face{font-family:'FontAwesome';src:url('fonts/fontawesome-webfont.eot');src:url('fonts/fontawesome-webfont.eot') format('embedded-opentype'),url('fonts/fontawesome-webfont.woff') format('woff'),url('fonts/fontawesome-webfont.ttf') format('truetype'),url('fonts/fontawesome-webfont.svg#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"} 6 | -------------------------------------------------------------------------------- /js/moment.min.js: -------------------------------------------------------------------------------- 1 | //! moment.js 2 | //! version : 2.10.6 3 | //! authors : Tim Wood, Iskren Chernev, Moment.js contributors 4 | //! license : MIT 5 | //! momentjs.com 6 | !function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):a.moment=b()}(this,function(){"use strict";function a(){return Hc.apply(null,arguments)}function b(a){Hc=a}function c(a){return"[object Array]"===Object.prototype.toString.call(a)}function d(a){return a instanceof Date||"[object Date]"===Object.prototype.toString.call(a)}function e(a,b){var c,d=[];for(c=0;c0)for(c in Jc)d=Jc[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function n(b){m(this,b),this._d=new Date(null!=b._d?b._d.getTime():NaN),Kc===!1&&(Kc=!0,a.updateOffset(this),Kc=!1)}function o(a){return a instanceof n||null!=a&&null!=a._isAMomentObject}function p(a){return 0>a?Math.ceil(a):Math.floor(a)}function q(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=p(b)),c}function r(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&q(a[d])!==q(b[d]))&&g++;return g+f}function s(){}function t(a){return a?a.toLowerCase().replace("_","-"):a}function u(a){for(var b,c,d,e,f=0;f0;){if(d=v(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&r(e,c,!0)>=b-1)break;b--}f++}return null}function v(a){var b=null;if(!Lc[a]&&"undefined"!=typeof module&&module&&module.exports)try{b=Ic._abbr,require("./locale/"+a),w(b)}catch(c){}return Lc[a]}function w(a,b){var c;return a&&(c="undefined"==typeof b?y(a):x(a,b),c&&(Ic=c)),Ic._abbr}function x(a,b){return null!==b?(b.abbr=a,Lc[a]=Lc[a]||new s,Lc[a].set(b),w(a),Lc[a]):(delete Lc[a],null)}function y(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return Ic;if(!c(a)){if(b=v(a))return b;a=[a]}return u(a)}function z(a,b){var c=a.toLowerCase();Mc[c]=Mc[c+"s"]=Mc[b]=a}function A(a){return"string"==typeof a?Mc[a]||Mc[a.toLowerCase()]:void 0}function B(a){var b,c,d={};for(c in a)f(a,c)&&(b=A(c),b&&(d[b]=a[c]));return d}function C(b,c){return function(d){return null!=d?(E(this,b,d),a.updateOffset(this,c),this):D(this,b)}}function D(a,b){return a._d["get"+(a._isUTC?"UTC":"")+b]()}function E(a,b,c){return a._d["set"+(a._isUTC?"UTC":"")+b](c)}function F(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else if(a=A(a),"function"==typeof this[a])return this[a](b);return this}function G(a,b,c){var d=""+Math.abs(a),e=b-d.length,f=a>=0;return(f?c?"+":"":"-")+Math.pow(10,Math.max(0,e)).toString().substr(1)+d}function H(a,b,c,d){var e=d;"string"==typeof d&&(e=function(){return this[d]()}),a&&(Qc[a]=e),b&&(Qc[b[0]]=function(){return G(e.apply(this,arguments),b[1],b[2])}),c&&(Qc[c]=function(){return this.localeData().ordinal(e.apply(this,arguments),a)})}function I(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function J(a){var b,c,d=a.match(Nc);for(b=0,c=d.length;c>b;b++)Qc[d[b]]?d[b]=Qc[d[b]]:d[b]=I(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function K(a,b){return a.isValid()?(b=L(b,a.localeData()),Pc[b]=Pc[b]||J(b),Pc[b](a)):a.localeData().invalidDate()}function L(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Oc.lastIndex=0;d>=0&&Oc.test(a);)a=a.replace(Oc,c),Oc.lastIndex=0,d-=1;return a}function M(a){return"function"==typeof a&&"[object Function]"===Object.prototype.toString.call(a)}function N(a,b,c){dd[a]=M(b)?b:function(a){return a&&c?c:b}}function O(a,b){return f(dd,a)?dd[a](b._strict,b._locale):new RegExp(P(a))}function P(a){return a.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e}).replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function Q(a,b){var c,d=b;for("string"==typeof a&&(a=[a]),"number"==typeof b&&(d=function(a,c){c[b]=q(a)}),c=0;cd;d++){if(e=h([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}}function X(a,b){var c;return"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),T(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a)}function Y(b){return null!=b?(X(this,b),a.updateOffset(this,!0),this):D(this,"Month")}function Z(){return T(this.year(),this.month())}function $(a){var b,c=a._a;return c&&-2===j(a).overflow&&(b=c[gd]<0||c[gd]>11?gd:c[hd]<1||c[hd]>T(c[fd],c[gd])?hd:c[id]<0||c[id]>24||24===c[id]&&(0!==c[jd]||0!==c[kd]||0!==c[ld])?id:c[jd]<0||c[jd]>59?jd:c[kd]<0||c[kd]>59?kd:c[ld]<0||c[ld]>999?ld:-1,j(a)._overflowDayOfYear&&(fd>b||b>hd)&&(b=hd),j(a).overflow=b),a}function _(b){a.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+b)}function aa(a,b){var c=!0;return g(function(){return c&&(_(a+"\n"+(new Error).stack),c=!1),b.apply(this,arguments)},b)}function ba(a,b){od[a]||(_(b),od[a]=!0)}function ca(a){var b,c,d=a._i,e=pd.exec(d);if(e){for(j(a).iso=!0,b=0,c=qd.length;c>b;b++)if(qd[b][1].exec(d)){a._f=qd[b][0];break}for(b=0,c=rd.length;c>b;b++)if(rd[b][1].exec(d)){a._f+=(e[6]||" ")+rd[b][0];break}d.match(ad)&&(a._f+="Z"),va(a)}else a._isValid=!1}function da(b){var c=sd.exec(b._i);return null!==c?void(b._d=new Date(+c[1])):(ca(b),void(b._isValid===!1&&(delete b._isValid,a.createFromInputFallback(b))))}function ea(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function fa(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function ga(a){return ha(a)?366:365}function ha(a){return a%4===0&&a%100!==0||a%400===0}function ia(){return ha(this.year())}function ja(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=Da(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ka(a){return ja(a,this._week.dow,this._week.doy).week}function la(){return this._week.dow}function ma(){return this._week.doy}function na(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")}function oa(a){var b=ja(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")}function pa(a,b,c,d,e){var f,g=6+e-d,h=fa(a,0,1+g),i=h.getUTCDay();return e>i&&(i+=7),c=null!=c?1*c:e,f=1+g+7*(b-1)-i+c,{year:f>0?a:a-1,dayOfYear:f>0?f:ga(a-1)+f}}function qa(a){var b=Math.round((this.clone().startOf("day")-this.clone().startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}function ra(a,b,c){return null!=a?a:null!=b?b:c}function sa(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function ta(a){var b,c,d,e,f=[];if(!a._d){for(d=sa(a),a._w&&null==a._a[hd]&&null==a._a[gd]&&ua(a),a._dayOfYear&&(e=ra(a._a[fd],d[fd]),a._dayOfYear>ga(e)&&(j(a)._overflowDayOfYear=!0),c=fa(e,0,a._dayOfYear),a._a[gd]=c.getUTCMonth(),a._a[hd]=c.getUTCDate()),b=0;3>b&&null==a._a[b];++b)a._a[b]=f[b]=d[b];for(;7>b;b++)a._a[b]=f[b]=null==a._a[b]?2===b?1:0:a._a[b];24===a._a[id]&&0===a._a[jd]&&0===a._a[kd]&&0===a._a[ld]&&(a._nextDay=!0,a._a[id]=0),a._d=(a._useUTC?fa:ea).apply(null,f),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[id]=24)}}function ua(a){var b,c,d,e,f,g,h;b=a._w,null!=b.GG||null!=b.W||null!=b.E?(f=1,g=4,c=ra(b.GG,a._a[fd],ja(Da(),1,4).year),d=ra(b.W,1),e=ra(b.E,1)):(f=a._locale._week.dow,g=a._locale._week.doy,c=ra(b.gg,a._a[fd],ja(Da(),f,g).year),d=ra(b.w,1),null!=b.d?(e=b.d,f>e&&++d):e=null!=b.e?b.e+f:f),h=pa(c,d,e,g,f),a._a[fd]=h.year,a._dayOfYear=h.dayOfYear}function va(b){if(b._f===a.ISO_8601)return void ca(b);b._a=[],j(b).empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,k=0;for(e=L(b._f,b._locale).match(Nc)||[],c=0;c0&&j(b).unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),k+=d.length),Qc[f]?(d?j(b).empty=!1:j(b).unusedTokens.push(f),S(f,d,b)):b._strict&&!d&&j(b).unusedTokens.push(f);j(b).charsLeftOver=i-k,h.length>0&&j(b).unusedInput.push(h),j(b).bigHour===!0&&b._a[id]<=12&&b._a[id]>0&&(j(b).bigHour=void 0),b._a[id]=wa(b._locale,b._a[id],b._meridiem),ta(b),$(b)}function wa(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function xa(a){var b,c,d,e,f;if(0===a._f.length)return j(a).invalidFormat=!0,void(a._d=new Date(NaN));for(e=0;ef)&&(d=f,c=b));g(a,c||b)}function ya(a){if(!a._d){var b=B(a._i);a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],ta(a)}}function za(a){var b=new n($(Aa(a)));return b._nextDay&&(b.add(1,"d"),b._nextDay=void 0),b}function Aa(a){var b=a._i,e=a._f;return a._locale=a._locale||y(a._l),null===b||void 0===e&&""===b?l({nullInput:!0}):("string"==typeof b&&(a._i=b=a._locale.preparse(b)),o(b)?new n($(b)):(c(e)?xa(a):e?va(a):d(b)?a._d=b:Ba(a),a))}function Ba(b){var f=b._i;void 0===f?b._d=new Date:d(f)?b._d=new Date(+f):"string"==typeof f?da(b):c(f)?(b._a=e(f.slice(0),function(a){return parseInt(a,10)}),ta(b)):"object"==typeof f?ya(b):"number"==typeof f?b._d=new Date(f):a.createFromInputFallback(b)}function Ca(a,b,c,d,e){var f={};return"boolean"==typeof c&&(d=c,c=void 0),f._isAMomentObject=!0,f._useUTC=f._isUTC=e,f._l=c,f._i=a,f._f=b,f._strict=d,za(f)}function Da(a,b,c,d){return Ca(a,b,c,d,!1)}function Ea(a,b){var d,e;if(1===b.length&&c(b[0])&&(b=b[0]),!b.length)return Da();for(d=b[0],e=1;ea&&(a=-a,c="-"),c+G(~~(a/60),2)+b+G(~~a%60,2)})}function Ka(a){var b=(a||"").match(ad)||[],c=b[b.length-1]||[],d=(c+"").match(xd)||["-",0,0],e=+(60*d[1])+q(d[2]);return"+"===d[0]?e:-e}function La(b,c){var e,f;return c._isUTC?(e=c.clone(),f=(o(b)||d(b)?+b:+Da(b))-+e,e._d.setTime(+e._d+f),a.updateOffset(e,!1),e):Da(b).local()}function Ma(a){return 15*-Math.round(a._d.getTimezoneOffset()/15)}function Na(b,c){var d,e=this._offset||0;return null!=b?("string"==typeof b&&(b=Ka(b)),Math.abs(b)<16&&(b=60*b),!this._isUTC&&c&&(d=Ma(this)),this._offset=b,this._isUTC=!0,null!=d&&this.add(d,"m"),e!==b&&(!c||this._changeInProgress?bb(this,Ya(b-e,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,a.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?e:Ma(this)}function Oa(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}function Pa(a){return this.utcOffset(0,a)}function Qa(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(Ma(this),"m")),this}function Ra(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(Ka(this._i)),this}function Sa(a){return a=a?Da(a).utcOffset():0,(this.utcOffset()-a)%60===0}function Ta(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()}function Ua(){if("undefined"!=typeof this._isDSTShifted)return this._isDSTShifted;var a={};if(m(a,this),a=Aa(a),a._a){var b=a._isUTC?h(a._a):Da(a._a);this._isDSTShifted=this.isValid()&&r(a._a,b.toArray())>0}else this._isDSTShifted=!1;return this._isDSTShifted}function Va(){return!this._isUTC}function Wa(){return this._isUTC}function Xa(){return this._isUTC&&0===this._offset}function Ya(a,b){var c,d,e,g=a,h=null;return Ia(a)?g={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(g={},b?g[b]=a:g.milliseconds=a):(h=yd.exec(a))?(c="-"===h[1]?-1:1,g={y:0,d:q(h[hd])*c,h:q(h[id])*c,m:q(h[jd])*c,s:q(h[kd])*c,ms:q(h[ld])*c}):(h=zd.exec(a))?(c="-"===h[1]?-1:1,g={y:Za(h[2],c),M:Za(h[3],c),d:Za(h[4],c),h:Za(h[5],c),m:Za(h[6],c),s:Za(h[7],c),w:Za(h[8],c)}):null==g?g={}:"object"==typeof g&&("from"in g||"to"in g)&&(e=_a(Da(g.from),Da(g.to)),g={},g.ms=e.milliseconds,g.M=e.months),d=new Ha(g),Ia(a)&&f(a,"_locale")&&(d._locale=a._locale),d}function Za(a,b){var c=a&&parseFloat(a.replace(",","."));return(isNaN(c)?0:c)*b}function $a(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function _a(a,b){var c;return b=La(b,a),a.isBefore(b)?c=$a(a,b):(c=$a(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c}function ab(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(ba(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=Ya(c,d),bb(this,e,a),this}}function bb(b,c,d,e){var f=c._milliseconds,g=c._days,h=c._months;e=null==e?!0:e,f&&b._d.setTime(+b._d+f*d),g&&E(b,"Date",D(b,"Date")+g*d),h&&X(b,D(b,"Month")+h*d),e&&a.updateOffset(b,g||h)}function cb(a,b){var c=a||Da(),d=La(c,this).startOf("day"),e=this.diff(d,"days",!0),f=-6>e?"sameElse":-1>e?"lastWeek":0>e?"lastDay":1>e?"sameDay":2>e?"nextDay":7>e?"nextWeek":"sameElse";return this.format(b&&b[f]||this.localeData().calendar(f,this,Da(c)))}function db(){return new n(this)}function eb(a,b){var c;return b=A("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Da(a),+this>+a):(c=o(a)?+a:+Da(a),c<+this.clone().startOf(b))}function fb(a,b){var c;return b=A("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=o(a)?a:Da(a),+a>+this):(c=o(a)?+a:+Da(a),+this.clone().endOf(b)b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function kb(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")}function lb(){var a=this.clone().utc();return 0b;b++)if(this._weekdaysParse[b]||(c=Da([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b}function Pb(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=Kb(a,this.localeData()),this.add(a-b,"d")):b}function Qb(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")}function Rb(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)}function Sb(a,b){H(a,0,0,function(){return this.localeData().meridiem(this.hours(),this.minutes(),b)})}function Tb(a,b){return b._meridiemParse}function Ub(a){return"p"===(a+"").toLowerCase().charAt(0)}function Vb(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"}function Wb(a,b){b[ld]=q(1e3*("0."+a))}function Xb(){return this._isUTC?"UTC":""}function Yb(){return this._isUTC?"Coordinated Universal Time":""}function Zb(a){return Da(1e3*a)}function $b(){return Da.apply(null,arguments).parseZone()}function _b(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.call(b,c):d}function ac(a){var b=this._longDateFormat[a],c=this._longDateFormat[a.toUpperCase()];return b||!c?b:(this._longDateFormat[a]=c.replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a])}function bc(){return this._invalidDate}function cc(a){return this._ordinal.replace("%d",a)}function dc(a){return a}function ec(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)}function fc(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)}function gc(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)}function hc(a,b,c,d){var e=y(),f=h().set(d,b);return e[c](f,a)}function ic(a,b,c,d,e){if("number"==typeof a&&(b=a,a=void 0),a=a||"",null!=b)return hc(a,b,c,e);var f,g=[];for(f=0;d>f;f++)g[f]=hc(a,f,c,e);return g}function jc(a,b){return ic(a,b,"months",12,"month")}function kc(a,b){return ic(a,b,"monthsShort",12,"month")}function lc(a,b){return ic(a,b,"weekdays",7,"day")}function mc(a,b){return ic(a,b,"weekdaysShort",7,"day")}function nc(a,b){return ic(a,b,"weekdaysMin",7,"day")}function oc(){var a=this._data;return this._milliseconds=Wd(this._milliseconds),this._days=Wd(this._days),this._months=Wd(this._months),a.milliseconds=Wd(a.milliseconds),a.seconds=Wd(a.seconds),a.minutes=Wd(a.minutes),a.hours=Wd(a.hours),a.months=Wd(a.months),a.years=Wd(a.years),this}function pc(a,b,c,d){var e=Ya(b,c);return a._milliseconds+=d*e._milliseconds,a._days+=d*e._days,a._months+=d*e._months,a._bubble()}function qc(a,b){return pc(this,a,b,1)}function rc(a,b){return pc(this,a,b,-1)}function sc(a){return 0>a?Math.floor(a):Math.ceil(a)}function tc(){var a,b,c,d,e,f=this._milliseconds,g=this._days,h=this._months,i=this._data;return f>=0&&g>=0&&h>=0||0>=f&&0>=g&&0>=h||(f+=864e5*sc(vc(h)+g),g=0,h=0),i.milliseconds=f%1e3,a=p(f/1e3),i.seconds=a%60,b=p(a/60),i.minutes=b%60,c=p(b/60),i.hours=c%24,g+=p(c/24),e=p(uc(g)),h+=e,g-=sc(vc(e)),d=p(h/12),h%=12,i.days=g,i.months=h,i.years=d,this}function uc(a){return 4800*a/146097}function vc(a){return 146097*a/4800}function wc(a){var b,c,d=this._milliseconds;if(a=A(a),"month"===a||"year"===a)return b=this._days+d/864e5,c=this._months+uc(b),"month"===a?c:c/12;switch(b=this._days+Math.round(vc(this._months)),a){case"week":return b/7+d/6048e5;case"day":return b+d/864e5;case"hour":return 24*b+d/36e5;case"minute":return 1440*b+d/6e4;case"second":return 86400*b+d/1e3;case"millisecond":return Math.floor(864e5*b)+d;default:throw new Error("Unknown unit "+a)}}function xc(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*q(this._months/12)}function yc(a){return function(){return this.as(a)}}function zc(a){return a=A(a),this[a+"s"]()}function Ac(a){return function(){return this._data[a]}}function Bc(){return p(this.days()/7)}function Cc(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function Dc(a,b,c){var d=Ya(a).abs(),e=ke(d.as("s")),f=ke(d.as("m")),g=ke(d.as("h")),h=ke(d.as("d")),i=ke(d.as("M")),j=ke(d.as("y")),k=e0,k[4]=c,Cc.apply(null,k)}function Ec(a,b){return void 0===le[a]?!1:void 0===b?le[a]:(le[a]=b,!0)}function Fc(a){var b=this.localeData(),c=Dc(this,!a,b);return a&&(c=b.pastFuture(+this,c)),b.postformat(c)}function Gc(){var a,b,c,d=me(this._milliseconds)/1e3,e=me(this._days),f=me(this._months);a=p(d/60),b=p(a/60),d%=60,a%=60,c=p(f/12),f%=12;var g=c,h=f,i=e,j=b,k=a,l=d,m=this.asSeconds();return m?(0>m?"-":"")+"P"+(g?g+"Y":"")+(h?h+"M":"")+(i?i+"D":"")+(j||k||l?"T":"")+(j?j+"H":"")+(k?k+"M":"")+(l?l+"S":""):"P0D"}var Hc,Ic,Jc=a.momentProperties=[],Kc=!1,Lc={},Mc={},Nc=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,Oc=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Pc={},Qc={},Rc=/\d/,Sc=/\d\d/,Tc=/\d{3}/,Uc=/\d{4}/,Vc=/[+-]?\d{6}/,Wc=/\d\d?/,Xc=/\d{1,3}/,Yc=/\d{1,4}/,Zc=/[+-]?\d{1,6}/,$c=/\d+/,_c=/[+-]?\d+/,ad=/Z|[+-]\d\d:?\d\d/gi,bd=/[+-]?\d+(\.\d{1,3})?/,cd=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,dd={},ed={},fd=0,gd=1,hd=2,id=3,jd=4,kd=5,ld=6;H("M",["MM",2],"Mo",function(){return this.month()+1}),H("MMM",0,0,function(a){return this.localeData().monthsShort(this,a)}),H("MMMM",0,0,function(a){return this.localeData().months(this,a)}),z("month","M"),N("M",Wc),N("MM",Wc,Sc),N("MMM",cd),N("MMMM",cd),Q(["M","MM"],function(a,b){b[gd]=q(a)-1}),Q(["MMM","MMMM"],function(a,b,c,d){var e=c._locale.monthsParse(a,d,c._strict);null!=e?b[gd]=e:j(c).invalidMonth=a});var md="January_February_March_April_May_June_July_August_September_October_November_December".split("_"),nd="Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),od={};a.suppressDeprecationWarnings=!1;var pd=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,qd=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],rd=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],sd=/^\/?Date\((\-?\d+)/i;a.createFromInputFallback=aa("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),H(0,["YY",2],0,function(){return this.year()%100}),H(0,["YYYY",4],0,"year"),H(0,["YYYYY",5],0,"year"),H(0,["YYYYYY",6,!0],0,"year"),z("year","y"),N("Y",_c),N("YY",Wc,Sc),N("YYYY",Yc,Uc),N("YYYYY",Zc,Vc),N("YYYYYY",Zc,Vc),Q(["YYYYY","YYYYYY"],fd),Q("YYYY",function(b,c){c[fd]=2===b.length?a.parseTwoDigitYear(b):q(b)}),Q("YY",function(b,c){c[fd]=a.parseTwoDigitYear(b)}),a.parseTwoDigitYear=function(a){return q(a)+(q(a)>68?1900:2e3)};var td=C("FullYear",!1);H("w",["ww",2],"wo","week"),H("W",["WW",2],"Wo","isoWeek"),z("week","w"),z("isoWeek","W"),N("w",Wc),N("ww",Wc,Sc),N("W",Wc),N("WW",Wc,Sc),R(["w","ww","W","WW"],function(a,b,c,d){b[d.substr(0,1)]=q(a)});var ud={dow:0,doy:6};H("DDD",["DDDD",3],"DDDo","dayOfYear"),z("dayOfYear","DDD"),N("DDD",Xc),N("DDDD",Tc),Q(["DDD","DDDD"],function(a,b,c){c._dayOfYear=q(a)}),a.ISO_8601=function(){};var vd=aa("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(){var a=Da.apply(null,arguments);return this>a?this:a}),wd=aa("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(){var a=Da.apply(null,arguments);return a>this?this:a});Ja("Z",":"),Ja("ZZ",""),N("Z",ad),N("ZZ",ad),Q(["Z","ZZ"],function(a,b,c){c._useUTC=!0,c._tzm=Ka(a)});var xd=/([\+\-]|\d\d)/gi;a.updateOffset=function(){};var yd=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,zd=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;Ya.fn=Ha.prototype;var Ad=ab(1,"add"),Bd=ab(-1,"subtract");a.defaultFormat="YYYY-MM-DDTHH:mm:ssZ";var Cd=aa("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(a){return void 0===a?this.localeData():this.locale(a)});H(0,["gg",2],0,function(){return this.weekYear()%100}),H(0,["GG",2],0,function(){return this.isoWeekYear()%100}),Db("gggg","weekYear"),Db("ggggg","weekYear"),Db("GGGG","isoWeekYear"),Db("GGGGG","isoWeekYear"),z("weekYear","gg"),z("isoWeekYear","GG"),N("G",_c),N("g",_c),N("GG",Wc,Sc),N("gg",Wc,Sc),N("GGGG",Yc,Uc),N("gggg",Yc,Uc),N("GGGGG",Zc,Vc),N("ggggg",Zc,Vc),R(["gggg","ggggg","GGGG","GGGGG"],function(a,b,c,d){b[d.substr(0,2)]=q(a)}),R(["gg","GG"],function(b,c,d,e){c[e]=a.parseTwoDigitYear(b)}),H("Q",0,0,"quarter"),z("quarter","Q"),N("Q",Rc),Q("Q",function(a,b){b[gd]=3*(q(a)-1)}),H("D",["DD",2],"Do","date"),z("date","D"),N("D",Wc),N("DD",Wc,Sc),N("Do",function(a,b){return a?b._ordinalParse:b._ordinalParseLenient}),Q(["D","DD"],hd),Q("Do",function(a,b){b[hd]=q(a.match(Wc)[0],10)});var Dd=C("Date",!0);H("d",0,"do","day"),H("dd",0,0,function(a){return this.localeData().weekdaysMin(this,a)}),H("ddd",0,0,function(a){return this.localeData().weekdaysShort(this,a)}),H("dddd",0,0,function(a){return this.localeData().weekdays(this,a)}),H("e",0,0,"weekday"),H("E",0,0,"isoWeekday"),z("day","d"),z("weekday","e"),z("isoWeekday","E"),N("d",Wc),N("e",Wc),N("E",Wc),N("dd",cd),N("ddd",cd),N("dddd",cd),R(["dd","ddd","dddd"],function(a,b,c){var d=c._locale.weekdaysParse(a);null!=d?b.d=d:j(c).invalidWeekday=a}),R(["d","e","E"],function(a,b,c,d){b[d]=q(a)});var Ed="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Fd="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Gd="Su_Mo_Tu_We_Th_Fr_Sa".split("_");H("H",["HH",2],0,"hour"),H("h",["hh",2],0,function(){return this.hours()%12||12}),Sb("a",!0),Sb("A",!1),z("hour","h"),N("a",Tb),N("A",Tb),N("H",Wc),N("h",Wc),N("HH",Wc,Sc),N("hh",Wc,Sc),Q(["H","HH"],id),Q(["a","A"],function(a,b,c){c._isPm=c._locale.isPM(a),c._meridiem=a}),Q(["h","hh"],function(a,b,c){b[id]=q(a),j(c).bigHour=!0});var Hd=/[ap]\.?m?\.?/i,Id=C("Hours",!0);H("m",["mm",2],0,"minute"),z("minute","m"),N("m",Wc),N("mm",Wc,Sc),Q(["m","mm"],jd);var Jd=C("Minutes",!1);H("s",["ss",2],0,"second"),z("second","s"),N("s",Wc),N("ss",Wc,Sc),Q(["s","ss"],kd);var Kd=C("Seconds",!1);H("S",0,0,function(){return~~(this.millisecond()/100)}),H(0,["SS",2],0,function(){return~~(this.millisecond()/10)}),H(0,["SSS",3],0,"millisecond"),H(0,["SSSS",4],0,function(){return 10*this.millisecond()}),H(0,["SSSSS",5],0,function(){return 100*this.millisecond()}),H(0,["SSSSSS",6],0,function(){return 1e3*this.millisecond()}),H(0,["SSSSSSS",7],0,function(){return 1e4*this.millisecond()}),H(0,["SSSSSSSS",8],0,function(){return 1e5*this.millisecond()}),H(0,["SSSSSSSSS",9],0,function(){return 1e6*this.millisecond()}),z("millisecond","ms"),N("S",Xc,Rc),N("SS",Xc,Sc),N("SSS",Xc,Tc);var Ld;for(Ld="SSSS";Ld.length<=9;Ld+="S")N(Ld,$c);for(Ld="S";Ld.length<=9;Ld+="S")Q(Ld,Wb);var Md=C("Milliseconds",!1);H("z",0,0,"zoneAbbr"),H("zz",0,0,"zoneName");var Nd=n.prototype;Nd.add=Ad,Nd.calendar=cb,Nd.clone=db,Nd.diff=ib,Nd.endOf=ub,Nd.format=mb,Nd.from=nb,Nd.fromNow=ob,Nd.to=pb,Nd.toNow=qb,Nd.get=F,Nd.invalidAt=Cb,Nd.isAfter=eb,Nd.isBefore=fb,Nd.isBetween=gb,Nd.isSame=hb,Nd.isValid=Ab,Nd.lang=Cd,Nd.locale=rb,Nd.localeData=sb,Nd.max=wd,Nd.min=vd,Nd.parsingFlags=Bb,Nd.set=F,Nd.startOf=tb,Nd.subtract=Bd,Nd.toArray=yb,Nd.toObject=zb,Nd.toDate=xb,Nd.toISOString=lb,Nd.toJSON=lb,Nd.toString=kb,Nd.unix=wb,Nd.valueOf=vb,Nd.year=td,Nd.isLeapYear=ia,Nd.weekYear=Fb,Nd.isoWeekYear=Gb,Nd.quarter=Nd.quarters=Jb,Nd.month=Y,Nd.daysInMonth=Z,Nd.week=Nd.weeks=na,Nd.isoWeek=Nd.isoWeeks=oa,Nd.weeksInYear=Ib,Nd.isoWeeksInYear=Hb,Nd.date=Dd,Nd.day=Nd.days=Pb,Nd.weekday=Qb,Nd.isoWeekday=Rb,Nd.dayOfYear=qa,Nd.hour=Nd.hours=Id,Nd.minute=Nd.minutes=Jd,Nd.second=Nd.seconds=Kd, 7 | Nd.millisecond=Nd.milliseconds=Md,Nd.utcOffset=Na,Nd.utc=Pa,Nd.local=Qa,Nd.parseZone=Ra,Nd.hasAlignedHourOffset=Sa,Nd.isDST=Ta,Nd.isDSTShifted=Ua,Nd.isLocal=Va,Nd.isUtcOffset=Wa,Nd.isUtc=Xa,Nd.isUTC=Xa,Nd.zoneAbbr=Xb,Nd.zoneName=Yb,Nd.dates=aa("dates accessor is deprecated. Use date instead.",Dd),Nd.months=aa("months accessor is deprecated. Use month instead",Y),Nd.years=aa("years accessor is deprecated. Use year instead",td),Nd.zone=aa("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",Oa);var Od=Nd,Pd={sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},Qd={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},Rd="Invalid date",Sd="%d",Td=/\d{1,2}/,Ud={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},Vd=s.prototype;Vd._calendar=Pd,Vd.calendar=_b,Vd._longDateFormat=Qd,Vd.longDateFormat=ac,Vd._invalidDate=Rd,Vd.invalidDate=bc,Vd._ordinal=Sd,Vd.ordinal=cc,Vd._ordinalParse=Td,Vd.preparse=dc,Vd.postformat=dc,Vd._relativeTime=Ud,Vd.relativeTime=ec,Vd.pastFuture=fc,Vd.set=gc,Vd.months=U,Vd._months=md,Vd.monthsShort=V,Vd._monthsShort=nd,Vd.monthsParse=W,Vd.week=ka,Vd._week=ud,Vd.firstDayOfYear=ma,Vd.firstDayOfWeek=la,Vd.weekdays=Lb,Vd._weekdays=Ed,Vd.weekdaysMin=Nb,Vd._weekdaysMin=Gd,Vd.weekdaysShort=Mb,Vd._weekdaysShort=Fd,Vd.weekdaysParse=Ob,Vd.isPM=Ub,Vd._meridiemParse=Hd,Vd.meridiem=Vb,w("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===q(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),a.lang=aa("moment.lang is deprecated. Use moment.locale instead.",w),a.langData=aa("moment.langData is deprecated. Use moment.localeData instead.",y);var Wd=Math.abs,Xd=yc("ms"),Yd=yc("s"),Zd=yc("m"),$d=yc("h"),_d=yc("d"),ae=yc("w"),be=yc("M"),ce=yc("y"),de=Ac("milliseconds"),ee=Ac("seconds"),fe=Ac("minutes"),ge=Ac("hours"),he=Ac("days"),ie=Ac("months"),je=Ac("years"),ke=Math.round,le={s:45,m:45,h:22,d:26,M:11},me=Math.abs,ne=Ha.prototype;ne.abs=oc,ne.add=qc,ne.subtract=rc,ne.as=wc,ne.asMilliseconds=Xd,ne.asSeconds=Yd,ne.asMinutes=Zd,ne.asHours=$d,ne.asDays=_d,ne.asWeeks=ae,ne.asMonths=be,ne.asYears=ce,ne.valueOf=xc,ne._bubble=tc,ne.get=zc,ne.milliseconds=de,ne.seconds=ee,ne.minutes=fe,ne.hours=ge,ne.days=he,ne.weeks=Bc,ne.months=ie,ne.years=je,ne.humanize=Fc,ne.toISOString=Gc,ne.toString=Gc,ne.toJSON=Gc,ne.locale=rb,ne.localeData=sb,ne.toIsoString=aa("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",Gc),ne.lang=Cd,H("X",0,0,"unix"),H("x",0,0,"valueOf"),N("x",_c),N("X",bd),Q("X",function(a,b,c){c._d=new Date(1e3*parseFloat(a,10))}),Q("x",function(a,b,c){c._d=new Date(q(a))}),a.version="2.10.6",b(Da),a.fn=Od,a.min=Fa,a.max=Ga,a.utc=h,a.unix=Zb,a.months=jc,a.isDate=d,a.locale=w,a.invalid=l,a.duration=Ya,a.isMoment=o,a.weekdays=lc,a.parseZone=$b,a.localeData=y,a.isDuration=Ia,a.monthsShort=kc,a.weekdaysMin=nc,a.defineLocale=x,a.weekdaysShort=mc,a.normalizeUnits=A,a.relativeTimeThreshold=Ec;var oe=a;return oe}); -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | /* ---- DON'T EDIT BELOW ---- */ 2 | 3 | var Plume = Plume || {}; 4 | 5 | Plume = (function () { 6 | 'use strict'; 7 | 8 | var config = Plume.config || {}; 9 | var appURL = window.location.origin+window.location.pathname; 10 | 11 | // RDF 12 | var PROXY = "https://databox.me/,proxy?uri={uri}"; 13 | var TIMEOUT = 5000; 14 | 15 | $rdf.Fetcher.crossSiteProxyTemplate = PROXY; 16 | // common vocabs 17 | var RDF = $rdf.Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#"); 18 | var FOAF = $rdf.Namespace("http://xmlns.com/foaf/0.1/"); 19 | var DCT = $rdf.Namespace("http://purl.org/dc/terms/"); 20 | var LDP = $rdf.Namespace("http://www.w3.org/ns/ldp#"); 21 | var SIOC = $rdf.Namespace("http://rdfs.org/sioc/ns#"); 22 | var SIOC = $rdf.Namespace("http://rdfs.org/sioc/ns#"); 23 | var SOLID = $rdf.Namespace("http://www.w3.org/ns/solid/terms#"); 24 | 25 | // init markdown editor 26 | var editor = new SimpleMDE({ 27 | status: false, 28 | spellChecker: false 29 | }); 30 | editor.codemirror.on("change", function(){ 31 | savePendingPost(editor.value()); 32 | }); 33 | 34 | // sanitize value to/from markdown editor 35 | var getBodyValue = function() { 36 | var val = editor.codemirror.getValue(); 37 | return val.replace('"', '\"'); 38 | }; 39 | var setBodyValue = function(val) { 40 | editor.value(val); 41 | } 42 | 43 | // set up markdown parser 44 | var parseMD = function(data) { 45 | if (data) { 46 | return editor.markdown(data); 47 | } 48 | return ''; 49 | }; 50 | 51 | // Get params from the URL 52 | var queryVals = (function(a) { 53 | if (a == "") return {}; 54 | var b = {}; 55 | for (var i = 0; i < a.length; ++i) 56 | { 57 | var p=a[i].split('=', 2); 58 | if (p.length == 1) 59 | b[p[0]] = ""; 60 | else 61 | b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); 62 | } 63 | return b; 64 | })(window.location.search.substr(1).split('&')); 65 | 66 | var defaultUser = { 67 | name: "John Doe", 68 | webid: "https://example.org/user#me", 69 | picture: "img/icon-blue.svg", 70 | authenticated: false 71 | }; 72 | 73 | var user = {}; 74 | var posts = {}; 75 | var authors = {}; 76 | var webSockets = {}; 77 | 78 | // Initializer 79 | var init = function(configData) { 80 | // set config params 81 | applyConfig(configData); 82 | 83 | // try to load authors 84 | loadLocalAuthors(); 85 | 86 | // Add online/offline events 87 | Solid.status.onOffline(function(){ 88 | notify('info', "You are no longer connected to the internet.", 3000); 89 | }); 90 | Solid.status.onOnline(function(){ 91 | notify('info', "And we're back!"); 92 | }); 93 | // Init growl-like notifications 94 | window.addEventListener('load', function () { 95 | Notification.requestPermission(function (status) { 96 | // This allows to use Notification.permission with Chrome/Safari 97 | if (Notification.permission !== status) { 98 | Notification.permission = status; 99 | } 100 | }); 101 | }); 102 | 103 | // basic app routes 104 | if (queryVals['post'] && queryVals['post'].length > 0) { 105 | var url = decodeURIComponent(queryVals['post']); 106 | showViewer(url); 107 | return; 108 | } else if (queryVals['view'] && queryVals['view'].length > 0) { 109 | // legacy [to be deprecated] 110 | var url = decodeURIComponent(queryVals['view']); 111 | showViewer(url); 112 | return; 113 | } else if (queryVals['edit'] && queryVals['edit'].length > 0) { 114 | var url = decodeURIComponent(queryVals['edit']); 115 | showEditor(url); 116 | return; 117 | } else if (queryVals['new'] !== undefined) { 118 | clearPendingPost(); 119 | showEditor(); 120 | return; 121 | } else if (queryVals['blog'] && queryVals['blog'].length > 0) { 122 | config.loadInBg = false; 123 | showBlog(queryVals['blog']); 124 | return; 125 | } else { 126 | // Load posts or initialize post container 127 | config.loadInBg = false; 128 | if (config.postsURL && config.postsURL.length > 0) { 129 | showBlog(config.postsURL); 130 | } else { 131 | showInitDialog(); 132 | } 133 | } 134 | }; 135 | 136 | // Set default config values 137 | var applyConfig = function(configData) { 138 | // loaded config from file 139 | config.defaultPath = 'posts'; 140 | if (configData) { 141 | config = configData; 142 | // append trailing slash to data path if missing 143 | if (config.defaultPath.lastIndexOf('/') < 0) { 144 | config.defaultPath += '/'; 145 | } 146 | config.saveDate = Date.now(); 147 | saveLocalStorage(); 148 | } else { 149 | // try to load config from localStorage 150 | console.log("Loading config from localStorage"); 151 | loadLocalStorage(); 152 | } 153 | 154 | document.querySelector('.blog-picture').src = config.picture; 155 | document.querySelector('.blog-title').innerHTML = config.title; 156 | document.querySelector('title').innerHTML = config.title; 157 | document.querySelector('.blog-tagline').innerHTML = config.tagline; 158 | // set default parent element for posts 159 | config.postsElement = '.posts'; 160 | 161 | if (user.authenticated) { 162 | hideLogin(); 163 | } 164 | 165 | // append trailing slash to data path if missing 166 | if (config.defaultPath.lastIndexOf('/') < 0) { 167 | config.defaultPath += '/'; 168 | } 169 | if (!config.postsURL || config.postsURL.length === 0) { 170 | config.postsURL = appURL + config.defaultPath; 171 | } 172 | 173 | config.loadInBg = true; 174 | }; 175 | 176 | // show a particular blog 177 | var showBlog = function(url) { 178 | // show loading 179 | if (!config.loadInBg) { 180 | showLoading(); 181 | } 182 | fetchPosts(url); 183 | }; 184 | 185 | // Init data container 186 | var initContainer = function(url) { 187 | Solid.web.head(url).then( 188 | function(container) { 189 | // create data container for posts if it doesn't exist 190 | if (!container.exists && container.xhr.status < 500) { 191 | Solid.web.post(appURL, config.defaultPath, null, true).then( 192 | function(res) { 193 | if (res.url && res.url.length > 0) { 194 | config.postsURL = res.url; 195 | } 196 | // add dummy post 197 | var acme = { 198 | title: "Welcome to Plume, a Solid blogging platform", 199 | author: user.webid, 200 | date: "3 Dec 2015", 201 | body: "```\nHellowWorld();\n```\n\n**Note!** This is a demo post created under your name. Feel free to remove it whenever you wish.\n\n*Plume* is a 100% client-side application built using [Solid standards](https://github.com/solid/), in which data is decoupled from the application itself. This means that you can host the application on any Web server, without having to install anything -- no database, no messing around with Node.js, it has 0 dependencies! It also means that other similar applications will be able to reuse the data resulting from your posts, without having to go through a complicated API.\n\nPlume uses [Markdown](https://en.wikipedia.org/wiki/Markdown) to provide you with the easiest and fastest experience for writing beautiful articles. Click the *Edit* button below to see this article.\n\nGive it a try, write your first post!", 202 | tags: [ 203 | { color: "#df2d4f", name: "Decentralization" }, 204 | { color: "#4d85d1", name: "Solid" } 205 | ] 206 | }; 207 | savePost(acme); 208 | } 209 | ) 210 | .catch( 211 | function(err) { 212 | console.log("Could not create data container for posts."); 213 | console.log(err); 214 | notify('error', 'Could not create data container'); 215 | } 216 | ); 217 | } else if (container.exists) { 218 | config.postsURL = appURL+config.defaultPath; 219 | fetchPosts(url); 220 | } 221 | } 222 | ); 223 | } 224 | 225 | // Log user in 226 | var login = function() { 227 | // Get the current user 228 | Solid.auth.login().then(function(webid){ 229 | gotWebID(webid); 230 | }).catch(function(err) { 231 | console.log(err); 232 | notify('error', "Authentication failed"); 233 | showError(err); 234 | }); 235 | }; 236 | // Signup for a WebID and space 237 | var signup = function() { 238 | Solid.auth.signup().then(function(webid) { 239 | gotWebID(webid); 240 | }).catch(function(err) { 241 | console.log("Err", err); 242 | notify('error', "Authentication failed"); 243 | showError(err); 244 | }); 245 | }; 246 | // Log user out 247 | var logout = function() { 248 | user = defaultUser; 249 | clearLocalStorage(); 250 | showLogin(); 251 | window.location.reload(); 252 | }; 253 | 254 | // set the logged in user 255 | var gotWebID = function(webid) { 256 | // set WebID 257 | user.webid = webid; 258 | user.authenticated = true; 259 | hideLogin(); 260 | // fetch and set user profile 261 | Solid.identity.getProfile(webid).then(function(g) { 262 | var profile = getUserProfile(webid, g); 263 | user.name = profile.name; 264 | user.picture = profile.picture; 265 | user.date = Date.now(); 266 | // add self to authors list 267 | authors[webid] = user; 268 | saveLocalAuthors(); 269 | // add workspaces 270 | Solid.identity.getWorkspaces(webid, g).then(function(ws){ 271 | user.workspaces = ws; 272 | // save to local storage and refresh page 273 | saveLocalStorage(); 274 | window.location.reload(); 275 | }).catch(function(err) { 276 | showError(err); 277 | // save to local storage and refresh page 278 | saveLocalStorage(); 279 | window.location.reload(); 280 | }); 281 | }); 282 | }; 283 | 284 | // get profile data for a given user 285 | // Returns 286 | // webid: "https://example.org/user#me" 287 | // name: "John Doe", 288 | // picture: "https://example.org/profile.png" 289 | var getUserProfile = function(webid, g) { 290 | var profile = {}; 291 | 292 | if (!g) { 293 | return profile; 294 | } 295 | 296 | var webidRes = $rdf.sym(webid); 297 | 298 | // set webid 299 | profile.webid = webid; 300 | 301 | // set name 302 | var name = g.any(webidRes, FOAF('name')); 303 | if (name && name.value.length > 0) { 304 | profile.name = name.value; 305 | } else { 306 | profile.name = ''; 307 | // use familyName and givenName instead of full name 308 | var givenName = g.any(webidRes, FOAF('familyName')); 309 | if (givenName) { 310 | profile.name += givenName.value; 311 | } 312 | var familyName = g.any(webidRes, FOAF('familyName')); 313 | if (familyName) { 314 | profile.name += (givenName)?' '+familyName.value:familyName.value; 315 | } 316 | // use nick 317 | if (!givenName && !familyName) { 318 | var nick = g.any(webidRes, FOAF('nick')); 319 | if (nick) { 320 | profile.name = nick.value; 321 | } 322 | } 323 | } 324 | 325 | // set picture 326 | var pic, img = g.any(webidRes, FOAF('img')); 327 | if (img) { 328 | pic = img; 329 | } else { 330 | // check if profile uses depic instead 331 | var depic = g.any(webidRes, FOAF('depiction')); 332 | if (depic) { 333 | pic = depic; 334 | } 335 | } 336 | if (pic && pic.uri.length > 0) { 337 | profile.picture = pic.uri; 338 | } 339 | 340 | return profile; 341 | }; 342 | 343 | var confirmDelete = function(url) { 344 | var postTitle = (posts[url].title)?'

'+posts[url].title+'

':'this post'; 345 | var div = document.createElement('div'); 346 | div.id = 'delete'; 347 | div.classList.add('dialog'); 348 | var section = document.createElement('section'); 349 | section.innerHTML = "You are about to delete "+postTitle; 350 | div.appendChild(section); 351 | 352 | var footer = document.createElement('footer'); 353 | 354 | var del = document.createElement('button'); 355 | del.classList.add("button"); 356 | del.classList.add('danger'); 357 | del.classList.add('float-left'); 358 | del.setAttribute('onclick', 'Plume.deletePost(\''+url+'\')'); 359 | del.innerHTML = 'Delete'; 360 | footer.appendChild(del); 361 | // delete button 362 | var cancel = document.createElement('button'); 363 | cancel.classList.add('button'); 364 | cancel.classList.add('float-right'); 365 | cancel.setAttribute('onclick', 'Plume.cancelDelete()'); 366 | cancel.innerHTML = 'Cancel'; 367 | footer.appendChild(cancel); 368 | div.appendChild(footer); 369 | 370 | // append to body 371 | document.querySelector('body').appendChild(div); 372 | }; 373 | 374 | var cancelDelete = function() { 375 | document.getElementById('delete').remove(); 376 | }; 377 | 378 | var deletePost = function(url) { 379 | if (url) { 380 | Solid.web.del(url).then( 381 | function(done) { 382 | if (done) { 383 | delete posts[url]; 384 | document.getElementById(url).remove(); 385 | document.getElementById('delete').remove(); 386 | notify('success', 'Successfully deleted post'); 387 | resetAll(true); 388 | } 389 | } 390 | ) 391 | .catch( 392 | function(err) { 393 | notify('error', 'Could not delete post'); 394 | resetAll(); 395 | } 396 | ); 397 | } 398 | }; 399 | 400 | var showError = function(err) { 401 | if (!err || !err.xhr) { 402 | return; 403 | } 404 | hideLoading(); 405 | var url = err.xhr.requestedURI; 406 | var errorText = ''; 407 | if (err.status > 400 && err.status < 500) { 408 | errorText = "Could not fetch URL"; 409 | } 410 | document.querySelector('.error-title').innerHTML = errorText + ' - ' + err.status; 411 | document.querySelector('.error-url').innerHTML = document.querySelector('.error-url').href = url; 412 | document.querySelector('.error').classList.remove('hidden'); 413 | }; 414 | 415 | var showViewer = function(url) { 416 | window.history.pushState("", document.querySelector('title').value, window.location.pathname+"?post="+encodeURIComponent(url)); 417 | // hide main page 418 | document.querySelector(config.postsElement).classList.add('hidden'); 419 | var viewer = document.querySelector('.viewer'); 420 | viewer.classList.remove('hidden'); 421 | 422 | var article = postToHTML(posts[url]); 423 | if (!article) { 424 | showLoading(); 425 | fetchPost(url).then( 426 | function(post) { 427 | // convert post to HTML 428 | posts[url] = post; 429 | hideLoading(); 430 | showViewer(url); 431 | } 432 | ).catch( 433 | function(err) { 434 | showError(err); 435 | } 436 | ); 437 | return; 438 | } 439 | 440 | // Update document title 441 | if (posts[url] && posts[url].title) { 442 | document.querySelector('title').innerHTML += ' - ' + posts[url].title; 443 | } 444 | 445 | // add last modified date 446 | if (posts[url].modified && posts[url].modified != posts[url].created) { 447 | var modDate = document.createElement('p'); 448 | modDate.innerHTML += ' '+"Last updated "+formatDate(posts[url].modified, 'LLL')+''; 449 | article.querySelector('section').appendChild(modDate); 450 | } 451 | 452 | // append article 453 | viewer.appendChild(article); 454 | var footer = document.createElement('footer'); 455 | viewer.appendChild(footer); 456 | // add separator 457 | var sep = document.createElement('h1'); 458 | sep.classList.add('content-subhead'); 459 | footer.appendChild(sep); 460 | // create button list 461 | var buttonList = document.createElement('div'); 462 | // add back button 463 | var back = document.createElement('a'); 464 | back.classList.add("action-button"); 465 | back.href = window.location.pathname; 466 | back.innerHTML = '≪ Back to blog'; 467 | buttonList.appendChild(back); 468 | // add view source 469 | if (config.showSources) { 470 | var src = document.createElement('a'); 471 | src.classList.add("action-button"); 472 | src.href = url; 473 | src.target = '_blank'; 474 | src.innerHTML = 'View data'; 475 | buttonList.appendChild(src); 476 | } 477 | // append button list to viewer 478 | footer.appendChild(buttonList); 479 | } 480 | 481 | var showEditor = function(url) { 482 | if (!user.authenticated) { 483 | notify('all', "You must log in before creating or editing posts."); 484 | return; 485 | } 486 | 487 | // make sure we're entering in edit mode 488 | if (editor.isPreviewActive()) { 489 | togglePreview(); 490 | } 491 | // hide nav button 492 | document.getElementById('menu-button').classList.add('hidden'); 493 | // handle tags 494 | var tags = document.querySelector('.editor-tags'); 495 | var appendTag = function(name, color) { 496 | var tagDiv = document.createElement('div'); 497 | tagDiv.classList.add('post-category'); 498 | tagDiv.classList.add('inline-block'); 499 | if (color) { 500 | tagDiv.setAttribute('style', 'background:'+color+';'); 501 | } 502 | var span = document.createElement('span'); 503 | span.innerHTML = name; 504 | tagDiv.appendChild(span); 505 | var tagLink = document.createElement('a'); 506 | tagLink.setAttribute('onclick', 'this.parentElement.remove()'); 507 | tagLink.innerHTML = 'x'; 508 | tagDiv.appendChild(tagLink); 509 | tags.appendChild(tagDiv); 510 | // clear input 511 | document.querySelector('.editor-add-tag').value = ''; 512 | }; 513 | 514 | var loadPost = function(url) { 515 | var post = posts[url]; 516 | if (post.title) { 517 | document.querySelector('.editor-title').value = post.title; 518 | // Also update document title 519 | document.querySelector('title').innerHTML += ' - Editing - ' + posts[url].title; 520 | } 521 | if (post.author) { 522 | var author = getAuthorByWebID(post.author); 523 | document.querySelector('.editor-author').innerHTML = author.name; 524 | } 525 | if (post.created) { 526 | document.querySelector('.editor-date').innerHTML = formatDate(post.created); 527 | } 528 | 529 | // add tags 530 | if (post.tags && post.tags.length > 0) { 531 | var tagInput = document.createElement('input'); 532 | for (var i in post.tags) { 533 | var tag = post.tags[i]; 534 | if (tag.name && tag.name.length > 0) { 535 | appendTag(tag.name, tag.color); 536 | } 537 | } 538 | 539 | } 540 | if (post.body) { 541 | setBodyValue(decodeHTML(post.body)); 542 | } 543 | 544 | document.querySelector('.publish').innerHTML = "Update"; 545 | document.querySelector('.publish').setAttribute('onclick', 'Plume.publishPost(\''+url+'\')'); 546 | window.history.pushState("", document.querySelector('title').value, window.location.pathname+"?edit="+encodeURIComponent(url)); 547 | }; 548 | 549 | document.querySelector('.posts').classList.add('hidden'); 550 | document.querySelector('.viewer').classList.add('hidden'); 551 | document.querySelector('.start').classList.add('hidden'); 552 | document.querySelector('.editor').classList.remove('hidden'); 553 | document.querySelector('.editor-title').focus(); 554 | document.querySelector('.editor-author').innerHTML = user.name; 555 | document.querySelector('.editor-date').innerHTML = formatDate(); 556 | document.querySelector('.editor-tags').innerHTML = ''; 557 | 558 | // add event listener and set up tags 559 | // document.querySelector('.editor-add-tag').value = ''; 560 | // document.querySelector('.editor-add-tag').onkeypress = function(e){ 561 | // if (!e) e = window.event; 562 | // var keyCode = e.keyCode || e.which; 563 | // if (keyCode == '13'){ 564 | // appendTag(document.querySelector('.editor-add-tag').value, document.querySelector('.color-picker').style.background); 565 | // } 566 | // } 567 | 568 | // preload data if updating 569 | if (url && url.length > 0) { 570 | if (posts[url]) { 571 | loadPost(url); 572 | } else { 573 | fetchPost(url).then( 574 | function(post) { 575 | loadPost(url); 576 | } 577 | ); 578 | } 579 | } else { 580 | // resume post if we have data 581 | var post = loadPendingPost(); 582 | if (post) { 583 | setBodyValue(post.body); 584 | document.querySelector('.editor-title').value = post.title; 585 | } 586 | document.querySelector('.publish').innerHTML = "Publish"; 587 | document.querySelector('.publish').setAttribute('onclick', 'Plume.publishPost()'); 588 | } 589 | }; 590 | 591 | var publishPost = function(url) { 592 | var post = (url)?posts[url]:{}; 593 | post.title = trim(document.querySelector('.editor-title').value); 594 | post.body = getBodyValue(); 595 | post.tags = []; 596 | var allTags = document.querySelectorAll('.editor-tags .post-category'); 597 | for (var i in allTags) { 598 | if (allTags[i].style) { 599 | var tag = {}; 600 | tag.name = allTags[i].querySelector('span').innerHTML; 601 | tag.color = rgbToHex(allTags[i].style.background); 602 | post.tags.push(tag); 603 | } 604 | } 605 | 606 | post.modified = moment().utcOffset('00:00').format("YYYY-MM-DDTHH:mm:ssZ"); 607 | 608 | if (!url) { 609 | post.author = user.webid; 610 | post.created = post.modified; 611 | } 612 | 613 | savePost(post, url); 614 | }; 615 | 616 | // save post data to server 617 | var savePost = function(post, url) { 618 | //TODO also write tags - use sioc:topic -> uri 619 | var g = new $rdf.graph(); 620 | g.add($rdf.sym(''), RDF('type'), SIOC('Post')); 621 | g.add($rdf.sym(''), DCT('title'), $rdf.lit(post.title)); 622 | g.add($rdf.sym(''), SIOC('has_creator'), $rdf.sym('#author')); 623 | g.add($rdf.sym(''), DCT('created'), $rdf.lit(post.created, '', $rdf.Symbol.prototype.XSDdateTime)); 624 | g.add($rdf.sym(''), DCT('modified'), $rdf.lit(post.modified, '', $rdf.Symbol.prototype.XSDdateTime)); 625 | g.add($rdf.sym(''), SIOC('content'), $rdf.lit(encodeHTML(post.body))); 626 | 627 | g.add($rdf.sym('#author'), RDF('type'), SIOC('UserAccount')); 628 | g.add($rdf.sym('#author'), SIOC('account_of'), $rdf.sym(post.author)); 629 | g.add($rdf.sym('#author'), FOAF('name'), $rdf.lit(authors[post.author].name)); 630 | g.add($rdf.sym('#author'), SIOC('avatar'), $rdf.sym(authors[post.author].picture)); 631 | 632 | var triples = new $rdf.Serializer(g).toN3(g); 633 | 634 | if (url) { 635 | var writer = Solid.web.put(url, triples); 636 | } else { 637 | var slug = makeSlug(post.title); 638 | var writer = Solid.web.post(config.postsURL, slug, triples); 639 | } 640 | writer.then( 641 | function(res) { 642 | // all done, clean up and go to initial state 643 | if (res.url.slice(0,4) !== 'http') { 644 | res.url = config.postsURL.slice(0, config.postsURL.lastIndexOf('/') + 1)+slug; 645 | } 646 | cancelPost('?post='+encodeURIComponent(res.url)); 647 | } 648 | ) 649 | .catch( 650 | function(err) { 651 | console.log("Could not create post!"); 652 | console.log(err); 653 | notify('error', 'Could not create post'); 654 | resetAll(); 655 | } 656 | ); 657 | }; 658 | 659 | var fetchPosts = function(url, showGrowl) { 660 | // select element holding all the posts 661 | var postsdiv = document.querySelector(config.postsElement); 662 | // clear previous posts 663 | postsdiv.innerHTML = ''; 664 | // ask only for sioc:Post resources 665 | Solid.web.get(url).then( 666 | function(g) { 667 | var _posts = []; 668 | var st = g.statementsMatching(undefined, RDF('type'), SIOC('Post')); 669 | // fallback to containment triples 670 | if (st.length === 0) { 671 | st = g.statementsMatching($rdf.sym(url), LDP('contains'), undefined); 672 | st.forEach(function(s) { 673 | _posts.push(s.object.uri); 674 | }) 675 | } else { 676 | st.forEach(function(s) { 677 | _posts.push(s.subject.uri); 678 | }); 679 | } 680 | 681 | if (_posts.length === 0) { 682 | resetAll(); 683 | hideLoading(); 684 | if (user.authenticated) { 685 | document.querySelector('.start').classList.remove('hidden'); 686 | } else { 687 | document.querySelector('.init').classList.remove('hidden'); 688 | } 689 | } 690 | 691 | var toLoad = _posts.length; 692 | var isDone = function() { 693 | if (toLoad <= 0) { 694 | hideLoading(); 695 | if (showGrowl) { 696 | growl("Updating...", "Finished updating your blog"); 697 | } 698 | } 699 | } 700 | 701 | var sortedPosts = []; 702 | _posts.forEach(function(url){ 703 | fetchPost(url).then( 704 | function(post) { 705 | if (len(post) === 0) { 706 | toLoad--; 707 | isDone(); 708 | } else { 709 | // convert post to HTML 710 | var article = postToHTML(post, true); 711 | 712 | // sort array and add to dom 713 | // TODO improve it later 714 | sortedPosts.push({date: post.created, url: post.url}); 715 | sortedPosts.sort(function(a,b) { 716 | var c = new Date(a.date); 717 | var d = new Date(b.date); 718 | return d-c; 719 | }); 720 | for(var i=0; i 0) { 754 | socketSubscribe(meta.websocket, url); 755 | } 756 | }).catch( 757 | function(err) { 758 | showError(err); 759 | } 760 | ); 761 | } 762 | ) 763 | .catch( 764 | function(err) { 765 | showError(err); 766 | } 767 | ); 768 | }; 769 | 770 | var fetchPost = function(url) { 771 | var promise = new Promise(function(resolve, reject){ 772 | Solid.web.get(url).then( 773 | function(g) { 774 | var subject = g.any(undefined, RDF('type'), SIOC('Post')); 775 | 776 | if (!subject) { 777 | subject = g.any(undefined, RDF('type'), SOLID('Notification')); 778 | } 779 | 780 | if (subject) { 781 | var post = { url: subject.uri }; 782 | 783 | // add title 784 | var title = g.any(subject, DCT('title')); 785 | if (title && title.value) { 786 | post.title = encodeHTML(title.value); 787 | } 788 | 789 | // add author 790 | var author = {}; 791 | var creator = g.any(subject, SIOC('has_creator')); 792 | if (creator) { 793 | var accountOf = g.any(creator, SIOC('account_of')); 794 | if (accountOf) { 795 | post.author = encodeHTML(accountOf.uri); 796 | author.webid = post.author; 797 | } 798 | var name = g.any(creator, FOAF('name')); 799 | if (name && name.value && name.value.length > 0) { 800 | author.name = encodeHTML(name.value); 801 | } 802 | var picture = g.any(creator, SIOC('avatar')); 803 | if (picture) { 804 | author.picture = encodeHTML(picture.uri); 805 | } 806 | } else { 807 | creator = g.any(subject, DCT('creator')); 808 | if (creator) { 809 | post.author = encodeHTML(creator.uri); 810 | } 811 | } 812 | // add to list of authors if not self 813 | if (post.author && post.author != user.webid && !authors[post.author]) { 814 | authors[post.author] = author; 815 | // save list to localStorage 816 | saveLocalAuthors(); 817 | } 818 | // update author info with fresh data 819 | if (post.author && post.author.length >0) { 820 | updateAuthorInfo(post.author, url); 821 | } 822 | 823 | // add created date 824 | var created = g.any(subject, DCT('created')); 825 | if (created) { 826 | post.created = created.value; 827 | } 828 | 829 | // add modified date 830 | var modified = g.any(subject, DCT('modified')); 831 | if (modified) { 832 | post.modified = modified.value; 833 | } else { 834 | post.modified = post.created; 835 | } 836 | 837 | // add body 838 | var body = g.any(subject, SIOC('content')); 839 | if (body) { 840 | post.body = body.value; 841 | } 842 | 843 | // add post to local list 844 | posts[post.url] = post; 845 | resolve(post); 846 | } else { 847 | resolve({}); 848 | } 849 | } 850 | ) 851 | .catch( 852 | function(err) { 853 | reject(err); 854 | } 855 | ); 856 | }); 857 | 858 | return promise; 859 | }; 860 | 861 | // update author details with more recent data 862 | // TODO add date of last update to avoid repeated fetches 863 | var updateAuthorInfo = function(webid, url) { 864 | // check if it really needs updating first 865 | if (webid == user.webid || authors[webid].updated || authors[webid].lock) { 866 | return; 867 | } 868 | authors[webid].lock = true; 869 | Solid.identity.getProfile(webid). 870 | then(function(g) { 871 | var profile = getUserProfile(webid, g); 872 | if (len(profile) > 0) { 873 | authors[webid].updated = true; 874 | authors[webid].name = profile.name; 875 | authors[webid].picture = profile.picture; 876 | // save to localStorage 877 | saveLocalAuthors(); 878 | // release lock 879 | authors[webid].lock = false; 880 | if (url && posts[url]) { 881 | var postId = document.getElementById(url); 882 | if (profile.name && postId) { 883 | postId.querySelector('.post-author').innerHTML = profile.name; 884 | postId.querySelector('.post-avatar').title = profile.name+"'s picture"; 885 | postId.querySelector('.post-avatar').alt = profile.name+"'s picture"; 886 | } 887 | if (profile.picture && postId) { 888 | postId.querySelector('.post-avatar').src = profile.picture; 889 | } 890 | } 891 | } 892 | }). 893 | catch(function(err) { 894 | console.log(err); 895 | }); 896 | }; 897 | 898 | var getAuthorByWebID = function(webid) { 899 | var name = 'Unknown'; 900 | var picture = 'img/icon-blue.svg'; 901 | if (webid && webid.length > 0) { 902 | var author = authors[webid]; 903 | if (author && author.name) { 904 | name = author.name; 905 | } 906 | if (author && author.picture) { 907 | picture = author.picture; 908 | } 909 | } 910 | return {name: name, picture: picture}; 911 | }; 912 | 913 | var postToHTML = function(post, makeLink) { 914 | // change separator:

Recent Posts

915 | if (!post) { 916 | return; 917 | } 918 | var author = getAuthorByWebID(post.author); 919 | var name = author.name; 920 | var picture = author.picture; 921 | 922 | // create main post element 923 | var article = document.createElement('article'); 924 | article.classList.add('post'); 925 | article.id = post.url; 926 | 927 | // create header 928 | var header = document.createElement('header'); 929 | header.classList.add('post-header'); 930 | // append header to article 931 | article.appendChild(header); 932 | 933 | // set avatar 934 | var avatar = document.createElement('img'); 935 | avatar.classList.add('post-avatar'); 936 | avatar.src = picture; 937 | avatar.alt = avatar.title = name+"'s picture"; 938 | // append picture to header 939 | var avatarLink = document.createElement('a'); 940 | avatarLink.href = post.author; 941 | avatarLink.setAttribute('target', '_blank'); 942 | avatarLink.appendChild(avatar); 943 | header.appendChild(avatarLink); 944 | 945 | // add meta data 946 | var meta = document.createElement('div'); 947 | meta.classList.add('post-meta'); 948 | // append meta to header 949 | header.appendChild(meta); 950 | 951 | // create meta author 952 | var metaAuthor = document.createElement('a'); 953 | metaAuthor.classList.add('post-author'); 954 | metaAuthor.href = post.author; 955 | metaAuthor.setAttribute('target', '_blank'); 956 | metaAuthor.innerHTML = name; 957 | // append meta author to meta 958 | meta.appendChild(metaAuthor); 959 | 960 | // add br 961 | meta.appendChild(document.createElement('br')); 962 | 963 | // create meta date 964 | var metaDate = document.createElement('span'); 965 | metaDate.classList.add('post-date'); 966 | metaDate.innerHTML = formatDate(post.created); 967 | // append meta date to meta 968 | meta.appendChild(metaDate); 969 | 970 | // create meta tags 971 | if (post.tags && post.tags.length > 0) { 972 | var metaTags = document.createElement('span'); 973 | metaTags.classList.add('post-tags'); 974 | metaTags.innerHTML = " under "; 975 | for (var i in post.tags) { 976 | var tag = post.tags[i]; 977 | if (tag.name && tag.name.length > 0) { 978 | var tagLink = document.createElement('a'); 979 | tagLink.classList.add('post-category'); 980 | if (tag.color) { 981 | tagLink.setAttribute('style', 'background:'+tag.color+';'); 982 | } 983 | tagLink.innerHTML = tag.name; 984 | tagLink.href = "#"; 985 | tagLink.setAttribute('onclick', 'Plume.sortTag("'+tag.name+'")'); 986 | metaTags.appendChild(tagLink); 987 | } 988 | } 989 | 990 | // append meta tag 991 | meta.appendChild(metaTags); 992 | } 993 | 994 | // create title 995 | var title = document.createElement('h1'); 996 | title.classList.add('post-title'); 997 | title.innerHTML = (post.title)?''+post.title+'':''; 998 | // append title to body 999 | header.appendChild(title); 1000 | 1001 | // create body 1002 | var section = document.createElement('section'); 1003 | section.classList.add('post-body'); 1004 | article.appendChild(section); 1005 | 1006 | var bodyText = parseMD(decodeHTML(post.body)); 1007 | 1008 | // add post body 1009 | if (makeLink) { 1010 | section.classList.add('clickable'); 1011 | section.addEventListener('click', function (event) { window.location.replace('?post='+encodeURIComponent(post.url))}); 1012 | } 1013 | section.innerHTML += bodyText; 1014 | 1015 | // add footer with action links 1016 | var footer = document.createElement('footer'); 1017 | 1018 | if (user.webid == post.author) { 1019 | // edit button 1020 | var edit = document.createElement('a'); 1021 | edit.classList.add("action-button"); 1022 | edit.href = '?edit='+encodeURIComponent(post.url); 1023 | edit.setAttribute('title', 'Edit post'); 1024 | edit.innerHTML = 'Edit postEdit'; 1025 | footer.appendChild(edit); 1026 | // delete button 1027 | var del = document.createElement('a'); 1028 | del.classList.add('action-button'); 1029 | del.classList.add('danger-text'); 1030 | del.setAttribute('onclick', 'Plume.confirmDelete(\''+post.url+'\')'); 1031 | del.innerHTML = 'Delete'; 1032 | footer.appendChild(del); 1033 | } 1034 | 1035 | // append footer to post 1036 | article.appendChild(footer); 1037 | 1038 | var sep = document.createElement('div'); 1039 | sep.classList.add('separator'); 1040 | article.appendChild(sep); 1041 | 1042 | // append article to list of posts 1043 | return article; 1044 | }; 1045 | 1046 | // fade long text in articles 1047 | // TODO fix fade after updating post 1048 | var addTextFade = function(url) { 1049 | // get element current height 1050 | var article = document.getElementById(url); 1051 | if (url && article) { 1052 | var section = article.querySelector('section'); 1053 | var height = section.offsetHeight; 1054 | // fade post contents if post is too long 1055 | if (height > 400) { 1056 | section.classList.add('less'); 1057 | var fade = document.createElement('div'); 1058 | fade.classList.add('fade-bottom'); 1059 | fade.classList.add('center-text'); 1060 | fade.innerHTML = '— '+"more —"; 1061 | article.insertBefore(fade, article.querySelector('footer')); 1062 | } 1063 | } 1064 | }; 1065 | 1066 | // Websocket 1067 | var connectToSocket = function(wss, uri) { 1068 | if (!webSockets[wss]) { 1069 | var socket = new WebSocket(wss); 1070 | socket.onopen = function(){ 1071 | this.send('sub ' + uri); 1072 | console.log("Connected to WebSocket at", wss); 1073 | } 1074 | socket.onmessage = function(msg){ 1075 | if (msg.data && msg.data.slice(0, 3) === 'pub') { 1076 | // resource updated 1077 | var res = trim(msg.data.slice(3, msg.data.length)); 1078 | console.log("Got new message: pub", res); 1079 | fetchPosts(res, true); //refetch posts and notify 1080 | } 1081 | } 1082 | socket.onclose = function() { 1083 | console.log("Websocket connection closed. Restarting..."); 1084 | connectToSocket(wss, uri); 1085 | } 1086 | webSockets[wss] = socket; 1087 | } 1088 | }; 1089 | 1090 | // Subscribe to changes to a URL 1091 | var socketSubscribe = function(wss, url) { 1092 | if (webSockets[wss]) { 1093 | webSockets[wss].send('sub '+url); 1094 | } else { 1095 | connectToSocket(wss, url); 1096 | } 1097 | }; 1098 | 1099 | // Misc/helper functions 1100 | var sortTag = function(name) { 1101 | console.log(name); 1102 | }; 1103 | 1104 | var notify = function(ntype, text, timeout) { 1105 | timeout = timeout || 1500; 1106 | var note = document.createElement('div'); 1107 | note.classList.add('note'); 1108 | note.innerHTML = text; 1109 | note.addEventListener('click', note.remove, false); 1110 | 1111 | switch (ntype) { 1112 | case 'success': 1113 | note.classList.add('success'); 1114 | break; 1115 | case 'error': 1116 | timeout = 3000; 1117 | note.classList.add('danger'); 1118 | var tip = document.createElement('small'); 1119 | tip.classList.add('small'); 1120 | tip.innerHTML = ' Tip: check console for debug information.'; 1121 | note.appendChild(tip); 1122 | break; 1123 | case 'sticky': 1124 | timeout = 0; 1125 | note.classList.add('dark'); 1126 | note.innerHTML += ' [dismiss]' 1127 | break; 1128 | default: 1129 | note.classList.add('dark'); 1130 | } 1131 | document.querySelector('body').appendChild(note); 1132 | if (timeout > 0) { 1133 | setTimeout(function() { 1134 | note.remove(); 1135 | }, timeout); 1136 | } 1137 | }; 1138 | 1139 | // Send a browser notification 1140 | var growl = function(type, body, timeout) { 1141 | var icon = 'favicon.png'; 1142 | if (!timeout) { 1143 | var timeout = 2000; 1144 | } 1145 | 1146 | // Let's check if the browser supports notifications 1147 | if (!("Notification" in window)) { 1148 | console.log("This browser does not support desktop notification"); 1149 | } 1150 | 1151 | // At last, if the user already denied any notification, and you 1152 | // want to be respectful there is no need to bother him any more. 1153 | // Let's check if the user is okay to get some notification 1154 | if (Notification.permission === "granted") { 1155 | // If it's okay let's create a notification 1156 | var notification = new Notification(type, { 1157 | dir: "auto", 1158 | lang: "", 1159 | icon: icon, 1160 | body: body, 1161 | tag: "notif" 1162 | }); 1163 | setTimeout(function() { notification.close(); }, timeout); 1164 | } 1165 | }; 1166 | // Authorize browser notifications 1167 | function authorizeNotifications() { 1168 | var status = getNotifStatus(); 1169 | // Let's check if the browser supports notifications 1170 | if (!("Notification" in window)) { 1171 | console.log("This browser does not support desktop notification"); 1172 | } 1173 | 1174 | if (status !== 'granted') { 1175 | Notification.requestPermission(function (permission) { 1176 | // Whatever the user answers, we make sure we store the information 1177 | Notification.permission = permission; 1178 | }); 1179 | } else if (status === 'granted') { 1180 | Notification.permission = 'denied'; 1181 | } 1182 | }; 1183 | // Browser notifications status 1184 | function getNotifStatus() { 1185 | // Let's check if the browser supports notifications 1186 | if (!("Notification" in window)) { 1187 | console.log("This browser does not support desktop notification"); 1188 | return undefined 1189 | } else { 1190 | return Notification.permission; 1191 | } 1192 | }; 1193 | 1194 | // Overlay 1195 | var toggleOverlay = function(elem) { 1196 | var overlay = document.querySelector(elem); 1197 | overlay.addEventListener('click', toggleOverlay); 1198 | overlay.style.visibility = (overlay.style.visibility == "visible") ? "hidden" : "visible"; 1199 | }; 1200 | 1201 | // Convert rgb() to #hex 1202 | var rgbToHex = function (color) { 1203 | color = color.replace(/\s/g,""); 1204 | var aRGB = color.match(/^rgb\((\d{1,3}[%]?),(\d{1,3}[%]?),(\d{1,3}[%]?)\)$/i); 1205 | if(aRGB) 1206 | { 1207 | color = ''; 1208 | for (var i=1; i<=3; i++) color += Math.round((aRGB[i][aRGB[i].length-1]=="%"?2.55:1)*parseInt(aRGB[i])).toString(16).replace(/^(.)$/,'0$1'); 1209 | } 1210 | else color = color.replace(/^#?([\da-f])([\da-f])([\da-f])$/i, '$1$1$2$2$3$3'); 1211 | return '#'+color; 1212 | }; 1213 | 1214 | var togglePreview = function() { 1215 | editor.togglePreview(); 1216 | var text = document.querySelector('.preview'); 1217 | text.innerHTML = (text.innerHTML=="View")?"Edit":"View"; 1218 | }; 1219 | 1220 | // check if user is among the owners list 1221 | var isOwner = function() { 1222 | if (config.owners && config.owners.indexOf(user.webid) >= 0) { 1223 | return true; 1224 | } 1225 | return false; 1226 | }; 1227 | 1228 | // formatDate 1229 | var formatDate = function(date, style) { 1230 | style = style || 'LL'; 1231 | if (moment().diff(moment(date), 'days') > 1) { 1232 | return moment(date).format(style); 1233 | } else { 1234 | return moment(date).fromNow(); 1235 | } 1236 | }; 1237 | 1238 | // sanitize strings 1239 | var trim = function (str) { 1240 | return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); 1241 | } 1242 | var makeSlug = function (str) { 1243 | // replace white spaces and multiple dashes 1244 | str = str.replace(/\s+/g, '-'). 1245 | replace(/-+/g, '-'). 1246 | replace(/^-+/, ''). 1247 | replace(/-*$/, ''). 1248 | replace(/[^A-Za-z0-9-]/g, ''). 1249 | toLowerCase(); 1250 | str += '.ttl'; 1251 | return str; 1252 | }; 1253 | 1254 | // escape HTML code 1255 | var encodeHTML = function (html) { 1256 | return html 1257 | .replace(/&/g, "&") 1258 | .replace(//g, ">") 1260 | .replace(/"/g, """) 1261 | .replace(/'/g, "'"); 1262 | }; 1263 | 1264 | var decodeHTML = function (html) { 1265 | return html 1266 | .replace(/&/g, "&") 1267 | .replace(/</g, "<") 1268 | .replace(/>/g, ">") 1269 | .replace(/"/g, "\"") 1270 | .replace(/'/g, "'"); 1271 | }; 1272 | // compute length of objects based on its keys 1273 | var len = function(obj) { 1274 | return Object.keys(obj).length; 1275 | }; 1276 | 1277 | 1278 | var setColor = function(color) { 1279 | document.querySelector('.color-picker').style.background = window.getComputedStyle(document.querySelector('.'+color), null).backgroundColor; 1280 | document.querySelector('.pure-menu-active').classList.remove('pure-menu-active'); 1281 | document.querySelector('.editor-add-tag').focus(); 1282 | }; 1283 | 1284 | var cancelPost = function(url) { 1285 | clearPendingPost(); 1286 | url = (url)?url:window.location.pathname; 1287 | window.location.replace(url); 1288 | }; 1289 | 1290 | // reset to initial view 1291 | var resetAll = function(refresh) { 1292 | document.getElementById('menu-button').classList.remove('hidden'); 1293 | if (isOwner()) { 1294 | showNewPostButton(); 1295 | } 1296 | hideLoading(); 1297 | document.querySelector('.init').classList.add('hidden'); 1298 | document.querySelector('.editor').classList.add('hidden'); 1299 | document.querySelector('.viewer').classList.add('hidden'); 1300 | document.querySelector('.viewer').innerHTML = ''; 1301 | document.querySelector('.posts').classList.remove('hidden'); 1302 | // document.querySelector('.editor-add-tag').value = ''; 1303 | if (posts && len(posts) === 0) { 1304 | if (user.authenticated) { 1305 | document.querySelector('.start').classList.remove('hidden'); 1306 | } else { 1307 | document.querySelector('.init').classList.remove('hidden'); 1308 | } 1309 | } 1310 | if (refresh) { 1311 | showBlog(config.postsURL); 1312 | } else { 1313 | window.history.pushState("", document.querySelector('title').value, window.location.pathname); 1314 | } 1315 | }; 1316 | 1317 | // login / logout buttons + new post 1318 | var showLogin = function() { 1319 | document.getElementsByClassName('login')[0].classList.remove('hidden'); 1320 | document.getElementsByClassName('logout')[0].classList.add('hidden'); 1321 | hideNewPostButton(); 1322 | }; 1323 | var hideLogin = function() { 1324 | document.getElementsByClassName('login')[0].classList.add('hidden'); 1325 | document.getElementsByClassName('logout')[0].classList.remove('hidden'); 1326 | }; 1327 | // loading animation 1328 | var hideLoading = function() { 1329 | document.querySelector('.loading').classList.add('hidden'); 1330 | } 1331 | var showLoading = function() { 1332 | document.querySelector('.loading').classList.remove('hidden'); 1333 | } 1334 | // new post button 1335 | var hideNewPostButton = function() { 1336 | document.querySelector('.new').classList.add('hidden'); 1337 | }; 1338 | var showNewPostButton = function() { 1339 | document.querySelector('.new').classList.remove('hidden'); 1340 | }; 1341 | 1342 | // save pending post text to localStorage 1343 | var savePendingPost = function(text) { 1344 | var post = {}; 1345 | post.title = trim(document.querySelector('.editor-title').value); 1346 | post.body = text; 1347 | try { 1348 | localStorage.setItem(appURL+'pendingPost', JSON.stringify(post)); 1349 | } catch(err) { 1350 | console.log(err); 1351 | } 1352 | 1353 | }; 1354 | // load pending post text from localStorage 1355 | var loadPendingPost = function() { 1356 | try { 1357 | return JSON.parse(localStorage.getItem(appURL+'pendingPost')); 1358 | } catch(err) { 1359 | console.log(err); 1360 | } 1361 | }; 1362 | var clearPendingPost = function() { 1363 | setBodyValue(''); 1364 | try { 1365 | localStorage.removeItem(appURL+'pendingPost'); 1366 | } catch(err) { 1367 | console.log(err); 1368 | } 1369 | } 1370 | 1371 | // save authors to localStorage 1372 | var saveLocalAuthors = function() { 1373 | try { 1374 | localStorage.setItem(appURL+'authors', JSON.stringify(authors)); 1375 | } catch(err) { 1376 | console.log(err); 1377 | } 1378 | }; 1379 | // clear localstorage authors data 1380 | var clearLocalAuthors = function() { 1381 | try { 1382 | localStorage.removeItem(appURL+'authors'); 1383 | } catch(err) { 1384 | console.log(err); 1385 | } 1386 | }; 1387 | // clear localstorage config data 1388 | var loadLocalAuthors = function() { 1389 | try { 1390 | var data = JSON.parse(localStorage.getItem(appURL+'authors')); 1391 | if (data) { 1392 | authors = data; 1393 | } 1394 | } catch(err) { 1395 | console.log(err); 1396 | } 1397 | }; 1398 | 1399 | // save config data to localStorage 1400 | var saveLocalStorage = function() { 1401 | var data = { 1402 | user: user, 1403 | config: config 1404 | }; 1405 | try { 1406 | localStorage.setItem(appURL, JSON.stringify(data)); 1407 | } catch(err) { 1408 | console.log(err); 1409 | } 1410 | }; 1411 | // clear localstorage config data 1412 | var clearLocalStorage = function() { 1413 | try { 1414 | localStorage.removeItem(appURL); 1415 | } catch(err) { 1416 | console.log(err); 1417 | } 1418 | }; 1419 | var loadLocalStorage = function() { 1420 | try { 1421 | var data = JSON.parse(localStorage.getItem(appURL)); 1422 | if (data) { 1423 | // don't let session data become stale (24h validity) 1424 | var dateValid = data.config.saveDate + 1000 * 60 * 60 * 24; 1425 | if (Date.now() < dateValid) { 1426 | config = data.config; 1427 | user = data.user; 1428 | if (user.authenticated) { 1429 | hideLogin(); 1430 | } 1431 | if (isOwner()) { 1432 | showNewPostButton(); 1433 | } 1434 | } else { 1435 | console.log("Deleting localStorage data because it expired"); 1436 | localStorage.removeItem(appURL); 1437 | } 1438 | } else { 1439 | // clear sessionStorage in case there was a change to the data structure 1440 | localStorage.removeItem(appURL); 1441 | } 1442 | } catch(err) { 1443 | notify('sticky', 'Persistence functionality is disabled while cookies are disabled.'); 1444 | console.log(err); 1445 | } 1446 | }; 1447 | 1448 | 1449 | 1450 | // ----- INIT ----- 1451 | // start app by loading the config file 1452 | applyConfig(); 1453 | var http = new XMLHttpRequest(); 1454 | http.open('get', 'config.json'); 1455 | http.onreadystatechange = function() { 1456 | if (this.readyState == this.DONE) { 1457 | init(JSON.parse(this.response)); 1458 | } 1459 | }; 1460 | http.send(); 1461 | 1462 | 1463 | 1464 | // return public functions 1465 | return { 1466 | notify: notify, 1467 | user: user, 1468 | posts: posts, 1469 | login: login, 1470 | logout: logout, 1471 | signup: signup, 1472 | resetAll: resetAll, 1473 | cancelPost: cancelPost, 1474 | showEditor: showEditor, 1475 | showViewer: showViewer, 1476 | setColor: setColor, 1477 | publishPost: publishPost, 1478 | confirmDelete: confirmDelete, 1479 | cancelDelete: cancelDelete, 1480 | deletePost: deletePost, 1481 | togglePreview: togglePreview, 1482 | toggleOverlay: toggleOverlay, 1483 | growl: growl 1484 | }; 1485 | }(this)); 1486 | 1487 | 1488 | Plume.menu = (function() { 1489 | var ESCAPE_CODE = 27; 1490 | 1491 | var navButton = document.getElementById('menu-button'), 1492 | navMenu = document.getElementById('global-nav'), 1493 | mainDiv = document.getElementById('main'); 1494 | 1495 | var navLinks = navMenu.getElementsByTagName('a'); 1496 | 1497 | function handleKeydown(event) { 1498 | event.preventDefault(); 1499 | if (event.keyCode === ESCAPE_CODE) { 1500 | document.body.classList.toggle('active'); 1501 | disableNavLinks(); 1502 | navButton.focus(); 1503 | } 1504 | }; 1505 | function handleClick(event) { 1506 | event.preventDefault(); 1507 | if (document.body.classList.contains('active')) { 1508 | document.body.classList.remove('active'); 1509 | disableNavLinks(); 1510 | } 1511 | else { 1512 | document.body.classList.add('active'); 1513 | enableNavLinks(); 1514 | navLinks[0].focus(); 1515 | } 1516 | }; 1517 | function forceClose(event) { 1518 | if (document.body.classList.contains('active')) { 1519 | document.body.classList.remove('active'); 1520 | disableNavLinks(); 1521 | } 1522 | }; 1523 | function enableNavLinks() { 1524 | navButton.removeAttribute('aria-label', 'Menu expanded'); 1525 | navMenu.removeAttribute('aria-hidden'); 1526 | for (var i=0; i