servel 0.20.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2763001e5065c946d727b67fdf97e42a888d6794159528c72b2f15c7492c3409
4
- data.tar.gz: d44b73a268aa7e69ea9b431ade3700a311b37906614fd8601effafc09473b2f4
3
+ metadata.gz: 2fa8d88495eaaf272edc23d6f8ee35358cdbf85e11339fc46f786cbead036ff9
4
+ data.tar.gz: dc9d48be2ce10ec35ebe1918f96985cef584bb2871ffaffebbb61ef2ea80a659
5
5
  SHA512:
6
- metadata.gz: ea0615e5c1661f40afd3ebf639e6d751db50989506fec1434c81f72ca3aaa3107c0eb5a8aa5f40e899e7d94ca62c99332e0998389c4a23296c910f8dd2c43750
7
- data.tar.gz: 0071e811b8c7c5a401b5a060c297a686616e311a9bd6726a4e4bd5d6ed6626ebf25cd193ea2202dbeaff9a9ca851bfc4f19de73ad819a5245e33c196cb0c3ede
6
+ metadata.gz: c06b97acc7830e90bda35051313097cf3c414f1f3f4b15e6c2ec1af4be0cc6e665ce9480ace68a20827ad8d140396f9b34630061daa929f289d0c4027f3d2997
7
+ data.tar.gz: 8d0d2d034cf124464ceb421c110e01750341b9e5aa2bd009963e0bb1ec6262fe8bd24edc97b7bcb4bafaf6b0466879f65caadade8feee8b7a9663f400cb01352
File without changes
File without changes
@@ -23,18 +23,3 @@ a {
23
23
  a:hover, a:focus, a:active {
24
24
  text-decoration: underline;
25
25
  }
26
-
27
- #loading {
28
- display: flex;
29
- align-items: center;
30
- justify-content: center;
31
- position: fixed;
32
- top: 0;
33
- right: 0;
34
- bottom: 0;
35
- left: 0;
36
- z-index: 2;
37
- background-color: rgba(255, 255, 255, 0.6);
38
- font-size: 24px;
39
- font-weight: bold;
40
- }
File without changes
File without changes
File without changes
@@ -1,5 +1,4 @@
1
1
  #listing {
2
- display: none;
3
2
  padding: 10px;
4
3
  position: relative;
5
4
  z-index: 1;
File without changes
File without changes
@@ -4,6 +4,12 @@
4
4
  %meta{charset: 'utf-8'}
5
5
  %title Listing of #{url_root}#{url_path}
6
6
  %meta{name: 'viewport', content: 'width=device-width, height=device-height, user-scalable=no'}
7
+
8
+ :javascript
9
+ window.specialEntries = #{special_entries};
10
+ window.directoryEntries = #{directory_entries};
11
+ window.fileEntries = #{file_entries};
12
+
7
13
  :css
8
14
  #{include('css/normalize.css')}
9
15
  #{include('css/common.css')}
@@ -12,11 +18,11 @@
12
18
  #{include('css/gallery-text.css')}
13
19
 
14
20
  :javascript
21
+ #{include('js/natural-orderby.min.js')}
22
+ #{include('js/entries.js')}
15
23
  #{include('js/listing.js')}
16
24
  #{include('js/ume.js')}
17
25
  #{include('js/gallery.js')}
18
- #{include('js/index.js')}
19
26
  %body
20
27
  #gallery!= partial('gallery')
21
- #listing!= partial('listing', { url_root: url_root, url_path: url_path })
22
- #loading Loading...
28
+ #listing!= partial('listing', { url_root: url_root, url_path: url_path })
data/app/js/entries.js ADDED
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+
3
+ var Entries = (function() {
4
+ //Lists
5
+ var all;
6
+ var media;
7
+ var hasMedia;
8
+
9
+ var sortMethod = "name";
10
+ var sortDirection = "asc";
11
+ var filterText = "";
12
+
13
+ function runFilter(entries) {
14
+ if(filterText == "") return entries;
15
+
16
+ var filteredEntries = [];
17
+
18
+ for(var i = 0; i < entries.length; i++) {
19
+ var entry = entries[i];
20
+ if(entry.name.toLowerCase().includes(filterText.toLowerCase())) filteredEntries.push(entry);
21
+ }
22
+
23
+ return filteredEntries;
24
+ }
25
+
26
+ function sortByName(entries) {
27
+ return naturalOrderBy.orderBy(entries, function(entry) {
28
+ return entry.name.toLowerCase();
29
+ }, sortDirection);
30
+ }
31
+
32
+ function sortByMtime(a, b) {
33
+ return b.mtime - a.mtime;
34
+ }
35
+
36
+ function sortBySize(a, b) {
37
+ return b.size - a.size;
38
+ }
39
+
40
+ function sortByType(a, b) {
41
+ var aType = a.type.toLowerCase();
42
+ var bType = b.type.toLowerCase();
43
+
44
+ if(aType < bType) return -1;
45
+ if(aType > bType) return 1;
46
+
47
+ return 0;
48
+ }
49
+
50
+ function runSort(entries) {
51
+ if(sortMethod == "name") return sortByName(entries);
52
+
53
+ var sortFunction;
54
+ if(sortMethod == "mtime") sortFunction = sortByMtime;
55
+ else if(sortMethod == "size") sortFunction = sortBySize;
56
+ else if(sortMethod == "type") sortFunction = sortByType;
57
+
58
+ entries.sort(sortFunction);
59
+ if(sortDirection == "desc") entries.reverse();
60
+
61
+ return entries;
62
+ }
63
+
64
+ function updateLists() {
65
+ specialEntries = window.specialEntries.slice();
66
+ directoryEntries = runSort(runFilter(window.directoryEntries.slice()));
67
+ fileEntries = runSort(runFilter(window.fileEntries.slice()));
68
+
69
+ all = [].concat(specialEntries, directoryEntries, fileEntries);
70
+
71
+ media = [];
72
+ for(var i = 0; i < fileEntries.length; i++) {
73
+ if(fileEntries[i].media) media.push(fileEntries[i]);
74
+ }
75
+
76
+ hasMedia = media.length > 0;
77
+ }
78
+
79
+ function update() {
80
+ updateLists();
81
+ Gallery.onEntriesUpdate();
82
+ Listing.onEntriesUpdate();
83
+ }
84
+
85
+ function sort(newSortMethod, newSortDirection) {
86
+ sortMethod = newSortMethod;
87
+ sortDirection = newSortDirection;
88
+ update();
89
+ }
90
+
91
+ function filter(newFilterText) {
92
+ filterText = newFilterText;
93
+ update();
94
+ }
95
+
96
+ updateLists();
97
+
98
+ return {
99
+ all: function() {
100
+ return all;
101
+ },
102
+ media: function() {
103
+ return media;
104
+ },
105
+ hasMedia: function() {
106
+ return hasMedia;
107
+ },
108
+ filter: filter,
109
+ sort: sort
110
+ };
111
+ })();
@@ -3,8 +3,7 @@
3
3
  var Gallery = (function() {
4
4
  var $;
5
5
  var $gallery;
6
- var mediaEntries = [];
7
- var currentIndex = 0;
6
+ var currentIndex;
8
7
  var layoutItemMax = false;
9
8
 
10
9
  function renderText(url) {
@@ -29,10 +28,10 @@ var Gallery = (function() {
29
28
  function render() {
30
29
  clearContent();
31
30
 
32
- var entry = mediaEntries[currentIndex];
31
+ var entry = Entries.media()[currentIndex];
33
32
 
34
33
  var url = entry.href;
35
- var type = entry.media_type;
34
+ var type = entry.mediaType;
36
35
 
37
36
  $gallery.classList.add(type);
38
37
 
@@ -52,7 +51,7 @@ var Gallery = (function() {
52
51
 
53
52
  function clamp(index) {
54
53
  if(index == null || isNaN(index) || index < 0) return 0;
55
- if(index >= mediaEntries.length) return mediaEntries.length - 1;
54
+ if(index >= Entries.media().length) return Entries.media().length - 1;
56
55
  return index;
57
56
  }
58
57
 
@@ -81,7 +80,7 @@ var Gallery = (function() {
81
80
  }
82
81
 
83
82
  function jump(url) {
84
- var index = mediaEntries.findIndex(function(entry) {
83
+ var index = Entries.media().findIndex(function(entry) {
85
84
  return entry.href == url;
86
85
  });
87
86
  go(index);
@@ -156,10 +155,18 @@ var Gallery = (function() {
156
155
  layout();
157
156
  }
158
157
 
159
- function onEntriesInit() {
158
+ function onEntriesUpdate() {
159
+ currentIndex = 0;
160
+ if(Entries.hasMedia()) render();
161
+ }
162
+
163
+ function init() {
164
+ $ = document.querySelector.bind(document);
165
+ $gallery = $("#gallery");
166
+
160
167
  onEntriesUpdate();
161
168
 
162
- if(mediaEntries.length > 0) {
169
+ if(Entries.hasMedia()) {
163
170
  $gallery.style.display = "flex";
164
171
 
165
172
  initEvents();
@@ -167,23 +174,8 @@ var Gallery = (function() {
167
174
  }
168
175
  }
169
176
 
170
- function onEntriesUpdate() {
171
- currentIndex = 0;
172
- mediaEntries = [];
173
- for(var i = 0; i < window.entries.length; i++) {
174
- if(window.entries[i].media) mediaEntries.push(window.entries[i]);
175
- }
176
-
177
- if(mediaEntries.length > 0) render();
178
- }
179
-
180
- window.addEventListener("DOMContentLoaded", function() {
181
- $ = document.querySelector.bind(document);
182
- $gallery = $("#gallery");
183
- });
184
-
185
177
  return {
186
- onEntriesInit: onEntriesInit,
178
+ init: init,
187
179
  onEntriesUpdate: onEntriesUpdate,
188
180
  go: go,
189
181
  prev: prev,
@@ -193,3 +185,5 @@ var Gallery = (function() {
193
185
  jump: jump
194
186
  };
195
187
  })();
188
+
189
+ window.addEventListener("DOMContentLoaded", Gallery.init);
@@ -3,10 +3,9 @@
3
3
  var Listing = (function() {
4
4
  var $;
5
5
  var $container;
6
- var filteredEntries = [];
7
6
  var perPage = 99;
8
- var currentIndex = 0;
9
- var moreContent = true;
7
+ var currentIndex;
8
+ var moreContent;
10
9
  var scrollDebounce = false;
11
10
 
12
11
  function escapeHTML(unsafe) {
@@ -31,14 +30,14 @@ var Listing = (function() {
31
30
  <tr>
32
31
  <td class="name">
33
32
  <span class="icon">${file.icon}</span>
34
- <a href="${file.href}" class="default ${file.class}" data-url="${file.href}" data-type="${file.media_type}">${file.name}</a>
33
+ <a href="${file.href}" class="default ${file.class}" data-url="${file.href}" data-type="${file.mediaType}">${file.name}</a>
35
34
  </td>
36
35
  <td class="new-tab">
37
36
  <a href="${file.href}" class="new-tab ${file.class}" target="_blank">(New tab)</a>
38
37
  </td>
39
38
  <td class="type">${file.type}</td>
40
- <td class="size">${file.size}</td>
41
- <td class="modified">${file.mtime}</td>
39
+ <td class="size">${file.sizeText}</td>
40
+ <td class="modified">${file.mtimeText}</td>
42
41
  </tr>
43
42
  `;
44
43
  }
@@ -58,7 +57,7 @@ var Listing = (function() {
58
57
  }
59
58
 
60
59
  function render() {
61
- var currentEntries = filteredEntries.slice(currentIndex, currentIndex + perPage);
60
+ var currentEntries = Entries.all().slice(currentIndex, currentIndex + perPage);
62
61
  $container.insertAdjacentHTML("beforeend", renderTable(currentEntries));
63
62
  }
64
63
 
@@ -69,7 +68,7 @@ var Listing = (function() {
69
68
  function onScrolled() {
70
69
  if(atBottom() && moreContent) {
71
70
  currentIndex += perPage;
72
- if(currentIndex >= filteredEntries.length) moreContent = false;
71
+ if(currentIndex >= Entries.all().length) moreContent = false;
73
72
  render();
74
73
  }
75
74
  scrollDebounce = false;
@@ -85,32 +84,8 @@ var Listing = (function() {
85
84
 
86
85
  sortable.classList.add("sort-active", "sort-" + sortable.dataset.sortDirection);
87
86
 
88
- Index.loadEntries(function() {
89
- sortable.scrollIntoView();
90
- });
91
- }
92
-
93
- function updateFilteredEntries(needle) {
94
- if(needle == "") {
95
- filteredEntries = window.entries;
96
- }
97
- else {
98
- filteredEntries = [];
99
-
100
- for(var i = 0; i < window.entries.length; i++) {
101
- var entry = window.entries[i];
102
- if(entry.name.toLowerCase().includes(needle.toLowerCase())) filteredEntries.push(entry);
103
- }
104
- }
105
- }
106
-
107
- function applyFilter(needle) {
108
- updateFilteredEntries(needle);
109
-
110
- $container.innerHTML = "";
111
- currentIndex = 0;
112
- moreContent = true;
113
- render();
87
+ Entries.sort(sortable.dataset.sortMethod, sortable.dataset.sortDirection);
88
+ sortable.scrollIntoView();
114
89
  }
115
90
 
116
91
  function initEvents() {
@@ -134,28 +109,31 @@ var Listing = (function() {
134
109
  e.stopPropagation();
135
110
 
136
111
  if(e.keyCode == 13) {
137
- applyFilter($("#search").value);
112
+ Entries.filter($("#search").value);
138
113
  }
139
114
  });
140
115
  }
141
116
 
142
- function onEntriesInit() {
143
- onEntriesUpdate();
144
- $("#listing").style.display = "block";
145
- initEvents();
146
- }
147
-
148
117
  function onEntriesUpdate() {
149
- applyFilter($("#search").value);
118
+ $container.innerHTML = "";
119
+ currentIndex = 0;
120
+ moreContent = true;
121
+ render();
150
122
  }
151
123
 
152
- window.addEventListener("DOMContentLoaded", function() {
124
+ function init() {
153
125
  $ = document.querySelector.bind(document);
154
126
  $container = $("#listing-container");
155
- });
127
+
128
+ onEntriesUpdate();
129
+
130
+ initEvents();
131
+ }
156
132
 
157
133
  return {
158
- onEntriesInit: onEntriesInit,
134
+ init: init,
159
135
  onEntriesUpdate: onEntriesUpdate
160
136
  };
161
137
  })();
138
+
139
+ window.addEventListener("DOMContentLoaded", Listing.init);
@@ -0,0 +1,2 @@
1
+ var naturalOrderBy=function(e){"use strict";var d=function(e,n){return e<n?-1:n<e?1:0},r=/(^0x[\da-fA-F]+$|^([+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?(?!\.\d+)(?=\D|\s|$))|\d+)/g,l=/^\s+|\s+$/g,o=/\s+/g,u=/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/,t=/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[/-]\d{1,4}[/-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,a=/^0+[1-9]{1}[0-9]*$/,y=/[^\x00-\x80]/,m=function(e,n){return e.value===n.value?0:void 0!==e.parsedNumber&&void 0!==n.parsedNumber?d(e.parsedNumber,n.parsedNumber):e.chunks&&n.chunks?function(e,n){for(var r,t,i,o,u=e.length,a=n.length,s=Math.min(u,a),c=0;c<s;c++){var f=e[c],l=n[c];if(f!==l)return""===f!=(""===l)?""===f?-1:1:"number"==typeof f&&"number"==typeof l?d(f,l):"number"==typeof f||"number"==typeof l?"number"==typeof f?-1:1:y.test(f+l)&&f.localeCompare?(i=l,(o=f.localeCompare(i))?o/Math.abs(o):0):(r=f)<(t=l)?-1:t<r?1:0}return s<u||s<a?u<=s?-1:1:0}(e.chunks,n.chunks):(t=n,((r=e).chunks?!t.chunks:t.chunks)?r.chunks?-1:1:(r.isNaN?!t.isNaN:t.isNaN)?r.isNaN?-1:1:(r.isSymbol?!t.isSymbol:t.isSymbol)?r.isSymbol?-1:1:(r.isObject?!t.isObject:t.isObject)?r.isObject?-1:1:(r.isArray?!t.isArray:t.isArray)?r.isArray?-1:1:(r.isFunction?!t.isFunction:t.isFunction)?r.isFunction?-1:1:(r.isNull?!t.isNull:t.isNull)?r.isNull?-1:1:0);var r,t},v="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},s=function(r){return"function"==typeof r?r:function(e){if(Array.isArray(e)){var n=Number(r);if(Number.isInteger(n))return e[n]}else if(e&&"object"===(void 0===e?"undefined":v(e))&&"function"!=typeof r)return e[r];return e}},c=function(e){if(0!==e.length){var n=Number(e);if(!Number.isNaN(n))return n}},b=function(e){var n=c(e);return void 0!==n?n:function(e){if(t.test(e)){var n=Date.parse(e);if(!Number.isNaN(n))return n}}(e)},p=function(e){var n;return(n=e,n.replace(r,"\0$1\0").replace(/\0$/,"").replace(/^\0/,"").split("\0")).map(function(e,n,r){return t=e,i=r.length,!u.test(t)||a.test(t)&&1!==i?t.replace(o," ").replace(l,""):c(t)||0;var t,i})},N=function(e){return Number.isNaN(e)||e instanceof Number&&Number.isNaN(e.valueOf())},f=function(){var f=!(0<arguments.length&&void 0!==arguments[0])||arguments[0];return function(e){if("string"==typeof e||e instanceof String||("number"==typeof e||e instanceof Number)&&!N(e)||"boolean"==typeof e||e instanceof Boolean||e instanceof Date){var n=(i=f,"boolean"==typeof(t=e)||t instanceof Boolean?Number(t).toString():"number"==typeof t||t instanceof Number?t.toString():t instanceof Date?t.getTime().toString():"string"==typeof t||t instanceof String?(i?t:t.toLowerCase()).replace(l,""):""),r=b(n);return{parsedNumber:r,chunks:p(r?""+r:n),value:e}}var t,i,o,u,a,s,c;return{isArray:Array.isArray(e),isFunction:(c=e,"function"==typeof c),isNaN:N(e),isNull:(s=e,null===s),isObject:(a=e,!(null===a||"object"!==(void 0===a?"undefined":v(a))||Array.isArray(a)||a instanceof Number||a instanceof String||a instanceof Boolean||a instanceof Date)),isSymbol:(u=e,"symbol"===(void 0===u?"undefined":v(u))),isUndefined:(o=e,void 0===o),value:e}}},g=function(t,e,r){var i=e.length?e.map(s):[function(e){return e}],n=t.map(function(n,e){return{index:e,values:i.map(function(e){return e(n)}).map(f())}});return n.sort(function(e,n){return function(e,n,r){for(var t=e.values,i=n.values,o=t.length,u=r.length,a=0;a<o;a++){var s=a<u?r[a]:null;if(s&&"function"==typeof s){var c=s(t[a].value,i[a].value);if(c)return c}else{var f=m(t[a],i[a]);if(f)return f*("desc"===s?-1:1)}}return 0}(e,n,r)}),n.map(function(e){return n=t,r=e.index,n[r];var n,r})};var i={caseSensitive:!0,order:"asc"};return e.orderBy=function(e,n,r){if(!e||!Array.isArray(e))return[];var t=function(e){if(!e)return[];var n=Array.isArray(e)?[].concat(e):[e];return n.some(function(e){return"string"!=typeof e&&"number"!=typeof e&&"function"!=typeof e})?[]:n}(n),i=function(e){if(!e)return[];var n=Array.isArray(e)?[].concat(e):[e];return n.some(function(e){return"asc"!==e&&"desc"!==e&&"function"!=typeof e})?[]:n}(r);return g(e,t,i)},e.compare=function(e){var n,o,r=(n=e)&&"object"===(void 0===n?"undefined":v(n))?{caseSensitive:"boolean"==typeof n.caseSensitive?n.caseSensitive:i.caseSensitive,order:"asc"===n.order||"desc"===n.order?n.order:i.order}:i;return o=r,function(e,n){var r=f(o.caseSensitive),t=r(e),i=r(n);return m(t,i)*("desc"===o.order?-1:1)}},e}({});
2
+ //# sourceMappingURL=natural-orderby.min.js.map
File without changes
data/lib/servel.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'rack'
2
2
  require 'rack/handler/puma'
3
3
  require 'hamlit'
4
- require 'naturalsorter'
5
4
  require 'active_support/all'
6
5
  require 'lru_redux'
7
6
 
@@ -23,7 +22,6 @@ require "servel/instrumentation"
23
22
  require "servel/entry"
24
23
  require "servel/entry_factory"
25
24
  require "servel/haml_context"
26
- require "servel/entries"
27
25
  require "servel/index"
28
26
  require "servel/app"
29
27
  require "servel/home_app"
data/lib/servel/app.rb CHANGED
@@ -25,13 +25,7 @@ class Servel::App
25
25
 
26
26
  return [404, {}, []] unless fs_path.exist?
27
27
 
28
- request = Rack::Request.new(env)
29
-
30
- if json_request?(request)
31
- Servel::Entries.new(url_root: url_root, url_path: url_path, fs_path: fs_path, params: request.params).render
32
- else
33
- Servel::Index.new(url_root: url_root, url_path: url_path).render
34
- end
28
+ Servel::Index.new(url_root: url_root, url_path: url_path, fs_path: fs_path).render
35
29
  end
36
30
 
37
31
  def redirect(location)
@@ -44,10 +38,6 @@ class Servel::App
44
38
  Rack::Utils.clean_path_info(url_path)
45
39
  end
46
40
 
47
- def json_request?(request)
48
- Rack::Utils.best_q_match(request.get_header("HTTP_ACCEPT"), ['text/html', 'application/json']) == 'application/json'
49
- end
50
-
51
41
  def try_encode(string)
52
42
  return string if string.encoding == UTF_8
53
43
  string.encode(UTF_8)
data/lib/servel/entry.rb CHANGED
@@ -32,11 +32,13 @@ class Servel::Entry
32
32
  icon: @icon,
33
33
  href: Rack::Utils.escape_path(@href),
34
34
  class: @listing_classes,
35
- media_type: @media_type,
35
+ mediaType: @media_type,
36
36
  name: @name,
37
37
  type: @type,
38
- size: @size.nil? ? "-" : @size,
39
- mtime: @mtime.nil? ? "-" : @mtime.strftime("%e %b %Y %l:%M %p"),
38
+ size: @size.to_i,
39
+ sizeText: @size.nil? ? "-" : @size,
40
+ mtime: @mtime.to_i,
41
+ mtimeText: @mtime.nil? ? "-" : @mtime.strftime("%e %b %Y %l:%M %p"),
40
42
  media: media?
41
43
  }
42
44
  end
@@ -9,7 +9,7 @@ class Servel::HamlContext
9
9
  end
10
10
 
11
11
  def initialize
12
- @build_path = Pathname.new(__FILE__).dirname.realpath + 'templates'
12
+ @build_path = Pathname.new(__FILE__).dirname.realpath + "../../app"
13
13
  end
14
14
 
15
15
  def render(template, locals = {})
data/lib/servel/index.rb CHANGED
@@ -1,21 +1,44 @@
1
1
  class Servel::Index
2
2
  extend Servel::Instrumentation
3
+ RENDER_CACHE = LruRedux::ThreadSafeCache.new(100)
3
4
 
4
- def initialize(url_root:, url_path:)
5
+ def initialize(url_root:, url_path:, fs_path:)
5
6
  @url_root = url_root
6
7
  @url_path = url_path
8
+ @fs_path = fs_path
7
9
  end
8
10
 
9
11
  def render
10
- Servel::HamlContext.render('index.haml', locals)
12
+ RENDER_CACHE.getset(render_cache_key) { Servel::HamlContext.render('index.haml', locals) }
13
+ end
14
+
15
+ def render_cache_key
16
+ @render_cache_key ||= [@fs_path.to_s, @fs_path.mtime.to_i].join("-")
11
17
  end
12
18
 
13
19
  def locals
20
+ children = @fs_path.children.map { |path| Servel::EntryFactory.for(path) }.compact
21
+
14
22
  {
15
23
  url_root: @url_root,
16
- url_path: @url_path
24
+ url_path: @url_path,
25
+ special_entries: special_entries.to_json,
26
+ directory_entries: children.select(&:directory?).to_json,
27
+ file_entries: children.select(&:file?).to_json
17
28
  }
18
29
  end
19
30
 
31
+ def special_entries
32
+ list = []
33
+ list << Servel::EntryFactory.home("/") if @url_root != ""
34
+
35
+ unless @url_path == "/"
36
+ list << Servel::EntryFactory.top(@url_root == "" ? "/" : @url_root)
37
+ list << Servel::EntryFactory.parent("../")
38
+ end
39
+
40
+ list
41
+ end
42
+
20
43
  instrument :render, :locals
21
44
  end
@@ -1,3 +1,3 @@
1
1
  module Servel
2
- VERSION = "0.20.0"
2
+ VERSION = "0.21.0"
3
3
  end
data/servel.gemspec CHANGED
@@ -25,7 +25,6 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "rake", "~> 12.0"
26
26
  spec.add_dependency "rack", "~> 2.0"
27
27
  spec.add_dependency "puma"
28
- spec.add_dependency "naturalsorter"
29
28
  spec.add_dependency "hamlit"
30
29
  spec.add_dependency "activesupport"
31
30
  spec.add_dependency "lru_redux"
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.20.0
4
+ version: 0.21.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-08-30 00:00:00.000000000 Z
11
+ date: 2018-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: naturalsorter
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: hamlit
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -135,33 +121,33 @@ files:
135
121
  - LICENSE.txt
136
122
  - README.md
137
123
  - Rakefile
124
+ - app/_gallery.haml
125
+ - app/_listing.haml
126
+ - app/css/common.css
127
+ - app/css/gallery-text.css
128
+ - app/css/gallery.css
129
+ - app/css/home.css
130
+ - app/css/listing.css
131
+ - app/css/normalize.css
132
+ - app/home.haml
133
+ - app/index.haml
134
+ - app/js/entries.js
135
+ - app/js/gallery.js
136
+ - app/js/listing.js
137
+ - app/js/natural-orderby.min.js
138
+ - app/js/ume.js
138
139
  - bin/console
139
140
  - bin/servel
140
141
  - bin/setup
141
142
  - lib/servel.rb
142
143
  - lib/servel/app.rb
143
144
  - lib/servel/cli.rb
144
- - lib/servel/entries.rb
145
145
  - lib/servel/entry.rb
146
146
  - lib/servel/entry_factory.rb
147
147
  - lib/servel/haml_context.rb
148
148
  - lib/servel/home_app.rb
149
149
  - lib/servel/index.rb
150
150
  - lib/servel/instrumentation.rb
151
- - lib/servel/templates/_gallery.haml
152
- - lib/servel/templates/_listing.haml
153
- - lib/servel/templates/css/common.css
154
- - lib/servel/templates/css/gallery-text.css
155
- - lib/servel/templates/css/gallery.css
156
- - lib/servel/templates/css/home.css
157
- - lib/servel/templates/css/listing.css
158
- - lib/servel/templates/css/normalize.css
159
- - lib/servel/templates/home.haml
160
- - lib/servel/templates/index.haml
161
- - lib/servel/templates/js/gallery.js
162
- - lib/servel/templates/js/index.js
163
- - lib/servel/templates/js/listing.js
164
- - lib/servel/templates/js/ume.js
165
151
  - lib/servel/version.rb
166
152
  - servel.gemspec
167
153
  homepage: http://bloople.net/
@@ -1,68 +0,0 @@
1
- class Servel::Entries
2
- extend Servel::Instrumentation
3
- RENDER_CACHE = LruRedux::ThreadSafeCache.new(100)
4
- SORT_METHODS = ["name", "mtime", "size", "type"]
5
- SORT_DIRECTIONS = ["asc", "desc"]
6
-
7
- def initialize(url_root:, url_path:, fs_path:, params:)
8
- @url_root = url_root
9
- @url_path = url_path
10
- @fs_path = fs_path
11
- @params = params
12
- end
13
-
14
- def render
15
- RENDER_CACHE.getset(render_cache_key) { [200, {}, [entries.to_json]] }
16
- end
17
-
18
- def render_cache_key
19
- @render_cache_key ||= [@fs_path.to_s, @fs_path.mtime.to_i, sort_method, sort_direction].join("-")
20
- end
21
-
22
- def entries
23
- children = @fs_path.children.map { |path| Servel::EntryFactory.for(path) }.compact
24
- special_entries + apply_sort(children.select(&:directory?)) + apply_sort(children.select(&:file?))
25
- end
26
-
27
- def sort_method
28
- param = @params["_servel_sort_method"]
29
- param = "name" unless SORT_METHODS.include?(param)
30
- param
31
- end
32
-
33
- def sort_direction
34
- param = @params["_servel_sort_direction"]
35
- param = "asc" unless SORT_DIRECTIONS.include?(param)
36
- param
37
- end
38
-
39
- def special_entries
40
- list = []
41
- list << Servel::EntryFactory.home("/") if @url_root != ""
42
-
43
- unless @url_path == "/"
44
- list << Servel::EntryFactory.top(@url_root == "" ? "/" : @url_root)
45
- list << Servel::EntryFactory.parent("../")
46
- end
47
-
48
- list
49
- end
50
-
51
- def apply_sort(entries)
52
- entries = case sort_method
53
- when "name"
54
- Naturalsorter::Sorter.sort_by_method(entries, :name, true)
55
- when "mtime"
56
- entries.sort_by { |entry| entry.mtime }
57
- when "size"
58
- entries.sort_by { |entry| entry.size || 0 }
59
- when "type"
60
- entries.sort_by { |entry| entry.type }
61
- end
62
-
63
- entries.reverse! if sort_direction == "desc"
64
- entries
65
- end
66
-
67
- instrument :render, :entries, :apply_sort
68
- end
@@ -1,54 +0,0 @@
1
- "use strict";
2
-
3
- var Index = (function() {
4
- var $;
5
- var inited = false;
6
-
7
- function entriesURL() {
8
- var sortable = $("th.sortable.sort-active");
9
- return `${location.pathname}?_servel_sort_method=${sortable.dataset.sortMethod}&_servel_sort_direction=${sortable.dataset.sortDirection}`;
10
- }
11
-
12
- function onEntriesLoad(callback) {
13
- if(inited) {
14
- Gallery.onEntriesUpdate();
15
- Listing.onEntriesUpdate();
16
- }
17
- else {
18
- inited = true;
19
- Gallery.onEntriesInit();
20
- Listing.onEntriesInit();
21
- }
22
-
23
- $("#loading").style.display = "none";
24
- if(callback) callback();
25
- }
26
-
27
- function loadEntries(callback) {
28
- $("#loading").style.display = "flex";
29
-
30
- var http = new XMLHttpRequest();
31
- http.open("GET", entriesURL());
32
-
33
- http.onreadystatechange = function() {
34
- if(http.readyState === 4 && http.status === 200) {
35
- window.entries = JSON.parse(http.responseText);
36
- setTimeout(function() {
37
- onEntriesLoad(callback);
38
- }, 0);
39
- }
40
- };
41
-
42
- http.setRequestHeader("Accept", "application/json");
43
- http.send();
44
- }
45
-
46
- window.addEventListener("DOMContentLoaded", function() {
47
- $ = document.querySelector.bind(document);
48
- loadEntries();
49
- });
50
-
51
- return {
52
- loadEntries: loadEntries
53
- };
54
- })();