Permalink
Find file
f74d7fe Nov 13, 2015
313 lines (289 sloc) 13.3 KB
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>REST Files: GitHub-like file access with 1 page jQuery + 1 C# REST Service</title>
<link href="/img/logo.png" rel="icon" />
<link rel="stylesheet" type="text/css" href="css/default.css" />
<script type="text/javascript" src="/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="js/ajaxfileupload.js"></script>
</head>
<body>
<div id="header">
<a id="github" title="View source on GitHub" href="https://github.com/ServiceStackApps/AwsApps/tree/master/src/AwsApps/restfiles"><img src="img/btn-github.png" alt="GitHub Project" /></a>
</div>
<div id="title">
<h1>
<a href="/"><img src="/img/logo.png" /></a>
ServiceStack
<b>/</b><a href="./">Rest Files</a>
</h1>
</div>
<div id="info">
<div id="net">
<strong>
.NET Clients can access the File Service API with:
</strong>
<a href="https://github.com/ServiceStackApps/RestFiles/blob/master/src/RestFiles/RestFiles.Tests/AsyncRestClientTests.cs">
Async C# client examples
</a>
<a href="https://github.com/ServiceStackApps/RestFiles/blob/master/src/RestFiles/RestFiles.Tests/SyncRestClientTests.cs">Sync
C# client examples
</a>
</div>
<h3>
GitHub-like browser with complete remote file management over REST in
<a href="https://github.com/ServiceStack/ServiceStack.Aws/tree/master/tests/AwsApps/restfiles/default.htm">
1 page jQuery
</a> +
<a href="https://github.com/ServiceStack/ServiceStack.Aws/tree/master/tests/AwsApps/FilesService.cs">
1 page C#
</a>
</h3>
<div id="doc">
<h4>
<a href="/metadata">The REST /files web service API:</a></h4>
<dl>
<dt><b>GET</b> <a href="./files/js">/path/to/folder</a></dt>
<dd>Directory listing at server</dd>
<dt><b>GET</b> <a href="./files/FilesService.cs">/path/to/file.txt</a></dt>
<dd>Info and contents of text file at path</dd>
<dt><b>POST</b> /path/to/newfolder (no-body)</dt>
<dd>Upload file at folder path</dd>
<dt><b>PUT</b> /path/to/file.txt</dt>
<dd>Replace contents of text file at path</dd>
<dt><b>DELETE</b> /path/to/folder</dt>
<dd>Delete folder at path</dd>
</dl>
</div>
</div>
<div id="breadcrumb">
</div>
<div id="ls">
</div>
<div id="fileadmin">
<div class="upload ib">
<input type="file" name="fileupload" id="fileupload"/>
<a class="btn"><span>upload here</span></a>
</div>
</div>
<div id="fileview"></div>
<div id="footer">
<a id="logo" href="https://servicestack.net">
<img src="https://raw.githubusercontent.com/ServiceStack/Assets/master/img/apps/logo-txt-small.png" alt="ServiceStack" /></a>
<div id="disclaimer" style="margin: 30px 0 0 0">
*Not affiliated with GitHub, which is a trademark of GitHub Inc.</div>
</div>
<script>
if (typeof console == "undefined") { var console = {}; console.log = function () { }; }
$.ajaxSetup({ cache: false, dataType: 'json' });
function fromDtoDate(dateStr) {
return new Date(parseFloat(/Date\(([^)]+)\)/.exec(dateStr)[1]));
}
function toTwitterTime(a) {
var b = new Date();
var c = typeof a == "date" ? a : new Date(a);
var d = b - c;
var e = 1000, minute = e * 60, hour = minute * 60, day = hour * 24, week = day * 7;
if (isNaN(d) || d < 0) { return "" }
if (d < e * 7) { return "right now" }
if (d < minute) { return Math.floor(d / e) + " secs ago" }
if (d < minute * 2) { return "about 1 min ago" }
if (d < hour) { return Math.floor(d / minute) + " mins ago" }
if (d < hour * 2) { return "about 1 hour ago" }
if (d < day) { return Math.floor(d / hour) + " hours ago" }
if (d > day && d < day * 2) { return "yesterday" }
if (d < day * 365) { return Math.floor(d / day) + " days ago" } else { return "over a year ago" }
}
function enc(html) {
if (typeof html != "string") return html;
return html.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
function dirPath(path) {
if (typeof path != "string") return path;
var strPos = path.lastIndexOf('/', path.length - 1);
if (strPos == -1) return path;
return path.substr(0, strPos);
}
function _mkAjax(url, data, callback, type, method) {
if ($.isFunction(data)) {
callback = data, data = {};
}
return $.ajax({ type: method, url: url, data: data, success: callback, contentType: type });
}
$.extend({
put: function (url, data, callback, type) {
return _mkAjax(url, data, callback, type, 'PUT');
},
del: function (url, data, callback, type) {
return _mkAjax(url, data, callback, type, 'DELETE');
}
});
var href = "files", lastHref = "";
var mkdir = function () {
var dir = $("#dirname");
if (!dir.val()) {
alert("Enter the name of the folder first");
dir.focus();
return;
}
$.post(href + "/" + dir.val(), null, function () { dir.val(''); refresh(); });
};
$(".mkdir .btn").click(mkdir);
$(".mkdir INPUT").keypress(function (e) { if (e.which == '13') mkdir(); });
$(".upload .btn").click(function () {
var file = $("#fileupload").val();
if (!file) {
alert("Select a file to upload first");
return;
}
try {
$.ajaxFileUpload({
url: href + "?format=json",
secureuri: false,
fileElementId: 'fileupload',
success: refresh
});
}
catch (e) {
alert("Not supported in " + ($.browser.msie ? "IE" : "this browser"));
}
});
$(".btn").mousedown(function () { $(this).toggleClass("mousedown"); });
$(".btn").mouseup(function () { $(this).toggleClass("mousedown"); });
var refresh = function (callback, skipPushState) {
if (!skipPushState && window.history.pushState)
window.history.pushState(href, href.replace('/', ' / '), '#!' + href);
var dirs = href.replace(/\/$/, "").split('/');
var sb = '<div id="breadcrumb">';
var sbDirs = "";
for (var i = 0; i < dirs.length; i++) {
var dir = dirs[i];
if (!dir) continue;
sb += (i == dirs.length - 1)
? '<strong>' + dir + '</strong>'
: '<a href="#!' + sbDirs + dir + '">' + dir + '</a><b>/</b>';
sbDirs += dir + "/";
}
$("#breadcrumb").html(sb + "</div>");
var jqLs = $("#ls");
$.getJSON(href, function (r) {
var navBack = lastHref.length > href.length && lastHref.substr(0, href.length) == href,
nextCls = navBack ? "results-0" : "results-2",
hasResults = $("#ls TABLE").length == 1,
cls = !hasResults ? "results-1" : nextCls;
var sb = "<div class='" + cls + "'><table><thead><tr><th>name</th><th>age</th><th>size</th></thead><tbody>";
var file = r.file;
if (file) {
if (!file.isTextFile) {
location.href = href + "?ForDownload=true";
setTimeout(function () { window.history.back() }, 1000);
return;
}
var jqFile = $("#fileview");
var sb = "<h3><a class='btn edit' href='#!savechanges'><span>save changes</span></a></dd>"
+ "<span class='ib txt'></span><dl><dd>" + enc(file.fileSizeBytes) + " bytes</dd><dd>"
+ toTwitterTime(fromDtoDate(file.modifiedDate)) + "</dd>"
+ '<dd><a class="btn download" href="' + href + '?ForDownload=true"><span>download file</span></a></dd>'
+ "</dl></h3>"
+ "<textarea>" + enc(file.contents) + "</textarea>";
jqFile.html(sb).show();
var height = $("#footer").position().top - $("#ls").position().top;
$("#fileview TEXTAREA").height(height - 65);
$("#fileadmin").hide();
$("#ls").html("").hide();
return;
}
$("#fileview").html("").hide();
var dirList = r.directory;
if (dirList) {
if (dirs.length > 1) {
var upHref = href.substr(0, href.lastIndexOf('/', href.length - 2));
sb += "<tr><td><a class='up-dir' href='#!" + upHref + "'>..<a></td><td></td><td></td></tr>";
}
$.each(dirList.folders, function (i, dir) {
sb += "<tr><td><a class='dir' href='#!" + href + "/" + dir.name + "'>" + dir.name + "/<a></td><td>"
+ toTwitterTime(fromDtoDate(dir.modifiedDate)) + "</td><td>"
+ dir.fileCount + " files</td>";
});
$.each(dirList.files, function (i, file) {
sb += "<tr><td><a class='file' href='#!" + href + "/" + file.name + "'><b class='del' href='#!deletefile'></b>" + file.name + "</a></td><td>"
+ toTwitterTime(fromDtoDate(file.modifiedDate)) + "</td><td>"
+ file.fileSizeBytes + " bytes</td>";
});
}
sb += "</tbody></table></div>";
$("#fileadmin").show();
$("#ls").show().append(sb);
var jq1 = $(".results-1"), jq2 = $("." + nextCls), el1 = jq1[0], el2 = jq2[0];
if (el1 && el2) {
jqLs.css({ "min-height": Math.max(jq1.height(), jq2.height()) + "px" });
setTimeout(function () {
jqLs.children().first().remove();
jqLs.children().first()[0].className = "results-1";
}, 450);
}
else {
$("#ls").css({ "min-height": jq1.height() + "px" });
}
});
}
window.onpopstate = function (e) {
e = e || event;
if (!e.state) return;
href = e.state;
refresh(null, true);
};
var clickHandlers = {
files: function (el, e, href) {
if (e.ctrlKey || e.shiftKey) {
window.open('#!' + href);
return;
}
refresh();
},
savechanges: function () {
$.put(lastHref, { TextContents: $("#fileview textarea").val() }, refresh, 'application/x-www-form-urlencoded');
href = dirPath(lastHref), location.hash = "#!" + href;
},
deletefile: function (el) {
var fileHref = $(el.parentNode).attr('href').substr(2);
$.del(fileHref, refresh);
href = dirPath(fileHref), location.hash = "#!" + href;
},
closechoice: function () {
document.body.className = "";
href = "files", location.hash = "#!files";
refresh();
}
}
$(document).click(function (e) {
var attrHref, el = e.target;
do { attrHref = el.getAttribute("href"); } while (!attrHref && (el = el.parentElement));
if (!attrHref) return;
if (attrHref.substr(0, 2) === "#!") {
lastHref = href, href = attrHref.substr(2);
var cmd = href.split('/')[0];
var clickHandler = clickHandlers[cmd];
if (clickHandler) {
if (e.preventDefault) e.preventDefault();
clickHandler(el, e, href);
}
}
});
var hash = location.hash.indexOf('#!') === 0 && location.hash.substr(2);
if (hash) href = hash;
refresh();
</script>
<!-- change the UA-XXXXX-X to be your site's ID -->
<script>
var _gaq = [['_setAccount', 'UA-7722718-7'], ['_trackPageview']];
(function (d, t) {
var g = d.createElement(t),
s = d.getElementsByTagName(t)[0];
g.async = true;
g.src = ('https:' == location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
s.parentNode.insertBefore(g, s);
})(document, 'script');
</script>
</body>
</html>