SSH server publishing

This commit is contained in:
benweet 2013-05-19 19:56:15 +01:00
parent a010366a4d
commit 383adfb032
16 changed files with 325 additions and 72 deletions

11
css/bootstrap.css vendored
View File

@ -1,5 +1,5 @@
/*! /*!
* Bootstrap v2.3.0 * Bootstrap v2.3.2
* *
* Copyright 2012 Twitter, Inc * Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0 * Licensed under the Apache License v2.0
@ -3009,6 +3009,15 @@ table th[class*="span"],
display: block; display: block;
} }
.dropdown-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 990;
}
.pull-right > .dropdown-menu { .pull-right > .dropdown-menu {
right: 0; right: 0;
left: auto; left: auto;

View File

@ -51,12 +51,12 @@ div, span, a, ul, li, textarea, input, button {
} }
.dropdown-menu { .dropdown-menu {
border: 1px solid #e2e2e2 !important; border: 1px solid #ddd !important;
text-align: left; text-align: left;
} }
.dropdown-menu:before { .dropdown-menu:before {
border-bottom-color: #e2e2e2 !important; border-bottom-color: #ddd !important;
} }
input, input,
@ -64,7 +64,33 @@ select,
textarea, textarea,
.input-prepend .btn, .input-prepend .btn,
.input-prepend .add-on { .input-prepend .add-on {
border: 1px solid #ebebeb !important; border: 1px solid #ddd !important;
}
textarea:focus,
input[type="text"]:focus,
input[type="password"]:focus,
input[type="datetime"]:focus,
input[type="datetime-local"]:focus,
input[type="date"]:focus,
input[type="month"]:focus,
input[type="time"]:focus,
input[type="week"]:focus,
input[type="number"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="search"]:focus,
input[type="tel"]:focus,
input[type="color"]:focus,
.uneditable-input:focus
{
border-color: rgba(82, 168, 236, 0.8) !important;
}
.help-block {
color: #999999;
font-size: 12px;
line-height: 17px;
} }
.error { .error {
@ -343,6 +369,13 @@ div.dropdown-menu i {
background-position: -109px 0; background-position: -109px 0;
} }
.icon-ssh {
background-image: url("../img/icons.png") !important;
width: 16px;
height: 16px;
background-position: -127px 0;
}
.working-indicator { .working-indicator {
background-image: none; background-image: none;
width: 43px; width: 43px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -263,23 +263,25 @@
is synchronized with the following location(s): is synchronized with the following location(s):
</p> </p>
<div id="manage-sync-list"></div> <div id="manage-sync-list"></div>
<p class="msg-sync-list hide muted"><b>NOTE:</b> Removing a <blockquote class="msg-sync-list hide muted">
synchronized location will not delete any file.</p> <b>NOTE:</b> Removing a synchronized location will not delete any
<p class="msg-no-sync hide">"<span class="file-title"></span>" is file.
not synchronized yet. </blockquote>
</p> <blockquote class="msg-no-sync hide muted">
"<span class="file-title"></span>" is not synchronized yet.
</blockquote>
<p>Add a synchronized location manually:</p> <p>Add a synchronized location manually:</p>
<div class="input-prepend input-append"> <div class="input-prepend input-append">
<span class="add-on" title="Google Drive"><i <span class="add-on" title="Google Drive"><i
class="icon-gdrive"></i></span><input id="input-sync-manual-gdrive-id" class="icon-gdrive"></i></span><input id="input-sync-manual-gdrive-id"
type="text" class="span5" placeholder="Google Drive file ID"></input> type="text" class="span5" placeholder="GoogleDriveFileID"></input>
<a class="btn action-sync-manual-gdrive" title="Add location" <a class="btn action-sync-manual-gdrive" title="Add location"
data-dismiss="modal"><i class="icon-ok"></i></a> data-dismiss="modal"><i class="icon-ok"></i></a>
</div> </div>
<div class="input-prepend input-append"> <div class="input-prepend input-append">
<span class="add-on" title="Dropbox"><i class="icon-dropbox"></i></span><input <span class="add-on" title="Dropbox"><i class="icon-dropbox"></i></span><input
id="input-sync-manual-dropbox-path" type="text" class="span5" id="input-sync-manual-dropbox-path" type="text" class="span5"
placeholder="Dropbox file path"></input> <a placeholder="/dropbox/file/path"></input> <a
class="btn action-sync-manual-dropbox" title="Add location" class="btn action-sync-manual-dropbox" title="Add location"
data-dismiss="modal"><i class="icon-ok"></i></a> data-dismiss="modal"><i class="icon-ok"></i></a>
</div> </div>
@ -303,25 +305,63 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="form-horizontal"> <div class="form-horizontal">
<div class="control-group modal-publish-ssh">
<label class="control-label" for="input-publish-ssh-host">Host</label>
<div class="controls">
<input type="text" id="input-publish-ssh-host"
placeholder="host.name.or.ip"> <span class="help-block">
Host must be accessible publicly, unless you are hosting your own
<a target="_blank"
href="https://github.com/benweet/stackedit-ssh-proxy">SSH
proxy</a>.
</span>
</div>
</div>
<div class="control-group modal-publish-ssh">
<label class="control-label" for="input-publish-ssh-port">Port
(optional)</label>
<div class="controls">
<input type="text" id="input-publish-ssh-port" placeholder="22">
</div>
</div>
<div class="control-group modal-publish-ssh">
<label class="control-label" for="input-publish-ssh-username">Username</label>
<div class="controls">
<input type="text" id="input-publish-ssh-username"
placeholder="username">
</div>
</div>
<div class="control-group modal-publish-ssh">
<label class="control-label" for="input-publish-ssh-password">Password</label>
<div class="controls">
<input type="password" id="input-publish-ssh-password"
placeholder="password"> <span class="help-block">
Passwords are transmitted in clear, unless you are hosting your
own <a target="_blank"
href="https://github.com/benweet/stackedit-ssh-proxy">SSH
proxy</a>.
</span>
</div>
</div>
<div class="control-group modal-publish-github"> <div class="control-group modal-publish-github">
<label class="control-label" for="input-publish-github-reponame">Repository</label> <label class="control-label" for="input-publish-github-reponame">Repository</label>
<div class="controls"> <div class="controls">
<input type="text" id="input-publish-github-reponame" <input type="text" id="input-publish-github-reponame"
placeholder="Repository name"> placeholder="repository-name">
</div> </div>
</div> </div>
<div class="control-group modal-publish-github"> <div class="control-group modal-publish-github">
<label class="control-label" for="input-publish-github-branch">Branch</label> <label class="control-label" for="input-publish-github-branch">Branch</label>
<div class="controls"> <div class="controls">
<input type="text" id="input-publish-github-branch" <input type="text" id="input-publish-github-branch"
placeholder="Branch name"> placeholder="branch-name">
</div> </div>
</div> </div>
<div class="control-group modal-publish-github"> <div class="control-group modal-publish-ssh modal-publish-github">
<label class="control-label" for="input-publish-github-path">File <label class="control-label" for="input-publish-file-path">File
path</label> path</label>
<div class="controls"> <div class="controls">
<input type="text" id="input-publish-github-path" <input type="text" id="input-publish-file-path"
placeholder="path/to/file.md"> placeholder="path/to/file.md">
</div> </div>
</div> </div>
@ -329,15 +369,14 @@
<label class="control-label" for="input-publish-filename">Filename</label> <label class="control-label" for="input-publish-filename">Filename</label>
<div class="controls"> <div class="controls">
<input type="text" id="input-publish-filename" <input type="text" id="input-publish-filename"
placeholder="Filename"> placeholder="filename">
</div> </div>
</div> </div>
<div class="control-group modal-publish-gist"> <div class="control-group modal-publish-gist">
<label class="control-label" for="input-publish-gist-id">Existing <label class="control-label" for="input-publish-gist-id">Existing
ID (optional)</label> ID (optional)</label>
<div class="controls"> <div class="controls">
<input type="text" id="input-publish-gist-id" <input type="text" id="input-publish-gist-id" placeholder="GistID">
placeholder="Gist ID">
</div> </div>
</div> </div>
<div class="control-group modal-publish-gist"> <div class="control-group modal-publish-gist">
@ -376,7 +415,7 @@
<label class="control-label" for="input-publish-postid">Update <label class="control-label" for="input-publish-postid">Update
existing post ID (optional)</label> existing post ID (optional)</label>
<div class="controls"> <div class="controls">
<input type="text" id="input-publish-postid" placeholder="Post ID"> <input type="text" id="input-publish-postid" placeholder="PostID">
</div> </div>
</div> </div>
<div class="control-group modal-publish-blogger"> <div class="control-group modal-publish-blogger">
@ -409,26 +448,21 @@
ID (optional)</label> ID (optional)</label>
<div class="controls"> <div class="controls">
<input type="text" id="input-publish-gdrive-fileid" <input type="text" id="input-publish-gdrive-fileid"
placeholder="File ID"> placeholder="FileID"> <span class="help-block">If
no file ID is supplied, the file will be created in your Google
Drive root folder. You can move the file afterwards within Google
Drive.</span>
</div> </div>
</div> </div>
<div class="control-group modal-publish-gdrive">
<div class="controls muted">If no file ID is supplied, the
file will be created into your Google Drive root folder. You can
move the file afterwards within Google Drive.</div>
</div>
<div class="control-group modal-publish-gdrive"> <div class="control-group modal-publish-gdrive">
<label class="control-label" for="input-publish-gdrive-filename">Force <label class="control-label" for="input-publish-gdrive-filename">Force
file name (optional)</label> filename (optional)</label>
<div class="controls"> <div class="controls">
<input type="text" id="input-publish-gdrive-filename" <input type="text" id="input-publish-gdrive-filename"
placeholder="File name"> placeholder="Filename"> <span class="help-block">If
no file name is supplied, the document title will be used.</span>
</div> </div>
</div> </div>
<div class="control-group modal-publish-gdrive">
<div class="controls muted">If no file name is supplied, the
document title will be used.</div>
</div>
<div class="control-group"> <div class="control-group">
<div class="control-label">Format</div> <div class="control-label">Format</div>
@ -461,9 +495,9 @@
is published on the following location(s): is published on the following location(s):
</p> </p>
<div id="manage-publish-list"></div> <div id="manage-publish-list"></div>
<p class="msg-no-publish hide">"<span class="file-title"></span>" <blockquote class="msg-no-publish hide muted">
is not published yet. "<span class="file-title"></span>" is not published yet.
</p> </blockquote>
<blockquote class="muted"> <blockquote class="muted">
<b>NOTE:</b> You can add locations using "Publish on" sub-menu. <b>NOTE:</b> You can add locations using "Publish on" sub-menu.
</blockquote> </blockquote>
@ -575,6 +609,13 @@
<textarea id="textarea-settings-publish-template"></textarea> <textarea id="textarea-settings-publish-template"></textarea>
</div> </div>
</div> </div>
<div class="control-group">
<label class="control-label" for="input-settings-ssh-proxy">SSH
proxy</label>
<div class="controls">
<input type="text" id="input-settings-ssh-proxy">
</div>
</div>
</div> </div>
</div> </div>
<div class="tab-pane" id="tabpane-settings-utils"> <div class="tab-pane" id="tabpane-settings-utils">
@ -615,7 +656,7 @@
<dd> <dd>
<a target="_blank" <a target="_blank"
href="https://chrome.google.com/webstore/detail/stackedit/iiooodelglhkcpgbajoejffhijaclcdg">Chrome href="https://chrome.google.com/webstore/detail/stackedit/iiooodelglhkcpgbajoejffhijaclcdg">Chrome
app</a> app</a> (thanks for your review!)
</dd> </dd>
<dd> <dd>
<a target="_blank" href="https://twitter.com/stackedit/">Follow <a target="_blank" href="https://twitter.com/stackedit/">Follow
@ -689,6 +730,29 @@
<a target="_blank" href="http://underscorejs.org/">Underscore.js</a> <a target="_blank" href="http://underscorejs.org/">Underscore.js</a>
</dd> </dd>
</dl> </dl>
<dl>
<dt>Related projects:</dt>
<dd>
<a target="_blank"
href="https://github.com/benweet/stackedit-download-proxy">StackEdit
Download Proxy</a>
</dd>
<dd>
<a target="_blank"
href="https://github.com/benweet/stackedit-ssh-proxy">StackEdit
SSH Proxy</a>
</dd>
<dd>
<a target="_blank"
href="https://github.com/benweet/stackedit-tumblr-proxy">StackEdit
Tumblr Proxy</a>
</dd>
<dd>
<a target="_blank"
href="https://github.com/benweet/stackedit-wordpress-proxy">StackEdit
WordPress Proxy</a>
</dd>
</dl>
<p>Copyright 2013 <a target="_blank" <p>Copyright 2013 <a target="_blank"
href="http://www.benoitschweblin.com">Benoit Schweblin</a><br /> href="http://www.benoitschweblin.com">Benoit Schweblin</a><br />
Licensed under an <a target="_blank" Licensed under an <a target="_blank"
@ -731,5 +795,6 @@
<textarea id="md-section-helper"></textarea> <textarea id="md-section-helper"></textarea>
<div id="dropboxjs" data-app-key="x0k2l8puemfvg0o"></div> <div id="dropboxjs" data-app-key="x0k2l8puemfvg0o"></div>
</body> </body>
</html> </html>

46
js/bootstrap.js vendored
View File

@ -1,5 +1,5 @@
/* =================================================== /* ===================================================
* bootstrap-transition.js v2.3.0 * bootstrap-transition.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#transitions * http://twitter.github.com/bootstrap/javascript.html#transitions
* =================================================== * ===================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -58,7 +58,7 @@
}) })
}(window.jQuery);/* ========================================================== }(window.jQuery);/* ==========================================================
* bootstrap-alert.js v2.3.0 * bootstrap-alert.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#alerts * http://twitter.github.com/bootstrap/javascript.html#alerts
* ========================================================== * ==========================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -156,7 +156,7 @@
$(document).on('click.alert.data-api', dismiss, Alert.prototype.close) $(document).on('click.alert.data-api', dismiss, Alert.prototype.close)
}(window.jQuery);/* ============================================================ }(window.jQuery);/* ============================================================
* bootstrap-button.js v2.3.0 * bootstrap-button.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#buttons * http://twitter.github.com/bootstrap/javascript.html#buttons
* ============================================================ * ============================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -260,7 +260,7 @@
}) })
}(window.jQuery);/* ========================================================== }(window.jQuery);/* ==========================================================
* bootstrap-carousel.js v2.3.0 * bootstrap-carousel.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#carousel * http://twitter.github.com/bootstrap/javascript.html#carousel
* ========================================================== * ==========================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -336,7 +336,7 @@
if (!e) this.paused = true if (!e) this.paused = true
if (this.$element.find('.next, .prev').length && $.support.transition.end) { if (this.$element.find('.next, .prev').length && $.support.transition.end) {
this.$element.trigger($.support.transition.end) this.$element.trigger($.support.transition.end)
this.cycle() this.cycle(true)
} }
clearInterval(this.interval) clearInterval(this.interval)
this.interval = null this.interval = null
@ -466,7 +466,7 @@
}) })
}(window.jQuery);/* ============================================================= }(window.jQuery);/* =============================================================
* bootstrap-collapse.js v2.3.0 * bootstrap-collapse.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#collapse * http://twitter.github.com/bootstrap/javascript.html#collapse
* ============================================================= * =============================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -632,7 +632,7 @@
}) })
}(window.jQuery);/* ============================================================ }(window.jQuery);/* ============================================================
* bootstrap-dropdown.js v2.3.0 * bootstrap-dropdown.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#dropdowns * http://twitter.github.com/bootstrap/javascript.html#dropdowns
* ============================================================ * ============================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -685,6 +685,10 @@
clearMenus() clearMenus()
if (!isActive) { if (!isActive) {
if ('ontouchstart' in document.documentElement) {
// if mobile we we use a backdrop because click events don't delegate
$('<div class="dropdown-backdrop"/>').insertBefore($(this)).on('click', clearMenus)
}
$parent.toggleClass('open') $parent.toggleClass('open')
} }
@ -737,6 +741,7 @@
} }
function clearMenus() { function clearMenus() {
$('.dropdown-backdrop').remove()
$(toggle).each(function () { $(toggle).each(function () {
getParent($(this)).removeClass('open') getParent($(this)).removeClass('open')
}) })
@ -791,13 +796,12 @@
$(document) $(document)
.on('click.dropdown.data-api', clearMenus) .on('click.dropdown.data-api', clearMenus)
.on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('.dropdown-menu', function (e) { e.stopPropagation() })
.on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle) .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle)
.on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
}(window.jQuery); }(window.jQuery);
/* ========================================================= /* =========================================================
* bootstrap-modal.js v2.3.0 * bootstrap-modal.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#modals * http://twitter.github.com/bootstrap/javascript.html#modals
* ========================================================= * =========================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -946,7 +950,7 @@
} }
, removeBackdrop: function () { , removeBackdrop: function () {
this.$backdrop.remove() this.$backdrop && this.$backdrop.remove()
this.$backdrop = null this.$backdrop = null
} }
@ -1044,7 +1048,7 @@
}(window.jQuery); }(window.jQuery);
/* =========================================================== /* ===========================================================
* bootstrap-tooltip.js v2.3.0 * bootstrap-tooltip.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#tooltips * http://twitter.github.com/bootstrap/javascript.html#tooltips
* Inspired by the original jQuery.tipsy by Jason Frame * Inspired by the original jQuery.tipsy by Jason Frame
* =========================================================== * ===========================================================
@ -1125,7 +1129,15 @@
} }
, enter: function (e) { , enter: function (e) {
var self = $(e.currentTarget)[this.type](this._options).data(this.type) var defaults = $.fn[this.type].defaults
, options = {}
, self
this._options && $.each(this._options, function (key, value) {
if (defaults[key] != value) options[key] = value
}, this)
self = $(e.currentTarget)[this.type](options).data(this.type)
if (!self.options.delay || !self.options.delay.show) return self.show() if (!self.options.delay || !self.options.delay.show) return self.show()
@ -1397,7 +1409,7 @@
}(window.jQuery); }(window.jQuery);
/* =========================================================== /* ===========================================================
* bootstrap-popover.js v2.3.0 * bootstrap-popover.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#popovers * http://twitter.github.com/bootstrap/javascript.html#popovers
* =========================================================== * ===========================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -1511,7 +1523,7 @@
}(window.jQuery); }(window.jQuery);
/* ============================================================= /* =============================================================
* bootstrap-scrollspy.js v2.3.0 * bootstrap-scrollspy.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#scrollspy * http://twitter.github.com/bootstrap/javascript.html#scrollspy
* ============================================================= * =============================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -1672,7 +1684,7 @@
}) })
}(window.jQuery);/* ======================================================== }(window.jQuery);/* ========================================================
* bootstrap-tab.js v2.3.0 * bootstrap-tab.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#tabs * http://twitter.github.com/bootstrap/javascript.html#tabs
* ======================================================== * ========================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -1815,7 +1827,7 @@
}) })
}(window.jQuery);/* ============================================================= }(window.jQuery);/* =============================================================
* bootstrap-typeahead.js v2.3.0 * bootstrap-typeahead.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#typeahead * http://twitter.github.com/bootstrap/javascript.html#typeahead
* ============================================================= * =============================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.
@ -2150,7 +2162,7 @@
}(window.jQuery); }(window.jQuery);
/* ========================================================== /* ==========================================================
* bootstrap-affix.js v2.3.0 * bootstrap-affix.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#affix * http://twitter.github.com/bootstrap/javascript.html#affix
* ========================================================== * ==========================================================
* Copyright 2012 Twitter, Inc. * Copyright 2012 Twitter, Inc.

View File

@ -19,6 +19,7 @@ var WELCOME_DOCUMENT_TITLE = "Welcome document";
var DOWNLOAD_PROXY_URL = "http://stackedit-download-proxy.herokuapp.com/"; var DOWNLOAD_PROXY_URL = "http://stackedit-download-proxy.herokuapp.com/";
var WORDPRESS_CLIENT_ID = '3185'; var WORDPRESS_CLIENT_ID = '3185';
var WORDPRESS_PROXY_URL = "http://stackedit-wordpress-proxy.herokuapp.com/"; var WORDPRESS_PROXY_URL = "http://stackedit-wordpress-proxy.herokuapp.com/";
var SSH_PROXY_URL = "http://stackedit-ssh-proxy.herokuapp.com/";
// Use by Google's client.js // Use by Google's client.js
var delayedFunction = undefined; var delayedFunction = undefined;

View File

@ -65,8 +65,8 @@ define(
// Useful function for input control // Useful function for input control
function inputError(element, event) { function inputError(element, event) {
element.stop(true, true).addClass("error").delay(800).switchClass("error");
if(event !== undefined) { if(event !== undefined) {
element.stop(true, true).addClass("error").delay(800).switchClass("error");
event.stopPropagation(); event.stopPropagation();
} }
} }
@ -100,14 +100,20 @@ define(
return value; return value;
}; };
core.resetModalInputs = function() { core.resetModalInputs = function() {
$(".modal input[type=text]:not([disabled])").val(""); $(".modal input[type=text]:not([disabled]), .modal input[type=password]").val("");
}; };
core.trim = function(str) { core.trim = function(str) {
return str.replace(/^\s+|\s+$/g, ''); return str.replace(/^\s+|\s+$/g, '');
}; };
core.checkUrl = function(url) { core.checkUrl = function(url, addSlash) {
if(!url) {
return url;
}
if(url.indexOf("http") !== 0) { if(url.indexOf("http") !== 0) {
return "http://" + url; url = "http://" + url;
}
if(addSlash && url.indexOf("/", url.length - 1) === -1) {
url += "/";
} }
return url; return url;
}; };
@ -220,7 +226,9 @@ define(
'<title><%= documentTitle %></title>\n', '<title><%= documentTitle %></title>\n',
'</head>\n', '</head>\n',
'<body><%= documentHTML %></body>\n', '<body><%= documentHTML %></body>\n',
'</html>'].join("") '</html>'].join(""),
sshProxy : SSH_PROXY_URL,
sshConnectionList : []
}; };
core.loadSettings = function() { core.loadSettings = function() {
@ -247,6 +255,8 @@ define(
$("#input-settings-publish-commit-msg").val(core.settings.commitMsg); $("#input-settings-publish-commit-msg").val(core.settings.commitMsg);
// Template // Template
$("#textarea-settings-publish-template").val(core.settings.template); $("#textarea-settings-publish-template").val(core.settings.template);
// SSH proxy
$("#input-settings-ssh-proxy").val(core.settings.sshProxy);
}; };
core.saveSettings = function(event) { core.saveSettings = function(event) {
@ -271,9 +281,11 @@ define(
newSettings.commitMsg = core.getInputValue($("#input-settings-publish-commit-msg"), event); newSettings.commitMsg = core.getInputValue($("#input-settings-publish-commit-msg"), event);
// Template // Template
newSettings.template = core.getInputValue($("#textarea-settings-publish-template"), event); newSettings.template = core.getInputValue($("#textarea-settings-publish-template"), event);
// SSH proxy
newSettings.sshProxy = core.checkUrl(core.getInputValue($("#input-settings-ssh-proxy"), event), true);
if(!event.isPropagationStopped()) { if(!event.isPropagationStopped()) {
core.settings = newSettings; $.extend(core.settings, newSettings);
localStorage.settings = JSON.stringify(newSettings); localStorage.settings = JSON.stringify(newSettings);
} }
}; };
@ -357,12 +369,6 @@ define(
height: scrollHeight - htmlSectionOffset height: scrollHeight - htmlSectionOffset
}); });
/*
console.log("mdSectionList: " + _.map(mdSectionList, function(section) {
return section.endOffset;
}));
*/
// apply Scroll Link // apply Scroll Link
lastEditorScrollTop = -9; lastEditorScrollTop = -9;
skipScrollLink = false; skipScrollLink = false;

View File

@ -10,7 +10,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.onRun(function() { task.onRun(function() {
if(core.isOffline === true) { if(core.isOffline === true) {
client = undefined; client = undefined;
task.error(new Error("Operation not available in offline mode.")); task.error(new Error("Operation not available in offline mode.|stopPublish"));
return; return;
} }
if (client !== undefined) { if (client !== undefined) {

View File

@ -10,7 +10,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.onRun(function() { task.onRun(function() {
if(core.isOffline === true) { if(core.isOffline === true) {
connected = false; connected = false;
task.error(new Error("Operation not available in offline mode.")); task.error(new Error("Operation not available in offline mode.|stopPublish"));
return; return;
} }
if (connected === true) { if (connected === true) {

View File

@ -17,7 +17,7 @@ define(["jquery", "core", "github-helper"], function($, core, githubHelper) {
var publishAttributes = {}; var publishAttributes = {};
publishAttributes.repository = core.getInputValue($("#input-publish-github-reponame"), event); publishAttributes.repository = core.getInputValue($("#input-publish-github-reponame"), event);
publishAttributes.branch = core.getInputValue($("#input-publish-github-branch"), event); publishAttributes.branch = core.getInputValue($("#input-publish-github-branch"), event);
publishAttributes.path = core.getInputValue($("#input-publish-github-path"), event); publishAttributes.path = core.getInputValue($("#input-publish-file-path"), event);
if(event.isPropagationStopped()) { if(event.isPropagationStopped()) {
return undefined; return undefined;
} }

View File

@ -10,7 +10,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
task.onRun(function() { task.onRun(function() {
if(core.isOffline === true) { if(core.isOffline === true) {
connected = false; connected = false;
task.error(new Error("Operation not available in offline mode.")); task.error(new Error("Operation not available in offline mode.|stopPublish"));
return; return;
} }
if (connected === true) { if (connected === true) {

View File

@ -1,4 +1,4 @@
define(["jquery", "core", "sharing", "blogger-provider", "dropbox-provider", "gist-provider", "github-provider", "gdrive-provider", "tumblr-provider", "wordpress-provider", "underscore"], define(["jquery", "core", "sharing", "blogger-provider", "dropbox-provider", "gist-provider", "github-provider", "gdrive-provider", "ssh-provider", "tumblr-provider", "wordpress-provider", "underscore"],
function($, core, sharing) { function($, core, sharing) {
var publisher = {}; var publisher = {};
@ -198,6 +198,9 @@ define(["jquery", "core", "sharing", "blogger-provider", "dropbox-provider", "gi
} }
_.each(publishIndexList, function(publishIndex) { _.each(publishIndexList, function(publishIndex) {
var publishAttributes = JSON.parse(localStorage[publishIndex]); var publishAttributes = JSON.parse(localStorage[publishIndex]);
if(publishAttributes.password) {
publishAttributes.password = "********";
}
var publishDesc = JSON.stringify(publishAttributes).replace(/{|}|"/g, ""); var publishDesc = JSON.stringify(publishAttributes).replace(/{|}|"/g, "");
var lineElement = $(_.template(lineTemplate, { var lineElement = $(_.template(lineTemplate, {
provider: providerMap[publishAttributes.provider], provider: providerMap[publishAttributes.provider],

80
js/ssh-helper.js Normal file
View File

@ -0,0 +1,80 @@
define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
var sshHelper = {};
// Only used to check the offline status
function connect(task) {
task.onRun(function() {
if(core.isOffline === true) {
task.error(new Error("Operation not available in offline mode.|stopPublish"));
return;
}
task.chain();
});
}
sshHelper.upload = function(host, port, username, password, path, title, content, callback) {
callback = callback || core.doNothing;
var task = asyncRunner.createTask();
connect(task);
task.onRun(function() {
var url = SSH_PROXY_URL + "upload";
var data = {
host: host,
port: port,
username: username,
password: password,
path: path,
title: title,
content: content
};
$.ajax({
url : url,
data: data,
type: "POST",
dataType : "json",
timeout : AJAX_TIMEOUT
}).done(function(response, textStatus, jqXHR) {
if(response.error === undefined) {
task.chain();
return;
}
handleError(response.error, task);
}).fail(function(jqXHR) {
var error = {
code: jqXHR.status,
message: jqXHR.statusText
};
handleError(error, task);
});
});
task.onSuccess(function() {
callback();
});
task.onError(function(error) {
callback(error);
});
asyncRunner.addTask(task);
};
function handleError(error, task) {
var errorMsg = undefined;
if (error) {
console.error(error);
// Try to analyze the error
if (typeof error === "string") {
errorMsg = "SSH error: " + error + ".";
}
else {
errorMsg = "Could not publish on SSH server.";
if (error.code <= 0) {
core.setOffline();
errorMsg = "|stopPublish";
}
}
}
task.error(new Error(errorMsg));
}
return sshHelper;
});

44
js/ssh-provider.js Normal file
View File

@ -0,0 +1,44 @@
define([ "jquery", "core", "ssh-helper" ], function($, core, sshHelper) {
var PROVIDER_SSH = "ssh";
var sshProvider = {
providerId : PROVIDER_SSH,
providerName : "SSH server"
};
sshProvider.publish = function(publishAttributes, title, content, callback) {
sshHelper.upload(
publishAttributes.host,
publishAttributes.port,
publishAttributes.username,
publishAttributes.password,
publishAttributes.path,
title,
content,
callback);
};
sshProvider.newPublishAttributes = function(event) {
var publishAttributes = {};
publishAttributes.host = core
.getInputValue(
$("#input-publish-ssh-host"),
event,
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/);
publishAttributes.port = core.getInputIntValue(
$("#input-publish-ssh-port"), undefined, 0);
publishAttributes.username = core.getInputValue(
$("#input-publish-ssh-username"), event);
publishAttributes.password = core.getInputValue(
$("#input-publish-ssh-password"), event);
publishAttributes.path = core.getInputValue(
$("#input-publish-file-path"), event);
if (event.isPropagationStopped()) {
return undefined;
}
return publishAttributes;
};
return sshProvider;
});

View File

@ -8,7 +8,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
function connect(task) { function connect(task) {
task.onRun(function() { task.onRun(function() {
if(core.isOffline === true) { if(core.isOffline === true) {
task.error(new Error("Operation not available in offline mode.")); task.error(new Error("Operation not available in offline mode.|stopPublish"));
return; return;
} }
task.chain(); task.chain();

View File

@ -8,7 +8,7 @@ define(["jquery", "core", "async-runner"], function($, core, asyncRunner) {
function connect(task) { function connect(task) {
task.onRun(function() { task.onRun(function() {
if(core.isOffline === true) { if(core.isOffline === true) {
task.error(new Error("Operation not available in offline mode.")); task.error(new Error("Operation not available in offline mode.|stopPublish"));
return; return;
} }
task.chain(); task.chain();