servel 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,18 +1,18 @@
1
- !!!
2
- %html
3
- %head
4
- %meta{charset: 'utf-8'}
5
- %title Browse Listings
6
- %meta{name: 'viewport', content: 'width=device-width, height=device-height, user-scalable=no'}
7
- :css
8
- #{include('css/normalize.css')}
9
- #{include('css/common.css')}
10
- #{include('css/home.css')}
11
- %body
12
- #home
13
- %h1 Browse Listings
14
- %ul#roots
15
- - roots.each do |root|
16
- %li
17
- %a{href: root}= root
18
- %a.new-tab{href: root, target: "_blank"} (New Tab)
1
+ !!!
2
+ %html
3
+ %head
4
+ %meta{charset: 'utf-8'}
5
+ %title Browse Listings
6
+ %meta{name: 'viewport', content: 'width=device-width, height=device-height, user-scalable=no'}
7
+ :css
8
+ #{include('css/normalize.css')}
9
+ #{include('css/common.css')}
10
+ #{include('css/home.css')}
11
+ %body
12
+ #home
13
+ %h1 Browse Listings
14
+ %ul#roots
15
+ - roots.each do |root|
16
+ %li
17
+ %a{href: root}= root
18
+ %a.new-tab{href: root, target: "_blank"} (New Tab)
@@ -1,21 +1,23 @@
1
- !!!
2
- %html
3
- %head
4
- %meta{charset: 'utf-8'}
5
- %title Listing of #{url_root}#{url_path}
6
- %meta{name: 'viewport', content: 'width=device-width, height=device-height, user-scalable=no'}
7
- :css
8
- #{include('css/normalize.css')}
9
- #{include('css/common.css')}
10
- #{include('css/index.css')}
11
- #{include('css/listing.css')}
12
- #{include('css/gallery.css')}
13
- #{include('css/gallery-text.css')}
14
-
15
- :javascript
16
- #{include('js/ume.js')}
17
- #{include('js/gallery.js')}
18
- %body
19
- - if files.any? { |f| f.media? }
20
- #gallery!= partial('gallery')
21
- #listing!= partial('listing', { url_root: url_root, url_path: url_path, directories: directories, files: files })
1
+ !!!
2
+ %html
3
+ %head
4
+ %meta{charset: 'utf-8'}
5
+ %title Listing of #{url_root}#{url_path}
6
+ %meta{name: 'viewport', content: 'width=device-width, height=device-height, user-scalable=no'}
7
+ :css
8
+ #{include('css/normalize.css')}
9
+ #{include('css/common.css')}
10
+ #{include('css/index.css')}
11
+ #{include('css/listing.css')}
12
+ #{include('css/gallery.css')}
13
+ #{include('css/gallery-text.css')}
14
+
15
+ :javascript
16
+ #{include('js/url-search-params.js')}
17
+ #{include('js/listing.js')}
18
+ #{include('js/ume.js')}
19
+ #{include('js/gallery.js')}
20
+ %body
21
+ - if files.any? { |f| f.media? }
22
+ #gallery!= partial('gallery')
23
+ #listing!= partial('listing', { url_root: url_root, url_path: url_path, directories: directories, files: files, sort: sort })
@@ -1,9 +1,11 @@
1
1
  var $;
2
2
 
3
3
  var Gallery = (function() {
4
+ var TYPES = ["image", "video", "audio", "text"];
4
5
  var urls = [];
5
6
  var types = [];
6
7
  var currentIndex = 0;
8
+ var $gallery;
7
9
 
8
10
  function initItems() {
9
11
  var links = document.querySelectorAll("#listing a.default.media");
@@ -26,12 +28,27 @@ var Gallery = (function() {
26
28
  http.send();
27
29
  }
28
30
 
31
+ function clearContent() {
32
+ for(var i = 0; i < TYPES.length; i++) {
33
+ var type = TYPES[i];
34
+
35
+ $gallery.classList.remove(type);
36
+
37
+ if(type == "text") {
38
+ $("#text-content").innerHTML = "";
39
+ }
40
+ else {
41
+ $("#" + type).src = "about:none";
42
+ }
43
+ }
44
+ }
45
+
29
46
  function render() {
47
+ clearContent();
48
+
30
49
  var url = urls[currentIndex];
31
50
  var type = types[currentIndex];
32
51
 
33
- var $gallery = $("#gallery");
34
- $gallery.classList.remove("image", "video", "audio", "text");
35
52
  $gallery.classList.add(type);
36
53
 
37
54
  if(type == "text") {
@@ -129,6 +146,8 @@ var Gallery = (function() {
129
146
  }
130
147
 
131
148
  function init() {
149
+ $gallery = $("#gallery");
150
+
132
151
  initItems();
133
152
  initEvents();
134
153
  render();
@@ -0,0 +1,26 @@
1
+ function initListing() {
2
+ $ = document.querySelector.bind(document);
3
+
4
+ function applySort(sortable) {
5
+ var params = new URLSearchParams(location.search.slice(1));
6
+ params.set("_servel_sort_method", sortable.dataset.sortMethod);
7
+ params.set("_servel_sort_direction", sortable.dataset.sortDirection);
8
+
9
+ if('sortActive' in sortable.dataset) {
10
+ params.set("_servel_sort_direction", sortable.dataset.sortDirection == "asc" ? "desc" : "asc");
11
+ }
12
+
13
+ location.href = location.pathname + "?" + params.toString();
14
+ }
15
+
16
+ document.body.addEventListener("click", function(e) {
17
+ if(!e.target) return;
18
+
19
+ if(e.target.closest("th.sortable")) {
20
+ e.preventDefault();
21
+ applySort(e.target.closest("th.sortable"));
22
+ }
23
+ });
24
+ }
25
+
26
+ window.addEventListener("DOMContentLoaded", initListing);
@@ -1,63 +1,63 @@
1
- var ume = (function() {
2
- function normalise(text) {
3
- return text.replace(/\s+/g, " ").trim();
4
- }
5
-
6
- function escapeEntities(text) {
7
- return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
8
- }
9
-
10
- const BOLD_ITALIC_REGEX = /(?:(\W|^)(\*)|(\*)(\W|$)|(\W|^)(_)|(_)(\W|$))/;
11
-
12
- function parseInlines(text) {
13
- const parts = text.split(BOLD_ITALIC_REGEX);
14
-
15
- if(parts.filter(function(part) { return part == "*"; }).length % 2 != 0) return text;
16
- if(parts.filter(function(part) { return part == "_"; }).length % 2 != 0) return text;
17
-
18
- var inBold = false;
19
- var inItalic = false;
20
- var html = [];
21
-
22
- for(const part of parts) {
23
- if(part == "*") {
24
- inBold = !inBold;
25
- html.push(inBold ? "<b>" : "</b>"); //Note that in_bold has been inverted, so this is inverted as well
26
- }
27
- else if(part == "_") {
28
- inItalic = !inItalic;
29
- html.push(inItalic ? "<i>" : "</i>"); //Note that in_italic has been inverted, so this is inverted as well
30
- }
31
- else {
32
- html.push(part);
33
- }
34
- }
35
-
36
- return html.join("");
37
- }
38
-
39
- function parseHeading(text) {
40
- const parts = text.match(/^(#+) (.*)$/);
41
- return "<h" + parts[1].length + ">" + parseInlines(parts[2]) + "</h" + parts[1].length + ">";
42
- }
43
-
44
- function parseParagraph(text) {
45
- return "<p>" + parseInlines(text) + "</p>";
46
- }
47
-
48
- return function(text) {
49
- const nodes = text.split(/(\r?\n){2,}/g);
50
- var html = [];
51
-
52
- for(const node of nodes) {
53
- const cleanedNode = escapeEntities(normalise(node));
54
-
55
- if(cleanedNode.startsWith("#")) html.push(parseHeading(cleanedNode));
56
- else html.push(parseParagraph(cleanedNode));
57
- }
58
-
59
- return html.join("");
60
- }
61
- })();
62
-
63
- if(typeof module === "object" && typeof module.exports === "object") module.exports = ume;
1
+ var ume = (function() {
2
+ function normalise(text) {
3
+ return text.replace(/\s+/g, " ").trim();
4
+ }
5
+
6
+ function escapeEntities(text) {
7
+ return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
8
+ }
9
+
10
+ const BOLD_ITALIC_REGEX = /(?:(\W|^)(\*)|(\*)(\W|$)|(\W|^)(_)|(_)(\W|$))/;
11
+
12
+ function parseInlines(text) {
13
+ const parts = text.split(BOLD_ITALIC_REGEX);
14
+
15
+ if(parts.filter(function(part) { return part == "*"; }).length % 2 != 0) return text;
16
+ if(parts.filter(function(part) { return part == "_"; }).length % 2 != 0) return text;
17
+
18
+ var inBold = false;
19
+ var inItalic = false;
20
+ var html = [];
21
+
22
+ for(const part of parts) {
23
+ if(part == "*") {
24
+ inBold = !inBold;
25
+ html.push(inBold ? "<b>" : "</b>"); //Note that in_bold has been inverted, so this is inverted as well
26
+ }
27
+ else if(part == "_") {
28
+ inItalic = !inItalic;
29
+ html.push(inItalic ? "<i>" : "</i>"); //Note that in_italic has been inverted, so this is inverted as well
30
+ }
31
+ else {
32
+ html.push(part);
33
+ }
34
+ }
35
+
36
+ return html.join("");
37
+ }
38
+
39
+ function parseHeading(text) {
40
+ const parts = text.match(/^(#+) (.*)$/);
41
+ return "<h" + parts[1].length + ">" + parseInlines(parts[2]) + "</h" + parts[1].length + ">";
42
+ }
43
+
44
+ function parseParagraph(text) {
45
+ return "<p>" + parseInlines(text) + "</p>";
46
+ }
47
+
48
+ return function(text) {
49
+ const nodes = text.split(/(\r?\n){2,}/g);
50
+ var html = [];
51
+
52
+ for(const node of nodes) {
53
+ const cleanedNode = escapeEntities(normalise(node));
54
+
55
+ if(cleanedNode.startsWith("#")) html.push(parseHeading(cleanedNode));
56
+ else html.push(parseParagraph(cleanedNode));
57
+ }
58
+
59
+ return html.join("");
60
+ }
61
+ })();
62
+
63
+ if(typeof module === "object" && typeof module.exports === "object") module.exports = ume;
@@ -0,0 +1,2 @@
1
+ /*! (C) Andrea Giammarchi - Mit Style License */
2
+ var URLSearchParams=URLSearchParams||function(){"use strict";function URLSearchParams(query){var index,key,value,pairs,i,length,dict=Object.create(null);this[secret]=dict;if(!query)return;if(typeof query==="string"){if(query.charAt(0)==="?"){query=query.slice(1)}for(pairs=query.split("&"),i=0,length=pairs.length;i<length;i++){value=pairs[i];index=value.indexOf("=");if(-1<index){appendTo(dict,decode(value.slice(0,index)),decode(value.slice(index+1)))}else if(value.length){appendTo(dict,decode(value),"")}}}else{if(isArray(query)){for(i=0,length=query.length;i<length;i++){value=query[i];appendTo(dict,value[0],value[1])}}else{for(key in query){appendTo(dict,key,query[key])}}}}var isArray=Array.isArray,URLSearchParamsProto=URLSearchParams.prototype,find=/[!'\(\)~]|%20|%00/g,plus=/\+/g,replace={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+","%00":"\0"},replacer=function(match){return replace[match]},secret="__URLSearchParams__:"+Math.random();function appendTo(dict,name,value){if(name in dict){dict[name].push(""+value)}else{dict[name]=isArray(value)?value:[""+value]}}function decode(str){return decodeURIComponent(str.replace(plus," "))}function encode(str){return encodeURIComponent(str).replace(find,replacer)}URLSearchParamsProto.append=function append(name,value){appendTo(this[secret],name,value)};URLSearchParamsProto["delete"]=function del(name){delete this[secret][name]};URLSearchParamsProto.get=function get(name){var dict=this[secret];return name in dict?dict[name][0]:null};URLSearchParamsProto.getAll=function getAll(name){var dict=this[secret];return name in dict?dict[name].slice(0):[]};URLSearchParamsProto.has=function has(name){return name in this[secret]};URLSearchParamsProto.set=function set(name,value){this[secret][name]=[""+value]};URLSearchParamsProto.forEach=function forEach(callback,thisArg){var dict=this[secret];Object.getOwnPropertyNames(dict).forEach(function(name){dict[name].forEach(function(value){callback.call(thisArg,value,name,this)},this)},this)};URLSearchParamsProto.toJSON=function toJSON(){return{}};URLSearchParamsProto.toString=function toString(){var dict=this[secret],query=[],i,key,name,value;for(key in dict){name=encode(key);for(i=0,value=dict[key];i<value.length;i++){query.push(name+"="+encode(value[i]))}}return query.join("&")};var dP=Object.defineProperty,gOPD=Object.getOwnPropertyDescriptor,createSearchParamsPollute=function(search){function append(name,value){URLSearchParamsProto.append.call(this,name,value);name=this.toString();search.set.call(this._usp,name?"?"+name:"")}function del(name){URLSearchParamsProto["delete"].call(this,name);name=this.toString();search.set.call(this._usp,name?"?"+name:"")}function set(name,value){URLSearchParamsProto.set.call(this,name,value);name=this.toString();search.set.call(this._usp,name?"?"+name:"")}return function(sp,value){sp.append=append;sp["delete"]=del;sp.set=set;return dP(sp,"_usp",{configurable:true,writable:true,value:value})}},createSearchParamsCreate=function(polluteSearchParams){return function(obj,sp){dP(obj,"_searchParams",{configurable:true,writable:true,value:polluteSearchParams(sp,obj)});return sp}},updateSearchParams=function(sp){var append=sp.append;sp.append=URLSearchParamsProto.append;URLSearchParams.call(sp,sp._usp.search.slice(1));sp.append=append},verifySearchParams=function(obj,Class){if(!(obj instanceof Class))throw new TypeError("'searchParams' accessed on an object that "+"does not implement interface "+Class.name)},upgradeClass=function(Class){var ClassProto=Class.prototype,searchParams=gOPD(ClassProto,"searchParams"),href=gOPD(ClassProto,"href"),search=gOPD(ClassProto,"search"),createSearchParams;if(!searchParams&&search&&search.set){createSearchParams=createSearchParamsCreate(createSearchParamsPollute(search));Object.defineProperties(ClassProto,{href:{get:function(){return href.get.call(this)},set:function(value){var sp=this._searchParams;href.set.call(this,value);if(sp)updateSearchParams(sp)}},search:{get:function(){return search.get.call(this)},set:function(value){var sp=this._searchParams;search.set.call(this,value);if(sp)updateSearchParams(sp)}},searchParams:{get:function(){verifySearchParams(this,Class);return this._searchParams||createSearchParams(this,new URLSearchParams(this.search.slice(1)))},set:function(sp){verifySearchParams(this,Class);createSearchParams(this,sp)}}})}};upgradeClass(HTMLAnchorElement);if(/^function|object$/.test(typeof URL)&&URL.prototype)upgradeClass(URL);return URLSearchParams}();(function(URLSearchParamsProto){var iterable=function(){try{return!!Symbol.iterator}catch(error){return false}}();if(!("forEach"in URLSearchParamsProto)){URLSearchParamsProto.forEach=function forEach(callback,thisArg){var names=Object.create(null);this.toString().replace(/=[\s\S]*?(?:&|$)/g,"=").split("=").forEach(function(name){if(!name.length||name in names)return;(names[name]=this.getAll(name)).forEach(function(value){callback.call(thisArg,value,name,this)},this)},this)}}if(!("keys"in URLSearchParamsProto)){URLSearchParamsProto.keys=function keys(){var items=[];this.forEach(function(value,name){items.push(name)});var iterator={next:function(){var value=items.shift();return{done:value===undefined,value:value}}};if(iterable){iterator[Symbol.iterator]=function(){return iterator}}return iterator}}if(!("values"in URLSearchParamsProto)){URLSearchParamsProto.values=function values(){var items=[];this.forEach(function(value){items.push(value)});var iterator={next:function(){var value=items.shift();return{done:value===undefined,value:value}}};if(iterable){iterator[Symbol.iterator]=function(){return iterator}}return iterator}}if(!("entries"in URLSearchParamsProto)){URLSearchParamsProto.entries=function entries(){var items=[];this.forEach(function(value,name){items.push([name,value])});var iterator={next:function(){var value=items.shift();return{done:value===undefined,value:value}}};if(iterable){iterator[Symbol.iterator]=function(){return iterator}}return iterator}}if(iterable&&!(Symbol.iterator in URLSearchParamsProto)){URLSearchParamsProto[Symbol.iterator]=URLSearchParamsProto.entries}if(!("sort"in URLSearchParamsProto)){URLSearchParamsProto.sort=function sort(){var entries=this.entries(),entry=entries.next(),done=entry.done,keys=[],values=Object.create(null),i,key,value;while(!done){value=entry.value;key=value[0];keys.push(key);if(!(key in values)){values[key]=[]}values[key].push(value[1]);entry=entries.next();done=entry.done}keys.sort();for(i=0;i<keys.length;i++){this["delete"](keys[i])}for(i=0;i<keys.length;i++){key=keys[i];this.append(key,values[key].shift())}}}})(URLSearchParams.prototype);
@@ -1,3 +1,3 @@
1
1
  module Servel
2
- VERSION = "0.11.0"
2
+ VERSION = "0.12.0"
3
3
  end
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.add_dependency "rack", "~> 2.0"
27
27
  spec.add_dependency "puma"
28
28
  spec.add_dependency "naturalsorter"
29
- spec.add_dependency "haml", "~> 4"
29
+ spec.add_dependency "hamlit"
30
30
  spec.add_dependency "activesupport"
31
+ spec.add_dependency "lru_redux"
31
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brenton "B-Train" Fletcher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-19 00:00:00.000000000 Z
11
+ date: 2018-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,19 +81,19 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: haml
84
+ name: hamlit
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '4'
89
+ version: '0'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '4'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: activesupport
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: lru_redux
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Serves files and directories over HTTP.
112
126
  email:
113
127
  - i@bloople.net
@@ -132,6 +146,7 @@ files:
132
146
  - lib/servel/haml_context.rb
133
147
  - lib/servel/home_app.rb
134
148
  - lib/servel/index.rb
149
+ - lib/servel/instrumentation.rb
135
150
  - lib/servel/templates/_gallery.haml
136
151
  - lib/servel/templates/_listing.haml
137
152
  - lib/servel/templates/css/common.css
@@ -144,7 +159,9 @@ files:
144
159
  - lib/servel/templates/home.haml
145
160
  - lib/servel/templates/index.haml
146
161
  - lib/servel/templates/js/gallery.js
162
+ - lib/servel/templates/js/listing.js
147
163
  - lib/servel/templates/js/ume.js
164
+ - lib/servel/templates/js/url-search-params.js
148
165
  - lib/servel/version.rb
149
166
  - servel.gemspec
150
167
  homepage: http://bloople.net/