Remove localhost link

This commit is contained in:
Benoit Schweblin 2013-04-09 08:58:06 +01:00
parent d43f2c341c
commit fb848a9f81
18 changed files with 4287 additions and 123 deletions

View File

@ -1 +1 @@
CACHE MANIFEST # v33 CACHE: index.html css/bootstrap.css css/jgrowl.css css/main.css js/async-runner.js js/bootstrap.js js/config.js js/custo.github.js js/dropbox.js js/gdrive.js js/jgrowl.js js/jquery.js js/jquery-ui.js js/layout.js js/main.js js/Markdown.Converter.js js/Markdown.Editor.js js/Markdown.Sanitizer.js js/require.js js/synchronizer.js img/ajax-loader.gif .js js/jquery.js .js js/jquery-ui.js img/glyphicons-halflings.png img/glyphicons-halflings-white.png img/stackedit-16.png img/stackedit-32.ico NETWORK: * CACHE MANIFEST # v33 CACHE: index.html css/bootstrap.css css/jgrowl.css css/main.css js/async-runner.js js/bootstrap.js js/config.js js/custo.github.js js/dropbox-helper.js js/gdrive.js .js js/gdrive.js js/gdrive.js js/jgrowl.js js/jquery.js js/jquery-ui.js js/layout.js js/main.js js/Markdown.Converter.js js/Markdown.Editor.js js/Markdown.Sanitizer.js js/publisher.js js/require.js js/synchronizer.js js/gdrive.js js/jquery.js .js js/jgrowl.js img/glyphicons-halflings.png img/glyphicons-halflings-white.png img/icons.png img/stackedit-32.ico img/stackedit-promo.png NETWORK: *

View File

@ -225,18 +225,53 @@ hr {
background-position: -456px -168px; background-position: -456px -168px;
} }
.icon-gdrive { .icon-stackedit {
background-image: url("../img/gdrive.png") !important; background-image: url("../img/icons.png") !important;
width: 16px; width: 16px;
height: 16px; height: 16px;
background-position: 0 0; background-position: -1px 0;
}
.icon-gdrive {
background-image: url("../img/icons.png") !important;
width: 16px;
height: 16px;
background-position: -19px 0;
} }
.icon-dropbox { .icon-dropbox {
background-image: url("../img/dropbox.png") !important; background-image: url("../img/icons.png") !important;
width: 16px; width: 16px;
height: 16px; height: 16px;
background-position: 0 0; background-position: -37px 0;
}
.icon-github {
background-image: url("../img/icons.png") !important;
width: 16px;
height: 16px;
background-position: -55px 0;
}
.icon-blogger {
background-image: url("../img/icons.png") !important;
width: 16px;
height: 16px;
background-position: -73px 0;
}
.icon-tumblr {
background-image: url("../img/icons.png") !important;
width: 16px;
height: 16px;
background-position: -91px 0;
}
.icon-wordpress {
background-image: url("../img/icons.png") !important;
width: 16px;
height: 16px;
background-position: -109px 0;
} }
.icon-spinner { .icon-spinner {

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<script src="js/dropbox.min.js"></script> <script src="lib/dropbox.js"></script>
<script type="text/javascript"> <script type="text/javascript">
Dropbox.Drivers.Popup.oauthReceiver(); Dropbox.Drivers.Popup.oauthReceiver();
</script> </script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 741 B

BIN
img/icons.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -23,7 +23,10 @@
<li class="btn-group"><button class="btn action-force-sync" <li class="btn-group"><button class="btn action-force-sync"
title="Synchronize"> title="Synchronize">
<i class="icon-refresh"></i> <i class="icon-refresh"></i>
</button></li> </button><button class="btn action-publish"
title="Publish">
<i class="icon-share"></i>
</button></li>
<li class="btn-group"><button class="btn action-create-file" <li class="btn-group"><button class="btn action-create-file"
title="New local document"> title="New local document">
<i class="icon-file"></i> <i class="icon-file"></i>
@ -39,8 +42,8 @@
<ul id="file-selector" class="dropdown-menu"> <ul id="file-selector" class="dropdown-menu">
</ul></li> </ul></li>
<li class="btn-group"><a class="btn dropdown-toggle" <li class="btn-group"><a class="btn dropdown-toggle"
data-toggle="dropdown" href="#" title="Menu"><img data-toggle="dropdown" href="#" title="Menu"><i
src="img/stackedit-16.png" />&nbsp;&nbsp;<b class="caret"></b></a> class="icon-stackedit"></i>&nbsp;&nbsp;<b class="caret"></b></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="action-download-md" href="#"><i <li><a class="action-download-md" href="#"><i
class="icon-download-alt"></i> Save as MD</a></li> class="icon-download-alt"></i> Save as MD</a></li>
@ -67,6 +70,22 @@
data-target="#modal-manage-sync"><i class="icon-refresh"></i> data-target="#modal-manage-sync"><i class="icon-refresh"></i>
Manage synchronization</a></li> Manage synchronization</a></li>
<li class="divider"></li> <li class="divider"></li>
<li class="dropdown-submenu"><a href="#"><i
class="icon-share"></i> Publish</a>
<ul class="dropdown-menu">
<li><a href="#" class="action-publish-github"><i
class="icon-github"></i> GitHub</a></li>
<li><a href="#" class="action-publish-blogger"><i
class="icon-blogger"></i> Blogger</a></li>
<li><a href="#" class="action-publish-wordpress"><i
class="icon-wordpress"></i> WordPress</a></li>
<li><a href="#" class="action-publish-tumblr"><i
class="icon-tumblr"></i> Tumblr</a></li>
</ul></li>
<li><a href="#" data-toggle="modal"
data-target="#modal-manage-publication"><i class="icon-share"></i>
Manage publication</a></li>
<li class="divider"></li>
<li><a href="#" data-toggle="modal" <li><a href="#" data-toggle="modal"
data-target="#modal-settings" class="action-load-settings"><i data-target="#modal-settings" class="action-load-settings"><i
class="icon-cog"></i> Settings</a></li> class="icon-cog"></i> Settings</a></li>
@ -237,6 +256,56 @@
</div> </div>
</div> </div>
<div id="modal-publish-existing" class="modal hide">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h3>Publish</h3>
</div>
<div class="modal-body">
<dl class="dl-horizontal">
<dt>Would you like to:</dt>
<dd>
<label class="radio"> <input type="radio"
name="radio-publish-existing" value="new">
Create a new Post
</label> <label class="radio"> <input type="radio"
name="radio-publish-existing" value="existing"> Edit an existing post
</label>
</dd>
</dl>
</div>
<div class="modal-footer">
<a href="#" class="btn" data-dismiss="modal">Cancel</a> <a href="#"
data-dismiss="modal" class="btn btn-primary action-publish-next">Next</a>
</div>
</div>
<div id="modal-publish-format" class="modal hide">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h3>Publish</h3>
</div>
<div class="modal-body">
<dl class="dl-horizontal">
<dt>Publish as:</dt>
<dd>
<label class="radio"> <input type="radio"
name="radio-publish-format" value="markdown">
Markdown format
</label> <label class="radio"> <input type="radio"
name="radio-publish-format" value="html"> HTML format
</label>
</dd>
</dl>
</div>
<div class="modal-footer">
<a href="#" class="btn" data-dismiss="modal">Cancel</a> <a href="#"
data-dismiss="modal" class="btn btn-primary action-publish-finish">OK</a>
</div>
</div>
<div id="modal-settings" class="modal hide"> <div id="modal-settings" class="modal hide">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" <button type="button" class="close" data-dismiss="modal"

View File

@ -271,7 +271,110 @@ define(["jquery", "bootstrap", "jgrowl", "layout", "Markdown.Editor"], function(
return x.join(''); return x.join('');
}; };
// CRC32 algorithm
var mHash = [ 0, 1996959894, 3993919788, 2567524794, 124634137,
1886057615, 3915621685, 2657392035, 249268274, 2044508324,
3772115230, 2547177864, 162941995, 2125561021, 3887607047,
2428444049, 498536548, 1789927666, 4089016648, 2227061214,
450548861, 1843258603, 4107580753, 2211677639, 325883990,
1684777152, 4251122042, 2321926636, 335633487, 1661365465,
4195302755, 2366115317, 997073096, 1281953886, 3579855332,
2724688242, 1006888145, 1258607687, 3524101629, 2768942443,
901097722, 1119000684, 3686517206, 2898065728, 853044451,
1172266101, 3705015759, 2882616665, 651767980, 1373503546,
3369554304, 3218104598, 565507253, 1454621731, 3485111705,
3099436303, 671266974, 1594198024, 3322730930, 2970347812,
795835527, 1483230225, 3244367275, 3060149565, 1994146192,
31158534, 2563907772, 4023717930, 1907459465, 112637215,
2680153253, 3904427059, 2013776290, 251722036, 2517215374,
3775830040, 2137656763, 141376813, 2439277719, 3865271297,
1802195444, 476864866, 2238001368, 4066508878, 1812370925,
453092731, 2181625025, 4111451223, 1706088902, 314042704,
2344532202, 4240017532, 1658658271, 366619977, 2362670323,
4224994405, 1303535960, 984961486, 2747007092, 3569037538,
1256170817, 1037604311, 2765210733, 3554079995, 1131014506,
879679996, 2909243462, 3663771856, 1141124467, 855842277,
2852801631, 3708648649, 1342533948, 654459306, 3188396048,
3373015174, 1466479909, 544179635, 3110523913, 3462522015,
1591671054, 702138776, 2966460450, 3352799412, 1504918807,
783551873, 3082640443, 3233442989, 3988292384, 2596254646,
62317068, 1957810842, 3939845945, 2647816111, 81470997, 1943803523,
3814918930, 2489596804, 225274430, 2053790376, 3826175755,
2466906013, 167816743, 2097651377, 4027552580, 2265490386,
503444072, 1762050814, 4150417245, 2154129355, 426522225,
1852507879, 4275313526, 2312317920, 282753626, 1742555852,
4189708143, 2394877945, 397917763, 1622183637, 3604390888,
2714866558, 953729732, 1340076626, 3518719985, 2797360999,
1068828381, 1219638859, 3624741850, 2936675148, 906185462,
1090812512, 3747672003, 2825379669, 829329135, 1181335161,
3412177804, 3160834842, 628085408, 1382605366, 3423369109,
3138078467, 570562233, 1426400815, 3317316542, 2998733608,
733239954, 1555261956, 3268935591, 3050360625, 752459403,
1541320221, 2607071920, 3965973030, 1969922972, 40735498,
2617837225, 3943577151, 1913087877, 83908371, 2512341634,
3803740692, 2075208622, 213261112, 2463272603, 3855990285,
2094854071, 198958881, 2262029012, 4057260610, 1759359992,
534414190, 2176718541, 4139329115, 1873836001, 414664567,
2282248934, 4279200368, 1711684554, 285281116, 2405801727,
4167216745, 1634467795, 376229701, 2685067896, 3608007406,
1308918612, 956543938, 2808555105, 3495958263, 1231636301,
1047427035, 2932959818, 3654703836, 1088359270, 936918000,
2847714899, 3736837829, 1202900863, 817233897, 3183342108,
3401237130, 1404277552, 615818150, 3134207493, 3453421203,
1423857449, 601450431, 3009837614, 3294710456, 1567103746,
711928724, 3020668471, 3272380065, 1510334235, 755167117 ];
core.crc32 = function(str) {
var n = 0, crc = -1;
for ( var i = 0; i < str.length; i++) {
n = (crc ^ str.charCodeAt(i)) & 0xFF;
crc = (crc >>> 8) ^ mHash[n];
}
crc = crc ^ (-1);
if (crc < 0) {
crc = 0xFFFFFFFF + crc + 1;
}
return crc.toString(16);
};
// Used to setup an empty localStorage
function setupLocalStorage() {
if (localStorage["file.counter"] === undefined
|| localStorage["file.list"] === undefined) {
localStorage["file.counter"] = "0";
localStorage["file.list"] = ";";
}
}
// Used to upgrade an existing localStorage
function upgradeLocalStorage() {
var version = localStorage["version"];
// from v0 to v1
if(version === undefined) {
var fileIndexList = localStorage["file.list"].split(";");
for ( var i = 1; i < fileIndexList.length - 1; i++) {
var fileIndex = fileIndexList[i];
localStorage[fileIndex + ".publish"] = ";";
var titleCRC = core.crc32(localStorage[fileIndex + ".title"]);
var contentCRC = core.crc32(localStorage[fileIndex + ".content"]);
var fileSyncIndexList = localStorage[fileIndex + ".sync"].split(";");
for ( var j = 1; j < fileSyncIndexList.length - 1; j++) {
var fileSyncIndex = fileSyncIndexList[j];
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
// We store title CRC only for Google Drive synchronization
if(localStorage[fileSyncIndex + ".etag"] !== undefined) {
localStorage[fileSyncIndex + ".titleCRC"] = titleCRC;
}
}
}
version = "v1";
}
localStorage["version"] = version;
}
core.init = function() { core.init = function() {
setupLocalStorage();
upgradeLocalStorage();
// jGrowl configuration // jGrowl configuration
$.jGrowl.defaults.life = 5000; $.jGrowl.defaults.life = 5000;

View File

@ -6,7 +6,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
var client = undefined; var client = undefined;
var authenticated = false; var authenticated = false;
var dropbox = {}; var dropboxHelper = {};
// Try to connect dropbox by downloading client.js // Try to connect dropbox by downloading client.js
function connect(callback) { function connect(callback) {
@ -24,7 +24,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
return; return;
} }
$.ajax({ $.ajax({
url : "js/dropbox.min.js", url : "lib/dropbox.js",
dataType : "script", timeout : AJAX_TIMEOUT dataType : "script", timeout : AJAX_TIMEOUT
}).done(function() { }).done(function() {
asyncTask.success(); asyncTask.success();
@ -96,7 +96,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
} }
dropbox.upload = function(path, content, callback) { dropboxHelper.upload = function(path, content, callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
authenticate(function() { authenticate(function() {
if (client === undefined) { if (client === undefined) {
@ -128,7 +128,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
dropbox.checkUpdates = function(lastChangeId, callback) { dropboxHelper.checkUpdates = function(lastChangeId, callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
authenticate(function() { authenticate(function() {
if (client === undefined) { if (client === undefined) {
@ -177,7 +177,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
dropbox.downloadMetadata = function(paths, callback, result) { dropboxHelper.downloadMetadata = function(paths, callback, result) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
result = result || []; result = result || [];
if(paths.length === 0) { if(paths.length === 0) {
@ -204,13 +204,13 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
asyncTask.onSuccess = function() { asyncTask.onSuccess = function() {
dropbox.downloadMetadata(paths, callback, result); dropboxHelper.downloadMetadata(paths, callback, result);
}; };
asyncTaskRunner.addTask(asyncTask); asyncTaskRunner.addTask(asyncTask);
}); });
}; };
dropbox.downloadContent = function(objects, callback, result) { dropboxHelper.downloadContent = function(objects, callback, result) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
result = result || []; result = result || [];
if(objects.length === 0) { if(objects.length === 0) {
@ -252,7 +252,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
asyncTask.onSuccess = function() { asyncTask.onSuccess = function() {
dropbox.downloadContent(objects, callback, result); dropboxHelper.downloadContent(objects, callback, result);
}; };
asyncTaskRunner.addTask(asyncTask); asyncTaskRunner.addTask(asyncTask);
}); });
@ -322,7 +322,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
} }
dropbox.picker = function(callback) { dropboxHelper.picker = function(callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
loadPicker(function() { loadPicker(function() {
if (pickerLoaded === false) { if (pickerLoaded === false) {
@ -349,12 +349,12 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
dropbox.importFiles = function(paths) { dropboxHelper.importFiles = function(paths) {
dropbox.downloadMetadata(paths, function(result) { dropboxHelper.downloadMetadata(paths, function(result) {
if(result === undefined) { if(result === undefined) {
return; return;
} }
dropbox.downloadContent(result, function(result) { dropboxHelper.downloadContent(result, function(result) {
if(result === undefined) { if(result === undefined) {
return; return;
} }
@ -362,6 +362,8 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
var file = result[i]; var file = result[i];
fileSyncIndex = SYNC_PROVIDER_DROPBOX + encodeURIComponent(file.path.toLowerCase()); fileSyncIndex = SYNC_PROVIDER_DROPBOX + encodeURIComponent(file.path.toLowerCase());
localStorage[fileSyncIndex + ".version"] = file.versionTag; localStorage[fileSyncIndex + ".version"] = file.versionTag;
var contentCRC = core.crc32(file.content);
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
var fileIndex = fileManager.createFile(file.name, file.content, [fileSyncIndex]); var fileIndex = fileManager.createFile(file.name, file.content, [fileSyncIndex]);
fileManager.selectFile(fileIndex); fileManager.selectFile(fileIndex);
core.showMessage('"' + file.name + '" imported successfully from Dropbox.'); core.showMessage('"' + file.name + '" imported successfully from Dropbox.');
@ -370,11 +372,11 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
dropbox.init = function(fileManagerModule) { dropboxHelper.init = function(fileManagerModule) {
fileManager = fileManagerModule; fileManager = fileManagerModule;
}; };
dropbox.checkPath = function(path) { dropboxHelper.checkPath = function(path) {
if(!path.match(/^[^\\<>:"\|?\*]+$/)) { if(!path.match(/^[^\\<>:"\|?\*]+$/)) {
core.showError('"' + path + '" contains invalid characters.'); core.showError('"' + path + '" contains invalid characters.');
return undefined; return undefined;
@ -385,5 +387,5 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
return path; return path;
}; };
return dropbox; return dropboxHelper;
}); });

5
js/dropbox.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -1,11 +1,12 @@
define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"], define(["jquery", "core", "google-helper", "dropbox-helper", "synchronizer", "publisher", "async-runner"],
function($, core, gdrive, dropbox, synchronizer, asyncTaskRunner) { function($, core, googleHelper, dropboxHelper, synchronizer, publisher, asyncTaskRunner) {
var fileManager = {}; var fileManager = {};
fileManager.init = function() { fileManager.init = function() {
gdrive.init(fileManager); googleHelper.init(fileManager);
dropbox.init(fileManager); dropboxHelper.init(fileManager);
publisher.init(fileManager);
var changeSyncButtonState = function() { var changeSyncButtonState = function() {
if(synchronizer.isRunning() || synchronizer.isQueueEmpty() || core.isOffline) { if(synchronizer.isRunning() || synchronizer.isQueueEmpty() || core.isOffline) {
@ -83,21 +84,21 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
$(".action-upload-gdrive-select").click(function() { $(".action-upload-gdrive-select").click(function() {
// This action is not available because picker does not support // This action is not available because picker does not support
// folder selection yet // folder selection yet
gdrive.picker(function(ids) { googleHelper.picker(function(ids) {
if(ids !== undefined && ids.length !== 0) { if(ids !== undefined && ids.length !== 0) {
uploadGdrive(ids[0]); uploadGdrive(undefined, ids[0]);
} }
}, true); }, true);
}); });
$(".action-download-gdrive").click(function() { $(".action-download-gdrive").click(function() {
gdrive.picker(importGdrive); googleHelper.picker(importGdrive);
}); });
$(".action-manual-gdrive").click(function(event) { $(".action-manual-gdrive").click(function(event) {
var fileId = core.getInputValue($("#manual-gdrive-fileid"), event); var fileId = core.getInputValue($("#manual-gdrive-fileid"), event);
manualGdrive(fileId); manualGdrive(fileId);
}); });
$(".action-download-dropbox").click(function() { $(".action-download-dropbox").click(function() {
dropbox.picker(importDropbox); dropboxHelper.picker(importDropbox);
}); });
$(".action-upload-dropbox").click(function(event) { $(".action-upload-dropbox").click(function(event) {
var path = core.getInputValue($("#upload-dropbox-path"), event); var path = core.getInputValue($("#upload-dropbox-path"), event);
@ -112,12 +113,6 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
// Caution: this function recreate the editor (reset undo operations) // Caution: this function recreate the editor (reset undo operations)
var fileDescList = []; var fileDescList = [];
fileManager.selectFile = function(fileIndex) { fileManager.selectFile = function(fileIndex) {
// If file system does not exist
if (!localStorage["file.counter"] || !localStorage["file.list"]) {
localStorage.clear();
localStorage["file.counter"] = 0;
localStorage["file.list"] = ";";
}
// If no file create one // If no file create one
if (localStorage["file.list"].length === 1) { if (localStorage["file.list"].length === 1) {
fileIndex = this.createFile(); fileIndex = this.createFile();
@ -169,6 +164,7 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
sync += syncIndexes[i] + ";"; sync += syncIndexes[i] + ";";
} }
localStorage[fileIndex + ".sync"] = sync; localStorage[fileIndex + ".sync"] = sync;
localStorage[fileIndex + ".publish"] = ";";
localStorage["file.counter"] = fileCounter + 1; localStorage["file.counter"] = fileCounter + 1;
localStorage["file.list"] += fileIndex + ";"; localStorage["file.list"] += fileIndex + ";";
return fileIndex; return fileIndex;
@ -282,10 +278,11 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
refreshManageSync(); refreshManageSync();
} }
} }
// Remove Google Drive etag // Remove ETAG, version, CRCs (if any)
localStorage.removeItem(fileSyncIndex + ".etag"); localStorage.removeItem(fileSyncIndex + ".etag");
// Remove Dropbox version
localStorage.removeItem(fileSyncIndex + ".version"); localStorage.removeItem(fileSyncIndex + ".version");
localStorage.removeItem(fileSyncIndex + ".contentCRC");
localStorage.removeItem(fileSyncIndex + ".titleCRC");
}; };
// Look for local file associated to a synchronized location // Look for local file associated to a synchronized location
@ -303,14 +300,18 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
return fileIndex; return fileIndex;
}; };
function uploadGdrive(folderId) { function uploadGdrive(fileId, folderId) {
var fileIndex = localStorage["file.current"]; var fileIndex = localStorage["file.current"];
var content = localStorage[fileIndex + ".content"]; var content = localStorage[fileIndex + ".content"];
var title = localStorage[fileIndex + ".title"]; var title = localStorage[fileIndex + ".title"];
gdrive.upload(undefined, folderId, title, content, function(fileSyncIndex) { googleHelper.upload(fileId, folderId, title, content, function(fileSyncIndex) {
if (fileSyncIndex === undefined) { if (fileSyncIndex === undefined) {
return; return;
} }
var contentCRC = core.crc32(content);
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
var titleCRC = core.crc32(title);
localStorage[fileSyncIndex + ".titleCRC"] = titleCRC;
localStorage[fileIndex + ".sync"] += fileSyncIndex + ";"; localStorage[fileIndex + ".sync"] += fileSyncIndex + ";";
refreshManageSync(); refreshManageSync();
fileManager.updateFileTitles(); fileManager.updateFileTitles();
@ -319,6 +320,21 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
}); });
} }
function manualGdrive(fileId) {
if(!fileId) {
return;
}
// Check that file is not synchronized with an other one
var fileSyncIndex = SYNC_PROVIDER_GDRIVE + fileId;
var fileIndex = fileManager.getFileIndexFromSync(fileSyncIndex);
if(fileIndex !== undefined) {
var title = localStorage[fileIndex + ".title"];
core.showError('File ID is already synchronized with "' + title + '"');
return;
}
uploadGdrive(fileId);
}
function importGdrive(ids) { function importGdrive(ids) {
if(ids === undefined) { if(ids === undefined) {
return; return;
@ -335,44 +351,14 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
} }
importIds.push(fileId); importIds.push(fileId);
} }
gdrive.importFiles(importIds); googleHelper.importFiles(importIds);
}
function manualGdrive(fileId) {
if(!fileId) {
return;
}
// Check that file is not synchronized with an other one
var fileSyncIndex = SYNC_PROVIDER_GDRIVE + fileId;
var fileIndex = fileManager.getFileIndexFromSync(fileSyncIndex);
if(fileIndex !== undefined) {
var title = localStorage[fileIndex + ".title"];
core.showError('File ID is already synchronized with "' + title + '"');
return;
}
var fileIndex = localStorage["file.current"];
var title = localStorage[fileIndex + ".title"];
gdrive.downloadMetadata([fileId], function(result) {
if(result === undefined || result.length === 0) {
return;
}
localStorage[fileSyncIndex + ".etag"] = result[0].etag;
localStorage[fileIndex + ".sync"] += fileSyncIndex + ";";
refreshManageSync();
fileManager.updateFileTitles();
core.showMessage('"' + title
+ '" will now be synchronized on Google Drive.');
// Force synchronization
synchronizer.addFileForUpload(fileIndex);
synchronizer.forceSync();
});
} }
function manualDropbox(path) { function manualDropbox(path) {
if(!path) { if(!path) {
return; return;
} }
path = dropbox.checkPath(path); path = dropboxHelper.checkPath(path);
if(path === undefined) { if(path === undefined) {
return; return;
} }
@ -387,10 +373,12 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
var fileIndex = localStorage["file.current"]; var fileIndex = localStorage["file.current"];
var content = localStorage[fileIndex + ".content"]; var content = localStorage[fileIndex + ".content"];
var title = localStorage[fileIndex + ".title"]; var title = localStorage[fileIndex + ".title"];
dropbox.upload(path, content, function(fileSyncIndex) { dropboxHelper.upload(path, content, function(fileSyncIndex) {
if (fileSyncIndex === undefined) { if (fileSyncIndex === undefined) {
return; return;
} }
var contentCRC = core.crc32(content);
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
localStorage[fileIndex + ".sync"] += fileSyncIndex + ";"; localStorage[fileIndex + ".sync"] += fileSyncIndex + ";";
refreshManageSync(); refreshManageSync();
fileManager.updateFileTitles(); fileManager.updateFileTitles();
@ -415,7 +403,7 @@ define(["jquery", "core", "gdrive", "dropbox", "synchronizer", "async-runner"],
} }
importPaths.push(filePath); importPaths.push(filePath);
} }
dropbox.importFiles(importPaths); dropboxHelper.importFiles(importPaths);
} }
function refreshManageSync() { function refreshManageSync() {

10
js/github.js Normal file
View File

@ -0,0 +1,10 @@
define(["jquery", "core", "async-runner", "underscore-min"], function($, core, asyncTaskRunner) {
var client = undefined;
var authenticated = false;
var github = {};
});

View File

@ -6,7 +6,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
var connected = false; var connected = false;
var authenticated = false; var authenticated = false;
var gdrive = {}; var googleHelper = {};
// Try to connect Gdrive by downloading client.js // Try to connect Gdrive by downloading client.js
function connect(callback) { function connect(callback) {
@ -97,7 +97,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
} }
gdrive.upload = function(fileId, parentId, title, content, callback) { googleHelper.upload = function(fileId, parentId, title, content, callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
authenticate(function() { authenticate(function() {
if (connected === false) { if (connected === false) {
@ -151,17 +151,10 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
return; return;
} }
var error = response.error; var error = response.error;
// If it's an update and file has been removed from Google Drive
if(error !== undefined && fileId !== undefined && error.code === 404) {
core.showMessage('"' + title + '" has been removed from Google Drive.');
fileManager.removeSync(SYNC_PROVIDER_GDRIVE + fileId);
fileManager.updateFileTitles();
// We assume it's not error
fileSyncIndex = null;
asyncTask.success();
return;
}
// Handle error // Handle error
if(error !== undefined && fileId !== undefined && error.code === 404) {
error = 'File ID "' + fileId + '" does not exist on Google Drive.';
}
handleError(error, asyncTask, callback); handleError(error, asyncTask, callback);
}); });
}; };
@ -172,7 +165,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
gdrive.checkUpdates = function(lastChangeId, callback) { googleHelper.checkUpdates = function(lastChangeId, callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
authenticate(function() { authenticate(function() {
if (connected === false) { if (connected === false) {
@ -226,7 +219,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
gdrive.downloadMetadata = function(ids, callback, result) { googleHelper.downloadMetadata = function(ids, callback, result) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
result = result || []; result = result || [];
if(ids.length === 0) { if(ids.length === 0) {
@ -268,13 +261,13 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
asyncTask.onSuccess = function() { asyncTask.onSuccess = function() {
gdrive.downloadMetadata(ids, callback, result); googleHelper.downloadMetadata(ids, callback, result);
}; };
asyncTaskRunner.addTask(asyncTask); asyncTaskRunner.addTask(asyncTask);
}); });
}; };
gdrive.downloadContent = function(objects, callback, result) { googleHelper.downloadContent = function(objects, callback, result) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
result = result || []; result = result || [];
if(objects.length === 0) { if(objects.length === 0) {
@ -328,7 +321,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
asyncTask.onSuccess = function() { asyncTask.onSuccess = function() {
gdrive.downloadContent(objects, callback, result); googleHelper.downloadContent(objects, callback, result);
}; };
asyncTaskRunner.addTask(asyncTask); asyncTaskRunner.addTask(asyncTask);
}); });
@ -404,7 +397,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
} }
gdrive.picker = function(callback) { googleHelper.picker = function(callback) {
callback = callback || core.doNothing; callback = callback || core.doNothing;
loadPicker(function() { loadPicker(function() {
if (pickerLoaded === false) { if (pickerLoaded === false) {
@ -446,12 +439,12 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
gdrive.importFiles = function(ids) { googleHelper.importFiles = function(ids) {
gdrive.downloadMetadata(ids, function(result) { googleHelper.downloadMetadata(ids, function(result) {
if(result === undefined) { if(result === undefined) {
return; return;
} }
gdrive.downloadContent(result, function(result) { googleHelper.downloadContent(result, function(result) {
if(result === undefined) { if(result === undefined) {
return; return;
} }
@ -459,6 +452,10 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
var file = result[i]; var file = result[i];
fileSyncIndex = SYNC_PROVIDER_GDRIVE + file.id; fileSyncIndex = SYNC_PROVIDER_GDRIVE + file.id;
localStorage[fileSyncIndex + ".etag"] = file.etag; localStorage[fileSyncIndex + ".etag"] = file.etag;
var contentCRC = core.crc32(file.content);
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
var titleCRC = core.crc32(file.title);
localStorage[fileSyncIndex + ".titleCRC"] = titleCRC;
var fileIndex = fileManager.createFile(file.title, file.content, [fileSyncIndex]); var fileIndex = fileManager.createFile(file.title, file.content, [fileSyncIndex]);
fileManager.selectFile(fileIndex); fileManager.selectFile(fileIndex);
core.showMessage('"' + file.title + '" imported successfully from Google Drive.'); core.showMessage('"' + file.title + '" imported successfully from Google Drive.');
@ -467,7 +464,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
}); });
}; };
gdrive.init = function(fileManagerModule) { googleHelper.init = function(fileManagerModule) {
fileManager = fileManagerModule; fileManager = fileManagerModule;
var state = localStorage["sync.gdrive.state"]; var state = localStorage["sync.gdrive.state"];
if(state === undefined) { if(state === undefined) {
@ -476,11 +473,15 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
localStorage.removeItem("sync.gdrive.state"); localStorage.removeItem("sync.gdrive.state");
state = JSON.parse(state); state = JSON.parse(state);
if (state.action == "create") { if (state.action == "create") {
gdrive.upload(undefined, state.folderId, GDRIVE_DEFAULT_FILE_TITLE, googleHelper.upload(undefined, state.folderId, GDRIVE_DEFAULT_FILE_TITLE,
"", function(fileSyncIndex) { "", function(fileSyncIndex) {
if(fileSyncIndex === undefined) { if(fileSyncIndex === undefined) {
return; return;
} }
var contentCRC = core.crc32("");
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
var titleCRC = core.crc32(GDRIVE_DEFAULT_FILE_TITLE);
localStorage[fileSyncIndex + ".titleCRC"] = titleCRC;
var fileIndex = fileManager.createFile(GDRIVE_DEFAULT_FILE_TITLE, "", [fileSyncIndex]); var fileIndex = fileManager.createFile(GDRIVE_DEFAULT_FILE_TITLE, "", [fileSyncIndex]);
fileManager.selectFile(fileIndex); fileManager.selectFile(fileIndex);
core.showMessage('"' + GDRIVE_DEFAULT_FILE_TITLE + '" created successfully on Google Drive.'); core.showMessage('"' + GDRIVE_DEFAULT_FILE_TITLE + '" created successfully on Google Drive.');
@ -498,9 +499,9 @@ define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
ids.push(id); ids.push(id);
} }
} }
gdrive.importFiles(ids); googleHelper.importFiles(ids);
} }
}; };
return gdrive; return googleHelper;
}); });

37
js/publisher.js Normal file
View File

@ -0,0 +1,37 @@
define(["jquery", "core", "async-runner"], function($, core, asyncTaskRunner) {
// Dependencies
var fileManager = undefined;
var publisher = {};
var wizardProvider = undefined;
function initWizard(provider) {
wizardProvider = provider;
$("input:radio[name=radio-publish-existing][value=new]").prop("checked", true);
$("input:radio[name=radio-publish-format][value=markdown]").prop("checked", true);
}
publisher.init = function(fileManagerModule) {
fileManager = fileManagerModule;
$("#action-publish-github").click(function() {
initWizard("github");
});
$("#action-publish-blogger").click(function() {
initWizard("blogger");
});
$("#action-publish-wordpress").click(function() {
initWizard("wordpress");
});
$("#action-publish-tumblr").click(function() {
initWizard("tumblr");
});
};
publisher.initWizard = function() {
};
return publisher;
});

View File

@ -1,4 +1,4 @@
define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbox) { define(["jquery", "core", "google-helper", "dropbox-helper"], function($, core, googleHelper, dropboxHelper) {
var synchronizer = {}; var synchronizer = {};
// Dependencies // Dependencies
@ -49,7 +49,7 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
}; };
// Recursive function to upload a single file on multiple locations // Recursive function to upload a single file on multiple locations
function fileUp(fileSyncIndexList, content, title, callback) { function fileUp(fileSyncIndexList, content, contentCRC, title, titleCRC, callback) {
if (fileSyncIndexList.length === 0) { if (fileSyncIndexList.length === 0) {
localStorage.removeItem("sync.current"); localStorage.removeItem("sync.current");
// run the next file synchronization // run the next file synchronization
@ -58,12 +58,22 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
} }
var fileSyncIndex = fileSyncIndexList.pop(); var fileSyncIndex = fileSyncIndexList.pop();
// Skip if CRC has not changed
var syncContentCRC = localStorage[fileSyncIndex + ".contentCRC"];
var syncTitleCRC = localStorage[fileSyncIndex + ".titleCRC"];
if(contentCRC == syncContentCRC && (syncTitleCRC === undefined || titleCRC == syncTitleCRC)) {
fileUp(fileSyncIndexList, content, contentCRC, title, titleCRC, callback);
return;
}
// Try to find the provider // Try to find the provider
if (fileSyncIndex.indexOf(SYNC_PROVIDER_GDRIVE) === 0) { if (fileSyncIndex.indexOf(SYNC_PROVIDER_GDRIVE) === 0) {
var id = fileSyncIndex.substring(SYNC_PROVIDER_GDRIVE.length); var id = fileSyncIndex.substring(SYNC_PROVIDER_GDRIVE.length);
gdrive.upload(id, undefined, title, content, function(result) { googleHelper.upload(id, undefined, title, content, function(result) {
if (result !== undefined) { if (result !== undefined) {
fileUp(fileSyncIndexList, content, title, callback); localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
localStorage[fileSyncIndex + ".titleCRC"] = titleCRC;
fileUp(fileSyncIndexList, content, contentCRC, title, titleCRC, callback);
return; return;
} }
// If error we put the fileIndex back in the queue // If error we put the fileIndex back in the queue
@ -75,9 +85,10 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
} else if (fileSyncIndex.indexOf(SYNC_PROVIDER_DROPBOX) === 0) { } else if (fileSyncIndex.indexOf(SYNC_PROVIDER_DROPBOX) === 0) {
var path = fileSyncIndex.substring(SYNC_PROVIDER_DROPBOX.length); var path = fileSyncIndex.substring(SYNC_PROVIDER_DROPBOX.length);
path = decodeURIComponent(path); path = decodeURIComponent(path);
dropbox.upload(path, content, function(result) { dropboxHelper.upload(path, content, function(result) {
if (result !== undefined) { if (result !== undefined) {
fileUp(fileSyncIndexList, content, title, callback); localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
fileUp(fileSyncIndexList, content, contentCRC, title, titleCRC, callback);
return; return;
} }
// If error we put the fileIndex back in the queue // If error we put the fileIndex back in the queue
@ -87,7 +98,7 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
return; return;
}); });
} else { } else {
fileUp(fileSyncIndexList, content, title, callback); fileUp(fileSyncIndexList, content, contentCRC, title, titleCRC, callback);
} }
} }
@ -108,10 +119,12 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
var content = localStorage[fileIndex + ".content"]; var content = localStorage[fileIndex + ".content"];
var title = localStorage[fileIndex + ".title"]; var title = localStorage[fileIndex + ".title"];
var contentCRC = core.crc32(content);
var titleCRC = core.crc32(title);
// Parse the list of synchronized locations associated to the file // Parse the list of synchronized locations associated to the file
var fileSyncIndexList = localStorage[fileIndex + ".sync"].split(";"); var fileSyncIndexList = localStorage[fileIndex + ".sync"].split(";");
fileUp(fileSyncIndexList, content, title, callback); fileUp(fileSyncIndexList, content, contentCRC, title, titleCRC, callback);
}; };
function syncDownGdrive(callback) { function syncDownGdrive(callback) {
@ -121,12 +134,12 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
} }
var lastChangeId = parseInt(localStorage[SYNC_PROVIDER_GDRIVE var lastChangeId = parseInt(localStorage[SYNC_PROVIDER_GDRIVE
+ "lastChangeId"]); + "lastChangeId"]);
gdrive.checkUpdates(lastChangeId, function(changes, newChangeId) { googleHelper.checkUpdates(lastChangeId, function(changes, newChangeId) {
if (changes === undefined) { if (changes === undefined) {
callback(); callback();
return; return;
} }
gdrive.downloadContent(changes, function(changes) { googleHelper.downloadContent(changes, function(changes) {
if (changes === undefined) { if (changes === undefined) {
callback(); callback();
return; return;
@ -175,9 +188,14 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
fileManager.selectFile(); // Refresh editor fileManager.selectFile(); // Refresh editor
} }
} }
// Update file etag // Update file etag and CRCs
localStorage[fileSyncIndex + ".etag"] = file.etag; localStorage[fileSyncIndex + ".etag"] = file.etag;
// Synchronize file to others locations var contentCRC = core.crc32(file.content);
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
var titleCRC = core.crc32(file.title);
localStorage[fileSyncIndex + ".titleCRC"] = titleCRC;
// Synchronize file with others locations
synchronizer.addFileForUpload(fileIndex); synchronizer.addFileForUpload(fileIndex);
} }
if(updateFileTitles) { if(updateFileTitles) {
@ -196,12 +214,12 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
return; return;
} }
var lastChangeId = localStorage[SYNC_PROVIDER_DROPBOX + "lastChangeId"]; var lastChangeId = localStorage[SYNC_PROVIDER_DROPBOX + "lastChangeId"];
dropbox.checkUpdates(lastChangeId, function(changes, newChangeId) { dropboxHelper.checkUpdates(lastChangeId, function(changes, newChangeId) {
if (changes === undefined) { if (changes === undefined) {
callback(); callback();
return; return;
} }
dropbox.downloadContent(changes, function(changes) { dropboxHelper.downloadContent(changes, function(changes) {
if (changes === undefined) { if (changes === undefined) {
callback(); callback();
return; return;
@ -243,9 +261,12 @@ define(["jquery", "core", "gdrive", "dropbox"], function($, core, gdrive, dropbo
fileManager.selectFile(); // Refresh editor fileManager.selectFile(); // Refresh editor
} }
} }
// Update file version // Update file version and CRC
localStorage[fileSyncIndex + ".version"] = file.versionTag; localStorage[fileSyncIndex + ".version"] = file.versionTag;
// Synchronize file to others locations var contentCRC = core.crc32(file.content);
localStorage[fileSyncIndex + ".contentCRC"] = contentCRC;
// Synchronize file with others locations
synchronizer.addFileForUpload(fileIndex); synchronizer.addFileForUpload(fileIndex);
} }
if(updateFileTitles) { if(updateFileTitles) {

5
js/underscore-min.js vendored Normal file

File diff suppressed because one or more lines are too long

3399
lib/dropbox.js Normal file

File diff suppressed because it is too large Load Diff

499
lib/github.js Normal file
View File

@ -0,0 +1,499 @@
// Github.js 0.7.0
// (c) 2012 Michael Aufreiter, Development Seed
// Github.js is freely distributable under the MIT license.
// For all details and documentation:
// http://substance.io/michael/github
(function() {
var Github;
var API_URL = 'https://api.github.com';
Github = window.Github = function(options) {
// HTTP Request Abstraction
// =======
//
// I'm not proud of this and neither should you be if you were responsible for the XMLHttpRequest spec.
function _request(method, path, data, cb, raw) {
function getURL() {
var url = API_URL + path;
return url + ((/\?/).test(url) ? "&" : "?") + (new Date()).getTime();
}
var xhr = new XMLHttpRequest();
if (!raw) {xhr.dataType = "json";}
xhr.open(method, getURL());
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status >= 200 && this.status < 300 || this.status === 304) {
cb(null, raw ? this.responseText : this.responseText ? JSON.parse(this.responseText) : true);
} else {
cb({request: this, error: this.status});
}
}
};
xhr.setRequestHeader('Accept','application/vnd.github.raw');
xhr.setRequestHeader('Content-Type','application/json');
if (
(options.auth == 'oauth' && options.token) ||
(options.auth == 'basic' && options.username && options.password)
) {
xhr.setRequestHeader('Authorization',options.auth == 'oauth'
? 'token '+ options.token
: 'Basic ' + Base64.encode(options.username + ':' + options.password)
);
}
data ? xhr.send(JSON.stringify(data)) : xhr.send();
}
// User API
// =======
Github.User = function() {
this.repos = function(cb) {
_request("GET", "/user/repos?type=all&per_page=1000&sort=updated", null, function(err, res) {
cb(err, res);
});
};
// List user organizations
// -------
this.orgs = function(cb) {
_request("GET", "/user/orgs", null, function(err, res) {
cb(err, res);
});
};
// List authenticated user's gists
// -------
this.gists = function(cb) {
_request("GET", "/gists", null, function(err, res) {
cb(err,res);
});
};
// Show user information
// -------
this.show = function(username, cb) {
var command = username ? "/users/"+username : "/user";
_request("GET", command, null, function(err, res) {
cb(err, res);
});
};
// List user repositories
// -------
this.userRepos = function(username, cb) {
_request("GET", "/users/"+username+"/repos?type=all&per_page=1000&sort=updated", null, function(err, res) {
cb(err, res);
});
};
// List a user's gists
// -------
this.userGists = function(username, cb) {
_request("GET", "/users/"+username+"/gists", null, function(err, res) {
cb(err,res);
});
};
// List organization repositories
// -------
this.orgRepos = function(orgname, cb) {
_request("GET", "/orgs/"+orgname+"/repos?type=all&per_page=1000&sort=updated&direction=desc", null, function(err, res) {
cb(err, res);
});
};
// Follow user
// -------
this.follow = function(username, cb) {
_request("PUT", "/user/following/"+username, null, function(err, res) {
cb(err, res);
});
};
// Unfollow user
// -------
this.unfollow = function(username, cb) {
_request("DELETE", "/user/following/"+username, null, function(err, res) {
cb(err, res);
});
};
};
// Repository API
// =======
Github.Repository = function(options) {
var repo = options.name;
var user = options.user;
var that = this;
var repoPath = "/repos/" + user + "/" + repo;
var currentTree = {
"branch": null,
"sha": null
};
// Uses the cache if branch has not been changed
// -------
function updateTree(branch, cb) {
if (branch === currentTree.branch && currentTree.sha) return cb(null, currentTree.sha);
that.getRef("heads/"+branch, function(err, sha) {
currentTree.branch = branch;
currentTree.sha = sha;
cb(err, sha);
});
}
// Get a particular reference
// -------
this.getRef = function(ref, cb) {
_request("GET", repoPath + "/git/refs/" + ref, null, function(err, res) {
if (err) return cb(err);
cb(null, res.object.sha);
});
};
// Create a new reference
// --------
//
// {
// "ref": "refs/heads/my-new-branch-name",
// "sha": "827efc6d56897b048c772eb4087f854f46256132"
// }
this.createRef = function(options, cb) {
_request("POST", repoPath + "/git/refs", options, cb);
};
// Delete a reference
// --------
//
// repo.deleteRef('heads/gh-pages')
// repo.deleteRef('tags/v1.0')
this.deleteRef = function(ref, cb) {
_request("DELETE", repoPath + "/git/refs/"+ref, options, cb);
};
// List all branches of a repository
// -------
this.listBranches = function(cb) {
_request("GET", repoPath + "/git/refs/heads", null, function(err, heads) {
if (err) return cb(err);
cb(null, _.map(heads, function(head) { return _.last(head.ref.split('/')); }));
});
};
// Retrieve the contents of a blob
// -------
this.getBlob = function(sha, cb) {
_request("GET", repoPath + "/git/blobs/" + sha, null, cb, 'raw');
};
// For a given file path, get the corresponding sha (blob for files, tree for dirs)
// -------
this.getSha = function(branch, path, cb) {
// Just use head if path is empty
if (path === "") return that.getRef("heads/"+branch, cb);
that.getTree(branch+"?recursive=true", function(err, tree) {
var file = _.select(tree, function(file) {
return file.path === path;
})[0];
cb(null, file ? file.sha : null);
});
};
// Retrieve the tree a commit points to
// -------
this.getTree = function(tree, cb) {
_request("GET", repoPath + "/git/trees/"+tree, null, function(err, res) {
if (err) return cb(err);
cb(null, res.tree);
});
};
// Post a new blob object, getting a blob SHA back
// -------
this.postBlob = function(content, cb) {
if (typeof(content) === "string") {
content = {
"content": content,
"encoding": "utf-8"
};
}
_request("POST", repoPath + "/git/blobs", content, function(err, res) {
if (err) return cb(err);
cb(null, res.sha);
});
};
// Update an existing tree adding a new blob object getting a tree SHA back
// -------
this.updateTree = function(baseTree, path, blob, cb) {
var data = {
"base_tree": baseTree,
"tree": [
{
"path": path,
"mode": "100644",
"type": "blob",
"sha": blob
}
]
};
_request("POST", repoPath + "/git/trees", data, function(err, res) {
if (err) return cb(err);
cb(null, res.sha);
});
};
// Post a new tree object having a file path pointer replaced
// with a new blob SHA getting a tree SHA back
// -------
this.postTree = function(tree, cb) {
_request("POST", repoPath + "/git/trees", { "tree": tree }, function(err, res) {
if (err) return cb(err);
cb(null, res.sha);
});
};
// Create a new commit object with the current commit SHA as the parent
// and the new tree SHA, getting a commit SHA back
// -------
this.commit = function(parent, tree, message, cb) {
var data = {
"message": message,
"author": {
"name": options.username
},
"parents": [
parent
],
"tree": tree
};
_request("POST", repoPath + "/git/commits", data, function(err, res) {
currentTree.sha = res.sha; // update latest commit
if (err) return cb(err);
cb(null, res.sha);
});
};
// Update the reference of your head to point to the new commit SHA
// -------
this.updateHead = function(head, commit, cb) {
_request("PATCH", repoPath + "/git/refs/heads/" + head, { "sha": commit }, function(err, res) {
cb(err);
});
};
// Show repository information
// -------
this.show = function(cb) {
_request("GET", repoPath, null, cb);
};
// Get contents
// --------
this.contents = function(branch, path, cb) {
_request("GET", repoPath + "/contents?ref=" + branch, { path: path }, cb);
};
// Fork repository
// -------
this.fork = function(cb) {
_request("POST", repoPath + "/forks", null, cb);
};
// Create pull request
// --------
this.createPullRequest = function(options, cb) {
_request("POST", repoPath + "/pulls", options, cb);
};
// Read file at given path
// -------
this.read = function(branch, path, cb) {
that.getSha(branch, path, function(err, sha) {
if (!sha) return cb("not found", null);
that.getBlob(sha, function(err, content) {
cb(err, content, sha);
});
});
};
// Remove a file from the tree
// -------
this.remove = function(branch, path, cb) {
updateTree(branch, function(err, latestCommit) {
that.getTree(latestCommit+"?recursive=true", function(err, tree) {
// Update Tree
var newTree = _.reject(tree, function(ref) { return ref.path === path; });
_.each(newTree, function(ref) {
if (ref.type === "tree") delete ref.sha;
});
that.postTree(newTree, function(err, rootTree) {
that.commit(latestCommit, rootTree, 'Deleted '+path , function(err, commit) {
that.updateHead(branch, commit, function(err) {
cb(err);
});
});
});
});
});
};
// Move a file to a new location
// -------
this.move = function(branch, path, newPath, cb) {
updateTree(branch, function(err, latestCommit) {
that.getTree(latestCommit+"?recursive=true", function(err, tree) {
// Update Tree
_.each(tree, function(ref) {
if (ref.path === path) ref.path = newPath;
if (ref.type === "tree") delete ref.sha;
});
that.postTree(tree, function(err, rootTree) {
that.commit(latestCommit, rootTree, 'Deleted '+path , function(err, commit) {
that.updateHead(branch, commit, function(err) {
cb(err);
});
});
});
});
});
};
// Write file contents to a given branch and path
// -------
this.write = function(branch, path, content, message, cb) {
updateTree(branch, function(err, latestCommit) {
if (err) return cb(err);
that.postBlob(content, function(err, blob) {
if (err) return cb(err);
that.updateTree(latestCommit, path, blob, function(err, tree) {
if (err) return cb(err);
that.commit(latestCommit, tree, message, function(err, commit) {
if (err) return cb(err);
that.updateHead(branch, commit, cb);
});
});
});
});
};
};
// Gists API
// =======
Github.Gist = function(options) {
var id = options.id;
var gistPath = "/gists/"+id;
// Read the gist
// --------
this.read = function(cb) {
_request("GET", gistPath, null, function(err, gist) {
cb(err, gist);
});
};
// Create the gist
// --------
// {
// "description": "the description for this gist",
// "public": true,
// "files": {
// "file1.txt": {
// "content": "String file contents"
// }
// }
// }
this.create = function(options, cb){
_request("POST","/gists", options, cb);
};
// Delete the gist
// --------
this.delete = function(cb) {
_request("DELETE", gistPath, null, function(err,res) {
cb(err,res);
});
};
// Fork a gist
// --------
this.fork = function(cb) {
_request("POST", gistPath+"/fork", null, function(err,res) {
cb(err,res);
});
};
// Update a gist with the new stuff
// --------
this.update = function(options, cb) {
_request("PATCH", gistPath, options, function(err,res) {
cb(err,res);
});
};
};
// Top Level API
// -------
this.getRepo = function(user, repo) {
return new Github.Repository({user: user, name: repo});
};
this.getUser = function() {
return new Github.User();
};
this.getGist = function(id) {
return new Github.Gist({id: id});
};
};
}).call(this);