Initial switch to smart browsing.

This commit is contained in:
Lars Jung 2012-10-18 21:27:09 +02:00
parent ecc05d3a8b
commit 499013f4fb
12 changed files with 244 additions and 97 deletions

View file

@ -1,13 +1,5 @@
modulejs.define('core/entry', ['_', 'config', 'model/entry'], function (_, config, Entry) { modulejs.define('core/entry', ['core/location'], function (location) {
_.each(config.entries || [], function (entry) { return location.getItem();
Entry.get(entry.absHref, entry.time, entry.size, entry.status, entry.content);
});
var entry = Entry.get();
entry.status = '=h5ai=';
return entry;
}); });

View file

@ -1,7 +1,13 @@
modulejs.define('core/location', [], function () { modulejs.define('core/location', ['_', 'modernizr', 'core/settings', 'core/event', 'core/notify'], function (_, modernizr, allsettings, event, notify) {
var doc = document, var settings = _.extend({
smartBrowsing: false
}, allsettings.view),
doc = document,
history = settings.smartBrowsing && modernizr.history ? window.history : null,
forceEncoding = function (href) { forceEncoding = function (href) {
@ -17,36 +23,109 @@ modulejs.define('core/location', [], function () {
.replace(/\=/g, '%3D'); .replace(/\=/g, '%3D');
}, },
absHref = (function () { reUriToPathname = /^.*:\/\/[^\/]*|[^\/]*$/g,
uriToPathname = function (uri) {
var rePrePathname = /.*:\/\/[^\/]*/, return uri.replace(reUriToPathname, '');
rePostPathname = /[^\/]*$/, },
uriToPathname = function (uri) { hrefsAreDecoded = (function () {
return uri.replace(rePrePathname, '').replace(rePostPathname, ''); var testpathname = '/a b',
}, a = doc.createElement('a');
testpathname = '/a b',
a = doc.createElement('a'),
isDecoded, location;
a.href = testpathname; a.href = testpathname;
isDecoded = uriToPathname(a.href) === testpathname; return uriToPathname(a.href) === testpathname;
}()),
a.href = doc.location.href; encodedHref = function (href) {
var a = doc.createElement('a'),
location;
a.href = href;
location = uriToPathname(a.href); location = uriToPathname(a.href);
if (isDecoded) { if (hrefsAreDecoded) {
location = encodeURIComponent(location).replace(/%2F/ig, '/'); location = encodeURIComponent(location).replace(/%2F/ig, '/');
} }
return forceEncoding(location); return forceEncoding(location);
}()); };
var absHref = null,
getDomain = function () {
return doc.domain;
},
getAbsHref = function () {
return absHref;
},
getItem = function () {
return modulejs.require('model/entry').get(absHref);
},
setLocation = function (newAbsHref, keepBrowserUrl) {
newAbsHref = encodedHref(newAbsHref);
if (absHref !== newAbsHref) {
absHref = newAbsHref;
event.pub('location.changed', absHref);
notify.set('loading...');
modulejs.require('core/refresh')(function () { notify.set(); });
if (history) {
if (keepBrowserUrl) {
history.replaceState({absHref: absHref}, '', absHref);
} else {
history.pushState({absHref: absHref}, '', absHref);
}
}
}
},
setLink = function ($el, item) {
$el.attr('href', item.absHref);
if (history && item.isFolder() && item.status === '=h5ai=') {
$el.on('click', function () {
setLocation(item.absHref);
return false;
});
}
if (item.status !== '=h5ai=') {
$el.attr('target', '_blank');
}
};
if (history) {
window.onpopstate = function (e) {
if (e.state && e.state.absHref) {
setLocation(e.state.absHref, true);
}
};
}
return { return {
domain: doc.domain, forceEncoding: forceEncoding,
absHref: absHref, encodedHref: encodedHref,
forceEncoding: forceEncoding getDomain: getDomain,
getAbsHref: getAbsHref,
getItem: getItem,
setLocation: setLocation,
setLink: setLink
}; };
}); });

View file

@ -1,5 +1,5 @@
modulejs.define('core/refresh', ['_', 'core/server', 'model/entry'], function (_, server, Entry) { modulejs.define('core/refresh', ['_', 'config', 'core/server', 'model/entry', 'core/location'], function (_, config, server, Entry, location) {
var parseJson = function (entry, json) { var parseJson = function (entry, json) {
@ -20,7 +20,7 @@ modulejs.define('core/refresh', ['_', 'core/server', 'model/entry'], function (_
refresh = function (callback) { refresh = function (callback) {
var entry = Entry.get(); var entry = Entry.get(location.getAbsHref());
server.request({action: 'get', entries: true, entriesHref: entry.absHref, entriesWhat: 1}, function (json) { server.request({action: 'get', entries: true, entriesHref: entry.absHref, entriesWhat: 1}, function (json) {

View file

@ -1,5 +1,5 @@
modulejs.define('core/server', ['$', '_', 'config'], function ($, _, config) { modulejs.define('core/server', ['$', '_', 'config', 'core/location'], function ($, _, config, location) {
var server = _.extend({}, config.server, { var server = _.extend({}, config.server, {
@ -7,7 +7,7 @@ modulejs.define('core/server', ['$', '_', 'config'], function ($, _, config) {
if (server.api) { if (server.api) {
$.ajax({ $.ajax({
url: '.', url: location.getAbsHref(),
data: data, data: data,
type: 'POST', type: 'POST',
dataType: 'json', dataType: 'json',

View file

@ -1,5 +1,5 @@
modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/event', 'core/entry'], function (_, $, allsettings, resource, event, entry) { modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/event', 'core/location'], function (_, $, allsettings, resource, event, location) {
var settings = _.extend({ var settings = _.extend({
enabled: false enabled: false
@ -26,11 +26,11 @@ modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/
$html $html
.addClass(entry.isFolder() ? 'folder' : 'file') .addClass(entry.isFolder() ? 'folder' : 'file')
.data('item', entry)
.data('status', entry.status); .data('status', entry.status);
$a location.setLink($a, entry);
.attr('href', entry.absHref) $a.find('span').text(entry.label).end();
.find('span').text(entry.label).end();
if (entry.isDomain()) { if (entry.isDomain()) {
$html.addClass('domain'); $html.addClass('domain');
@ -69,25 +69,49 @@ modulejs.define('ext/crumb', ['_', '$', 'core/settings', 'core/resource', 'core/
} }
}, },
// creates the complete crumb from entry down to the root onLocationChanged = function (item) {
init = function (entry) {
var crumb = item.getCrumb(),
$ul = $('#navbar'),
found = false;
$ul.find('.crumb').each(function () {
var $html = $(this);
if ($html.data('item') === item) {
found = true;
$html.addClass('current');
} else {
$html.removeClass('current');
}
});
if (!found) {
$ul.find('.crumb').remove();
_.each(crumb, function (e) {
$ul.append(update(e));
});
}
},
init = function () {
if (!settings.enabled) { if (!settings.enabled) {
return; return;
} }
var crumb = entry.getCrumb(),
$ul = $('#navbar');
_.each(crumb, function (e) {
$ul.append(update(e));
});
// event.sub('entry.created', onContentChanged); // event.sub('entry.created', onContentChanged);
// event.sub('entry.removed', onContentChanged); // event.sub('entry.removed', onContentChanged);
event.sub('entry.changed', onContentChanged); event.sub('entry.changed', onContentChanged);
event.sub('location.changed', function () {
onLocationChanged(location.getItem());
});
onLocationChanged(location.getItem());
}; };
init(entry); init();
}); });

View file

@ -1,5 +1,5 @@
modulejs.define('ext/custom', ['_', '$', 'core/settings', 'core/server'], function (_, $, allsettings, server) { modulejs.define('ext/custom', ['_', '$', 'core/settings', 'core/server', 'core/event'], function (_, $, allsettings, server, event) {
var settings = _.extend({ var settings = _.extend({
enabled: false, enabled: false,
@ -7,23 +7,35 @@ modulejs.define('ext/custom', ['_', '$', 'core/settings', 'core/server'], functi
footer: '_h5ai.footer.html' footer: '_h5ai.footer.html'
}, allsettings.custom), }, allsettings.custom),
onLocationChanged = function () {
$('#content-header, #content-footer').stop(true, true).slideUp(200);
server.request({action: 'get', custom: true}, function (response) {
if (response) {
if (response.custom.header) {
$('#content-header').html(response.custom.header).stop(true, true).slideDown(400);
}
if (response.custom.footer) {
$('#content-footer').html(response.custom.footer).stop(true, true).slideDown(400);
}
}
});
},
init = function () { init = function () {
if (!settings.enabled) { if (!settings.enabled) {
return; return;
} }
server.request({action: 'get', custom: true}, function (response) { $('<div id="content-header"/>').hide().prependTo('#content');
$('<div id="content-footer"/>').hide().appendTo('#content');
if (response) { event.sub('location.changed', onLocationChanged);
if (response.custom.header) {
$('<div id="content-header">' + response.custom.header + '</div>').prependTo('#content'); onLocationChanged();
}
if (response.custom.footer) {
$('<div id="content-footer">' + response.custom.footer + '</div>').appendTo('#content');
}
}
});
}; };
init(); init();

View file

@ -1,5 +1,5 @@
modulejs.define('ext/link-hover-states', ['_', '$', 'core/settings'], function (_, $, allsettings) { modulejs.define('ext/link-hover-states', ['_', '$', 'core/settings', 'core/event'], function (_, $, allsettings, event) {
var settings = _.extend({ var settings = _.extend({
enabled: false enabled: false
@ -29,13 +29,22 @@ modulejs.define('ext/link-hover-states', ['_', '$', 'core/settings'], function (
selectLinks(href).removeClass('hover'); selectLinks(href).removeClass('hover');
}, },
onLocationChanged = function () {
$('.hover').removeClass('hover');
},
init = function () { init = function () {
if (settings.enabled) { if (!settings.enabled) {
$('body') return;
.on('mouseenter', selector, onMouseEnter)
.on('mouseleave', selector, onMouseLeave);
} }
$('body')
.on('mouseenter', selector, onMouseEnter)
.on('mouseleave', selector, onMouseLeave);
event.sub('location.changed', onLocationChanged);
}; };
init(); init();

View file

@ -3,10 +3,12 @@ modulejs.define('main', ['_', 'core/event'], function (_, event) {
event.pub('beforeView'); event.pub('beforeView');
modulejs.require('view/extended'); modulejs.require('view/items');
modulejs.require('view/spacing'); modulejs.require('view/spacing');
modulejs.require('view/viewmode'); modulejs.require('view/viewmode');
modulejs.require('core/location').setLocation(document.location.href, true);
event.pub('beforeExt'); event.pub('beforeExt');
_.each(modulejs.state(), function (state, id) { _.each(modulejs.state(), function (state, id) {

View file

@ -1,5 +1,6 @@
modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/settings', 'core/location', 'core/server'], function ($, _, types, event, settings, location, server) { modulejs.define('model/entry', ['$', '_', 'config', 'core/types', 'core/event', 'core/settings', 'core/server', 'core/location'], function ($, _, config, types, event, settings, server, location) {
var reEndsWithSlash = /\/$/, var reEndsWithSlash = /\/$/,
@ -44,7 +45,7 @@ modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/sett
getEntry = function (absHref, time, size, status, isContentFetched) { getEntry = function (absHref, time, size, status, isContentFetched) {
absHref = location.forceEncoding(absHref || location.absHref); absHref = location.forceEncoding(absHref);
if (!startsWith(absHref, settings.rootAbsHref)) { if (!startsWith(absHref, settings.rootAbsHref)) {
return null; return null;
@ -88,7 +89,7 @@ modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/sett
removeEntry = function (absHref) { removeEntry = function (absHref) {
absHref = location.forceEncoding(absHref || location.absHref); absHref = location.forceEncoding(absHref);
var self = cache[absHref]; var self = cache[absHref];
@ -128,6 +129,14 @@ modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/sett
callback(self); callback(self);
}); });
} }
},
init = function () {
_.each(config.entries || [], function (entry) {
getEntry(entry.absHref, entry.time, entry.size, entry.status, entry.content);
});
}; };
@ -142,7 +151,7 @@ modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/sett
this.absHref = absHref; this.absHref = absHref;
this.type = types.getType(absHref); this.type = types.getType(absHref);
this.label = createLabel(absHref === '/' ? location.domain : split.name); this.label = createLabel(absHref === '/' ? location.getDomain() : split.name);
this.time = null; this.time = null;
this.size = null; this.size = null;
this.parent = null; this.parent = null;
@ -167,7 +176,7 @@ modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/sett
isCurrentFolder: function () { isCurrentFolder: function () {
return this.absHref === location.absHref; return this.absHref === location.getAbsHref();
}, },
isInCurrentFolder: function () { isInCurrentFolder: function () {
@ -177,7 +186,7 @@ modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/sett
isCurrentParentFolder: function () { isCurrentParentFolder: function () {
return this === getEntry().parent; return this === getEntry(location.getAbsHref()).parent;
}, },
isDomain: function () { isDomain: function () {
@ -259,6 +268,9 @@ modulejs.define('model/entry', ['$', '_', 'core/types', 'core/event', 'core/sett
} }
}); });
init();
return { return {
get: getEntry, get: getEntry,
remove: removeEntry remove: removeEntry

View file

@ -1,5 +1,5 @@
modulejs.define('view/extended', ['_', '$', 'core/settings', 'core/resource', 'core/format', 'core/event', 'core/entry'], function (_, $, allsettings, resource, format, event, entry) { modulejs.define('view/items', ['_', '$', 'core/settings', 'core/resource', 'core/format', 'core/event', 'core/location'], function (_, $, allsettings, resource, format, event, location) {
var settings = _.extend({ var settings = _.extend({
setParentFolderLabels: false, setParentFolderLabels: false,
@ -25,6 +25,7 @@ modulejs.define('view/extended', ['_', '$', 'core/settings', 'core/resource', 'c
'</li>' + '</li>' +
'</ul>', '</ul>',
emptyTemplate = '<div class="empty l10n-empty"/>', emptyTemplate = '<div class="empty l10n-empty"/>',
contentTemplate = '<div id="content"><div id="extended" class="clearfix"/></div>',
// updates this single entry // updates this single entry
update = function (entry, force) { update = function (entry, force) {
@ -40,14 +41,14 @@ modulejs.define('view/extended', ['_', '$', 'core/settings', 'core/resource', 'c
$label = $html.find('.label'), $label = $html.find('.label'),
$date = $html.find('.date'), $date = $html.find('.date'),
$size = $html.find('.size'); $size = $html.find('.size');
// escapedHref = entry.absHref.replace(/'/g, "%27").replace(/"/g, "%22");
$html $html
.addClass(entry.isFolder() ? 'folder' : 'file') .addClass(entry.isFolder() ? 'folder' : 'file')
.data('entry', entry) .data('entry', entry)
.data('status', entry.status); .data('status', entry.status);
$a.attr('href', entry.absHref); location.setLink($a, entry);
$imgSmall.attr('src', resource.icon(entry.type)).attr('alt', entry.type); $imgSmall.attr('src', resource.icon(entry.type)).attr('alt', entry.type);
$imgBig.attr('src', resource.icon(entry.type, true)).attr('alt', entry.type); $imgBig.attr('src', resource.icon(entry.type, true)).attr('alt', entry.type);
$label.text(entry.label); $label.text(entry.label);
@ -94,32 +95,42 @@ modulejs.define('view/extended', ['_', '$', 'core/settings', 'core/resource', 'c
event.pub('entry.mouseleave', entry); event.pub('entry.mouseleave', entry);
}, },
// creates the view for entry content onLocationChanged = function (item) {
init = function (entry) {
var $extended = $('#extended'), var $extended = $('#extended'),
$ul = $(listTemplate), $ul = $extended.find('ul'),
$emtpy = $(emptyTemplate); $empty = $extended.find('.empty');
format.setDefaultMetric(settings.binaryPrefix); $ul.find('.entry').remove();
if (entry.parent) { if (item.parent) {
$ul.append(update(entry.parent)); $ul.append(update(item.parent));
} }
_.each(entry.content, function (e) { _.each(item.content, function (e) {
$ul.append(update(e)); $ul.append(update(e));
}); });
$extended.append($ul); if (item.isEmpty()) {
$extended.append($emtpy); $empty.show();
} else {
if (!entry.isEmpty()) { $empty.hide();
$emtpy.hide();
} }
},
init = function () {
var $content = $(contentTemplate),
$extended = $content.find('#extended'),
$ul = $(listTemplate),
$emtpy = $(emptyTemplate).hide();
format.setDefaultMetric(settings.binaryPrefix);
$extended $extended
.append($ul)
.append($emtpy)
.on('mouseenter', '.entry a', onMouseenter) .on('mouseenter', '.entry a', onMouseenter)
.on('mouseleave', '.entry a', onMouseleave); .on('mouseleave', '.entry a', onMouseleave);
@ -133,24 +144,32 @@ modulejs.define('view/extended', ['_', '$', 'core/settings', 'core/resource', 'c
event.sub('entry.created', function (entry) { event.sub('entry.created', function (entry) {
if (entry.isInCurrentFolder() && !entry.$extended) { if (entry.isInCurrentFolder() && !entry.$extended) {
update(entry, true).hide().appendTo($ul).slideDown(400); $emtpy.fadeOut(100, function () {
$emtpy.slideUp(400); update(entry, true).hide().appendTo($ul).fadeIn(400);
});
} }
}); });
event.sub('entry.removed', function (entry) { event.sub('entry.removed', function (entry) {
if (entry.isInCurrentFolder() && entry.$extended) { if (entry.isInCurrentFolder() && entry.$extended) {
entry.$extended.slideUp(400, function () { entry.$extended.fadeOut(400, function () {
entry.$extended.remove(); entry.$extended.remove();
if (entry.parent.isEmpty()) { if (entry.parent.isEmpty()) {
$emtpy.slideDown(400); $emtpy.fadeIn(100);
} }
}); });
} }
}); });
event.sub('location.changed', function () {
onLocationChanged(location.getItem());
});
$content.appendTo('body');
}; };
init(entry); init();
}); });

View file

@ -38,7 +38,8 @@ Options
"setParentFolderLabels": true, "setParentFolderLabels": true,
"binaryPrefix": false, "binaryPrefix": false,
"indexFiles": ["index.html", "index.htm", "index.php"], "indexFiles": ["index.html", "index.htm", "index.php"],
"ignore": ["^\\.", "^_{{pkg.name}}"] "ignore": ["^\\.", "^_{{pkg.name}}"],
"smartBrowsing": true
}, },
@ -67,7 +68,7 @@ Options
in each folder. in each folder.
*/ */
"custom": { "custom": {
"enabled": false, "enabled": true,
"header": "_{{pkg.name}}.header.html", "header": "_{{pkg.name}}.header.html",
"footer": "_{{pkg.name}}.footer.html" "footer": "_{{pkg.name}}.footer.html"
}, },

View file

@ -27,9 +27,6 @@ html.no-js( lang="en" )
div#topbar.clearfix div#topbar.clearfix
ul#navbar ul#navbar
div#content
div#extended.clearfix
div#bottombar.clearfix div#bottombar.clearfix
span.left span.left
a#h5ai-reference( href="{{pkg.url}}", title="{{pkg.name}} · {{pkg.description}}" ) a#h5ai-reference( href="{{pkg.url}}", title="{{pkg.name}} · {{pkg.description}}" )