UI fixes
This commit is contained in:
parent
b5191a7457
commit
ab8b0cca02
@ -28,6 +28,7 @@
|
||||
"MutationObservers": "https://github.com/Polymer/MutationObservers.git#~0.2.1",
|
||||
"rangy": "~1.2.3",
|
||||
"google-diff-match-patch-js": "~1.0.0",
|
||||
"jsondiffpatch": "~0.1.5"
|
||||
"jsondiffpatch": "~0.1.5",
|
||||
"hammerjs": "~1.0.10"
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
<link rel="shortcut icon" sizes="196x196" href="res-min/img/nice-highres.png">
|
||||
<meta name="description" content="Full-featured, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.">
|
||||
<meta name="author" content="Benoit Schweblin">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="msvalidate.01" content="5E47EE6F67B069C17E3CDD418351A612"
|
||||
/>
|
||||
|
@ -62,7 +62,7 @@ define([
|
||||
fileDesc = selectedFileDesc;
|
||||
});
|
||||
|
||||
// Watcher used to detect editor changes
|
||||
// Used to detect editor changes
|
||||
function Watcher() {
|
||||
this.isWatching = false;
|
||||
var contentObserver;
|
||||
@ -212,9 +212,6 @@ define([
|
||||
};
|
||||
})();
|
||||
this.getCoordinates = function(inputOffset, container, offset) {
|
||||
if(inputOffset === textContent.length) {
|
||||
return this.getCoordinates(inputOffset - 1);
|
||||
}
|
||||
if(!container) {
|
||||
offset = this.findOffset(inputOffset);
|
||||
container = offset.container;
|
||||
@ -485,6 +482,8 @@ define([
|
||||
this.currentMode = undefined;
|
||||
lastMode = undefined;
|
||||
contentElt.textContent = content;
|
||||
// Force this since the content could be the same
|
||||
checkContentChange();
|
||||
};
|
||||
}
|
||||
var undoMgr = new UndoMgr();
|
||||
@ -503,12 +502,20 @@ define([
|
||||
var trailingLfNode;
|
||||
function checkContentChange() {
|
||||
var newTextContent = inputElt.textContent;
|
||||
if(contentElt.lastChild === trailingLfNode && trailingLfNode.textContent.slice(-1) === '\n') {
|
||||
if(contentElt.lastChild === trailingLfNode && trailingLfNode.textContent.slice(-1) == '\n') {
|
||||
newTextContent = newTextContent.slice(0, -1);
|
||||
}
|
||||
|
||||
if(fileChanged === false) {
|
||||
if(contentElt.children.length && newTextContent == textContent) {
|
||||
if(newTextContent == textContent) {
|
||||
// User has removed the empty section
|
||||
if(contentElt.children.length === 0) {
|
||||
contentElt.innerHTML = '';
|
||||
sectionList.forEach(function(section) {
|
||||
contentElt.appendChild(section.elt);
|
||||
});
|
||||
addTrailingLfNode();
|
||||
}
|
||||
return;
|
||||
}
|
||||
undoMgr.currentMode = undoMgr.currentMode || 'typing';
|
||||
@ -609,6 +616,15 @@ define([
|
||||
fileDesc.previewScrollTop = previewElt.scrollTop;
|
||||
}
|
||||
});
|
||||
|
||||
// See https://gist.github.com/shimondoodkin/1081133
|
||||
if(/AppleWebKit\/([\d.]+)/.exec(navigator.userAgent)) {
|
||||
var $editableFix = $('<input style="width:1px;height:1px;border:none;margin:0;padding:0;" tabIndex="-1">').appendTo('html');
|
||||
$contentElt.blur(function () {
|
||||
$editableFix[0].setSelectionRange(0, 0);
|
||||
$editableFix.blur();
|
||||
});
|
||||
}
|
||||
|
||||
inputElt.focus = focus;
|
||||
|
||||
@ -704,10 +720,8 @@ define([
|
||||
|
||||
actions[action](state, options);
|
||||
setValue(state.before + state.selection + state.after);
|
||||
_.defer(function() {
|
||||
selectionMgr.setSelectionStartEnd(state.selectionStart, state.selectionEnd);
|
||||
//$inputElt.trigger('input');
|
||||
});
|
||||
selectionMgr.setSelectionStartEnd(state.selectionStart, state.selectionEnd);
|
||||
|
||||
};
|
||||
|
||||
var actions = {
|
||||
@ -873,12 +887,19 @@ define([
|
||||
childNode = nextNode;
|
||||
}
|
||||
}
|
||||
trailingLfNode = document.createTextNode('\n');
|
||||
contentElt.appendChild(trailingLfNode);
|
||||
addTrailingLfNode();
|
||||
selectionMgr.setSelectionStartEnd();
|
||||
});
|
||||
}
|
||||
|
||||
function addTrailingLfNode() {
|
||||
trailingLfNode = crel('span', {
|
||||
class: 'token lf',
|
||||
});
|
||||
trailingLfNode.textContent = '\n';
|
||||
contentElt.appendChild(trailingLfNode);
|
||||
}
|
||||
|
||||
var escape = (function() {
|
||||
var entityMap = {
|
||||
"&": "&",
|
||||
|
@ -73,9 +73,13 @@ define([
|
||||
checkPublication();
|
||||
};
|
||||
|
||||
buttonPublish.onReady = function() {
|
||||
$(".action-update-publication").click(publisher.publish);
|
||||
};
|
||||
|
||||
buttonPublish.onPublishRemoved = checkPublication;
|
||||
buttonPublish.onNewPublishSuccess = checkPublication;
|
||||
|
||||
return buttonPublish;
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -87,14 +87,17 @@ define([
|
||||
isOffline = isOfflineParameter;
|
||||
updateButtonState();
|
||||
};
|
||||
|
||||
|
||||
buttonSync.onReady = function() {
|
||||
mousetrap.bind(buttonSync.config.syncShortcut, function(e) {
|
||||
synchronizer.sync() && (lastSync = utils.currentTime);
|
||||
e.preventDefault();
|
||||
});
|
||||
$(".action-force-synchronization").click(function() {
|
||||
synchronizer.sync() && (lastSync = utils.currentTime);
|
||||
});
|
||||
};
|
||||
|
||||
return buttonSync;
|
||||
|
||||
});
|
||||
});
|
||||
|
@ -21,6 +21,7 @@ define([
|
||||
var syncListElt;
|
||||
var $msgSyncListElt;
|
||||
var $msgNoSyncElt;
|
||||
var $showAlreadySynchronizedElt;
|
||||
var refreshDialog = function(fileDescParameter) {
|
||||
if(fileDescParameter !== undefined && fileDescParameter !== fileDesc) {
|
||||
return;
|
||||
@ -35,6 +36,8 @@ define([
|
||||
$msgNoSyncElt.removeClass("hide");
|
||||
}
|
||||
|
||||
$showAlreadySynchronizedElt.toggleClass("hide", _.size(fileDesc.syncLocations) === 0);
|
||||
|
||||
var syncListHtml = _.reduce(fileDesc.syncLocations, function(result, syncAttributes) {
|
||||
return result + _.template(dialogManageSynchronizationLocationHTML, {
|
||||
syncAttributes: syncAttributes,
|
||||
@ -66,6 +69,8 @@ define([
|
||||
syncListElt = modalElt.querySelector(".sync-list");
|
||||
$msgSyncListElt = $(modalElt.querySelectorAll(".msg-sync-list"));
|
||||
$msgNoSyncElt = $(modalElt.querySelectorAll(".msg-no-sync"));
|
||||
|
||||
$showAlreadySynchronizedElt = $(document.querySelectorAll(".show-already-synchronized"));
|
||||
};
|
||||
|
||||
return dialogManageSynchronization;
|
||||
|
@ -12,7 +12,7 @@
|
||||
'mod+z': bindPagedownButton('undo'),
|
||||
'mod+y': bindPagedownButton('redo'),
|
||||
'mod+shift+z': bindPagedownButton('redo'),
|
||||
'mod+p': function(evt) {
|
||||
'mod+d': function(evt) {
|
||||
$('.button-open-discussion').click();
|
||||
evt.preventDefault();
|
||||
},
|
||||
|
@ -74,18 +74,25 @@
|
||||
</button>
|
||||
<div class="panel-content">
|
||||
<div class="list-group">
|
||||
|
||||
<a href="viewer" title="StackEdit Viewer"
|
||||
class="list-group-item"><i class="icon-resize-full"></i>
|
||||
StackEdit Viewer</a>
|
||||
class="list-group-item">
|
||||
<i class="icon-resize-full"></i> StackEdit Viewer
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<div class=dropdown-header>EXPORT</div>
|
||||
<div class="list-group">
|
||||
|
||||
<a href="#" data-toggle="collapse" data-target=".collapse-synchronize"
|
||||
class="list-group-item"><i
|
||||
class="icon-refresh"></i> Synchronize...</a>
|
||||
class="list-group-item">
|
||||
<div><i class="icon-refresh"></i> Synchronize</div>
|
||||
<small>Backup, collaborate in the cloud</small>
|
||||
</a>
|
||||
<div class="sub-menu collapse collapse-synchronize clearfix">
|
||||
<ul class="nav">
|
||||
<ul class="nav alert alert-danger show-already-synchronized">
|
||||
<li><div>"<span class="file-title"></span>" is already synchronized.</div></li>
|
||||
<li><a href="#" class="action-force-synchronization"><i class="icon-refresh"></i>
|
||||
Force synchronization</a></li>
|
||||
<li><a href="#" data-toggle="modal" data-target=".modal-manage-sync"
|
||||
class="action-reset-input"><i
|
||||
class="icon-refresh"></i> Manage synchronization</a></li>
|
||||
@ -93,22 +100,27 @@
|
||||
<ul class="nav">
|
||||
<li><a href="#" class="action-sync-export-dialog-dropbox"><i
|
||||
class="icon-provider-dropbox"></i> Save on Dropbox</a></li>
|
||||
<li><a href="#" class="action-sync-import-dropbox"><i
|
||||
class="icon-provider-dropbox"></i> Open from Dropbox</a></li>
|
||||
<li><a href="#" class="submenu-sync-gdrive action-sync-export-dialog-gdrive"><i
|
||||
class="icon-provider-gdrive"></i> Save on Google Drive</a></li>
|
||||
<li><a href="#" class="submenu-sync-gdrive action-sync-import-gdrive"><i
|
||||
class="icon-provider-gdrive"></i> Open from Google Drive</a></li>
|
||||
<li><a href="#" class="submenu-sync-gdrivesec action-sync-export-dialog-gdrivesec"><i
|
||||
class="icon-provider-gdrive"></i> Save on Google Drive <small>(2nd account)</small></a></li>
|
||||
<li><a href="#" class="submenu-sync-gdrivesec action-sync-import-gdrivesec"><i
|
||||
class="icon-provider-gdrive"></i> Open from Google Drive <small>(2nd account)</small></a></li>
|
||||
<li><a href="#" class="submenu-sync-gdriveter action-sync-export-dialog-gdriveter"><i
|
||||
class="icon-provider-gdrive"></i> Save on Google Drive <small>(3rd account)</small></a></li>
|
||||
<li><a href="#" class="submenu-sync-gdrive action-autosync-dialog-gdrive"><i
|
||||
class="icon-provider-gdrive"></i> Google Drive AutoSync</a></li>
|
||||
<li><a href="#" class="submenu-sync-gdrivesec action-autosync-dialog-gdrivesec"><i
|
||||
class="icon-provider-gdrive"></i> Google Drive AutoSync <small>(2nd account)</small></a></li>
|
||||
<li><a href="#" class="submenu-sync-gdriveter action-autosync-dialog-gdriveter"><i
|
||||
class="icon-provider-gdrive"></i> Google Drive AutoSync <small>(3rd account)</small></a></li>
|
||||
<li><a href="#" class="submenu-sync-gdriveter action-sync-import-gdriveter"><i
|
||||
class="icon-provider-gdrive"></i> Open from Google Drive <small>(3rd account)</small></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a href="#" data-toggle="collapse" data-target=".collapse-publish-on"
|
||||
class="list-group-item"><i class="icon-upload"></i> Publish...</a>
|
||||
class="list-group-item">
|
||||
<div><i class="icon-upload"></i>Publish</div>
|
||||
<small>Export on the web</small>
|
||||
</a>
|
||||
<div class="sub-menu collapse collapse-publish-on clearfix">
|
||||
<ul class="nav alert alert-danger show-already-published">
|
||||
<li><div>"<span class="file-title"></span>" is already published.</div></li>
|
||||
@ -122,8 +134,13 @@
|
||||
</ul>
|
||||
</div>
|
||||
<a href="#" data-toggle="modal" data-target=".modal-manage-sharing"
|
||||
class="action-reset-input list-group-item"><i class="icon-link"></i>
|
||||
Sharing links</a>
|
||||
class="action-reset-input list-group-item">
|
||||
<div><i class="icon-link"></i>Sharing</div>
|
||||
<small>Share document links</small>
|
||||
</a>
|
||||
</div>
|
||||
<div class="list-group">
|
||||
|
||||
<a href="#" data-toggle="collapse" data-target=".collapse-save-as"
|
||||
class="list-group-item"><i class="icon-hdd"></i> Export to disk</a>
|
||||
<div class="sub-menu collapse collapse-save-as clearfix">
|
||||
@ -138,21 +155,7 @@
|
||||
class="icon-download"></i> Export as PDF</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class=dropdown-header>IMPORT</div>
|
||||
<div class="list-group">
|
||||
<a class="list-group-item action-sync-import-dropbox" href="#"><i
|
||||
class="icon-provider-dropbox"></i> Open from
|
||||
Dropbox</a>
|
||||
<a href="#" class="list-group-item submenu-sync-gdrive action-sync-import-gdrive"><i
|
||||
class="icon-provider-gdrive"></i> Open from
|
||||
Google Drive</a>
|
||||
<a href="#" class="list-group-item submenu-sync-gdrivesec action-sync-import-gdrivesec"><i
|
||||
class="icon-provider-gdrive"></i> Open from
|
||||
Google Drive <small>(2nd account)</small></a>
|
||||
<a href="#" class="list-group-item submenu-sync-gdriveter action-sync-import-gdriveter"><i
|
||||
class="icon-provider-gdrive"></i> Open from
|
||||
Google Drive <small>(3rd account)</small></a>
|
||||
|
||||
<a data-toggle="modal"
|
||||
data-target=".modal-import-harddrive-markdown"
|
||||
class="list-group-item action-reset-input" href="#"><i
|
||||
@ -303,7 +306,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="btn btn-default action-import-image-gplus"
|
||||
<a href="#" class="btn btn-default pull-left action-import-image-gplus"
|
||||
data-dismiss="modal"><i class="icon-provider-gplus"></i> Import
|
||||
from Google+</a> <a href="#" class="btn btn-default"
|
||||
data-dismiss="modal">Cancel</a> <a href="#"
|
||||
|
@ -97,7 +97,7 @@ Header 2
|
||||
> > And, they can be nested.
|
||||
|
||||
> #### Headers in blockquotes
|
||||
>
|
||||
>
|
||||
> * You can quote a list.
|
||||
> * Etc.
|
||||
</code></pre>
|
||||
@ -129,14 +129,14 @@ like `` `this` ``.
|
||||
|
||||
* * *
|
||||
|
||||
- - - -
|
||||
- - - -
|
||||
</code></pre>
|
||||
|
||||
<h4>Manual Line Breaks</h4>
|
||||
|
||||
<p>End a line with two or more spaces:</p>
|
||||
|
||||
<pre><code>Roses are red,
|
||||
<pre><code>Roses are red,
|
||||
Violets are blue.
|
||||
</code></pre>
|
||||
|
||||
|
@ -8,19 +8,33 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
<b>AutoSync</b> feature automatically exports every new document to your <i
|
||||
<b>AutoSync</b> feature automatically saves all documents to your <i
|
||||
class="icon-provider-<%= providerId %>"></i>
|
||||
<code>Google Drive</code>
|
||||
account and keep it synchronized.
|
||||
account and keep them synchronized.
|
||||
</p>
|
||||
<div class="form-horizontal">
|
||||
<br/>
|
||||
<div class="form-group">
|
||||
<div class="col-lg-3 control-label"></div>
|
||||
<div class="col-lg-8">
|
||||
<label> <input id="input-autosync-<%= providerId %>-enabled"
|
||||
type="checkbox"> Enable AutoSync for <%= providerName %>
|
||||
</label>
|
||||
<div class="radio">
|
||||
<label> <input type="radio"
|
||||
name="radio-autosync-<%= providerId %>-mode" value="off">
|
||||
Disabled
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label> <input type="radio"
|
||||
name="radio-autosync-<%= providerId %>-mode" value="new">
|
||||
New documents (not current)
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label> <input type="radio"
|
||||
name="radio-autosync-<%= providerId %>-mode" value="all">
|
||||
Every document not yet synchronized
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
|
@ -55,6 +55,8 @@
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="btn btn-default pull-left action-autosync-dialog-<%= providerId %>" data-dismiss="modal"><i
|
||||
class="icon-provider-gdrive"></i> Setup AutoSync</a>
|
||||
<a href="#" class="btn btn-default" data-dismiss="modal">Cancel</a>
|
||||
<a href="#" data-dismiss="modal"
|
||||
class="btn btn-primary action-sync-export-<%= providerId %>">OK</a>
|
||||
|
@ -7,7 +7,8 @@ define([
|
||||
'eventMgr',
|
||||
'crel',
|
||||
'mousetrap',
|
||||
], function($, _, utils, constants, settings, eventMgr, crel, mousetrap) {
|
||||
'hammerjs',
|
||||
], function($, _, utils, constants, settings, eventMgr, crel, mousetrap, hammer) {
|
||||
var layout = {};
|
||||
|
||||
var resizerSize = 32;
|
||||
@ -23,10 +24,11 @@ define([
|
||||
};
|
||||
var menuPanelWidth = 280;
|
||||
var documentPanelWidth = 320;
|
||||
var titleMinWidth = 200;
|
||||
var windowSize;
|
||||
|
||||
var wrapperL1, wrapperL2, wrapperL3;
|
||||
var navbar, menuPanel, documentPanel, editor, previewPanel, previewContainer, navbarToggler, previewToggler, previewResizer;
|
||||
var navbar, menuPanel, documentPanel, editor, previewPanel, previewContainer, navbarToggler, previewToggler, previewResizer, previewButtons;
|
||||
|
||||
var animate = false;
|
||||
function startAnimation() {
|
||||
@ -126,6 +128,19 @@ define([
|
||||
resizeAll();
|
||||
};
|
||||
};
|
||||
DomObject.prototype.initHammer = function(drag) {
|
||||
this.hammer = hammer(this.elt, {
|
||||
drag: drag ? true : false,
|
||||
drag_max_touches: 0,
|
||||
gesture: false,
|
||||
hold: false,
|
||||
release: false,
|
||||
swipe: drag ? false : true,
|
||||
tap: false,
|
||||
touch: false,
|
||||
transform: false
|
||||
});
|
||||
};
|
||||
|
||||
var maxWidthMap = [
|
||||
{ screenWidth: 0, maxWidth: 600 },
|
||||
@ -154,9 +169,9 @@ define([
|
||||
});
|
||||
var navbarMarginWidth = 18 * 2 + 25 + 25;
|
||||
var buttonsDropdownWidth = 40;
|
||||
var titleMinWidth = 200;
|
||||
var workingIndicatorWidth = 18 + 70;
|
||||
function onResize() {
|
||||
var paddingBottom = wrapperL3.height - 60;
|
||||
|
||||
var editorPadding = (editor.elt.offsetWidth - getMaxWidth()) / 2;
|
||||
if(editorPadding < constants.EDITOR_DEFAULT_PADDING) {
|
||||
@ -164,6 +179,7 @@ define([
|
||||
}
|
||||
editorContentElt.style.paddingLeft = editorPadding + 'px';
|
||||
editorContentElt.style.paddingRight = editorPadding + 'px';
|
||||
editorContentElt.style.paddingBottom = paddingBottom + 'px';
|
||||
editorMarginElt.style.width = editorPadding + 'px';
|
||||
|
||||
var previewPadding = (previewContainer.elt.offsetWidth - getMaxWidth()) / 2;
|
||||
@ -172,6 +188,7 @@ define([
|
||||
}
|
||||
previewContentElt.style.paddingLeft = previewPadding + 'px';
|
||||
previewContentElt.style.paddingRight = previewPadding + 'px';
|
||||
previewContentElt.style.paddingBottom = paddingBottom + 'px';
|
||||
|
||||
if(!window.viewerMode) {
|
||||
var maxWidth = navbarMarginWidth + workingIndicatorWidth + titleMinWidth + buttonsDropdownWidth;
|
||||
@ -322,11 +339,11 @@ define([
|
||||
navbarToggler = new DomObject('.layout-toggler-navbar');
|
||||
previewToggler = new DomObject('.layout-toggler-preview');
|
||||
previewResizer = new DomObject('.layout-resizer-preview');
|
||||
previewButtons = new DomObject('.extension-preview-buttons');
|
||||
|
||||
editorContentElt = editor.elt.querySelector('.editor-content');
|
||||
previewContentElt = document.getElementById('preview-contents');
|
||||
editorMarginElt = editor.elt.querySelector('.editor-margin');
|
||||
var $previewButtonsElt = $('.extension-preview-buttons');
|
||||
navbarInnerElt = navbar.elt.querySelector('.navbar-inner');
|
||||
navbarDropdownElt = navbar.elt.querySelector('.buttons-dropdown .dropdown-menu');
|
||||
$navbarDropdownBtnElt = navbar.$elt.find('.buttons-dropdown');
|
||||
@ -354,7 +371,7 @@ define([
|
||||
|
||||
previewPanel.isOpen = true;
|
||||
previewPanel.createToggler(false, function(isOpen) {
|
||||
$previewButtonsElt.toggleClass('hide', !isOpen);
|
||||
previewButtons.$elt.toggleClass('hide', !isOpen);
|
||||
eventMgr.onPreviewToggle(isOpen);
|
||||
});
|
||||
previewPanel.halfSize = true;
|
||||
@ -368,57 +385,39 @@ define([
|
||||
documentPanel.createToggler(true);
|
||||
documentPanel.$elt.find('.toggle-button').click(_.bind(documentPanel.toggle, documentPanel));
|
||||
|
||||
// Hide menu panel when clicking 'Save as' button
|
||||
menuPanel.$elt.on('click', 'a[data-toggle!=collapse]', _.bind(menuPanel.toggle, menuPanel, false));
|
||||
documentPanel.$elt.on('click', 'a[data-toggle!=collapse]', _.bind(documentPanel.toggle, documentPanel, false));
|
||||
// Gesture events
|
||||
previewResizer.initHammer(true);
|
||||
/*
|
||||
navbar.initHammer();
|
||||
menuPanel.initHammer();
|
||||
documentPanel.initHammer();
|
||||
previewButtons.initHammer();
|
||||
|
||||
menuPanel.$elt.on('show.bs.collapse', function() {
|
||||
// Close all open sub-menus when one submenu opens
|
||||
menuPanel.$elt.find('.in').collapse('hide');
|
||||
});
|
||||
navbar.hammer.on('swiperight', _.bind(menuPanel.toggle, menuPanel, true));
|
||||
navbar.hammer.on('swipeleft', _.bind(documentPanel.toggle, documentPanel, true));
|
||||
navbar.hammer.on('swipeup', _.bind(navbar.toggle, navbar, false));
|
||||
|
||||
var isDragging = false;
|
||||
var desiredWidth, desiredHeight;
|
||||
var lastCoord;
|
||||
wrapperL1.$elt.on('mousemove', function(evt) {
|
||||
if(!isDragging) {
|
||||
return;
|
||||
}
|
||||
if(evt.which !== 1) {
|
||||
isDragging = false;
|
||||
menuPanel.hammer.on('swiperight', _.bind(menuPanel.toggle, menuPanel, true));
|
||||
menuPanel.hammer.on('swipeleft', _.bind(menuPanel.toggle, menuPanel, false));
|
||||
|
||||
documentPanel.hammer.on('swipeleft', _.bind(documentPanel.toggle, documentPanel, true));
|
||||
documentPanel.hammer.on('swiperight', _.bind(documentPanel.toggle, documentPanel, false));
|
||||
*/
|
||||
|
||||
var initialWidth, initialHeight;
|
||||
previewResizer.hammer.on('dragstart', function() {
|
||||
initialWidth = previewPanel.width;
|
||||
initialHeight = previewPanel.height;
|
||||
}).on('drag', function(evt) {
|
||||
if(isVertical) {
|
||||
previewPanel.height = initialHeight - evt.gesture.deltaY;
|
||||
}
|
||||
else {
|
||||
var newCoord = {
|
||||
x: evt.pageX,
|
||||
y: evt.pageY,
|
||||
};
|
||||
if(isVertical && lastCoord.y !== newCoord.y) {
|
||||
desiredHeight += lastCoord.y - newCoord.y;
|
||||
previewPanel.height = desiredHeight;
|
||||
previewPanel.halfSize = false;
|
||||
resizeAll();
|
||||
}
|
||||
if(!isVertical && lastCoord.x !== newCoord.x) {
|
||||
desiredWidth += lastCoord.x - newCoord.x;
|
||||
previewPanel.width = desiredWidth;
|
||||
previewPanel.halfSize = false;
|
||||
resizeAll();
|
||||
}
|
||||
lastCoord = newCoord;
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
previewResizer.$elt.on('mousedown', function(evt) {
|
||||
if(evt.which === 1) {
|
||||
isDragging = true;
|
||||
desiredWidth = previewPanel.width;
|
||||
desiredHeight = previewPanel.height;
|
||||
lastCoord = {
|
||||
x: evt.pageX,
|
||||
y: evt.pageY,
|
||||
};
|
||||
previewPanel.width = initialWidth - evt.gesture.deltaX;
|
||||
}
|
||||
evt.gesture.preventDefault();
|
||||
previewPanel.halfSize = false;
|
||||
resizeAll();
|
||||
});
|
||||
|
||||
var isModalShown = false;
|
||||
@ -431,6 +430,15 @@ define([
|
||||
isModalShown = false;
|
||||
});
|
||||
|
||||
// Hide panels when clicking on a non collapse element
|
||||
menuPanel.$elt.on('click', 'a[data-toggle!=collapse]', _.bind(menuPanel.toggle, menuPanel, false));
|
||||
documentPanel.$elt.on('click', 'a[data-toggle!=collapse]', _.bind(documentPanel.toggle, documentPanel, false));
|
||||
|
||||
// In menu panel, close all open sub-menus when one submenu opens
|
||||
menuPanel.$elt.on('show.bs.collapse', function() {
|
||||
menuPanel.$elt.find('.in').collapse('hide');
|
||||
});
|
||||
|
||||
// Configure Mousetrap
|
||||
mousetrap.stopCallback = function() {
|
||||
return menuPanel.isOpen || documentPanel.isOpen || isModalShown;
|
||||
@ -469,11 +477,36 @@ define([
|
||||
style.innerHTML = styleContent;
|
||||
document.head.appendChild(style);
|
||||
|
||||
|
||||
|
||||
resizeAll();
|
||||
};
|
||||
|
||||
eventMgr.addListener('onReady', function() {
|
||||
var previewButtonsOffset = previewButtons.elt.offsetWidth + 5;
|
||||
function openPreviewButtons() {
|
||||
clearTimeout(closeTimeoutId);
|
||||
previewButtons.x = 0;
|
||||
previewButtons.applyCss();
|
||||
}
|
||||
var closeTimeoutId;
|
||||
var dropdownOpen = false;
|
||||
function closePreviewButtons() {
|
||||
clearTimeout(closeTimeoutId);
|
||||
closeTimeoutId = setTimeout(function() {
|
||||
if(!dropdownOpen) {
|
||||
previewButtons.x = previewButtonsOffset;
|
||||
previewButtons.applyCss();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
closePreviewButtons();
|
||||
previewButtons.$elt.hover(openPreviewButtons, closePreviewButtons).on('show.bs.dropdown', function() {
|
||||
dropdownOpen = true;
|
||||
}).on('hidden.bs.dropdown', function() {
|
||||
dropdownOpen = false;
|
||||
closePreviewButtons();
|
||||
});
|
||||
});
|
||||
|
||||
eventMgr.onLayoutCreated(layout);
|
||||
return layout;
|
||||
});
|
||||
|
@ -59,7 +59,8 @@ requirejs.config({
|
||||
'rangy-cssclassapplier': 'bower-libs/rangy/rangy-cssclassapplier',
|
||||
diff_match_patch: 'bower-libs/google-diff-match-patch-js/diff_match_patch',
|
||||
diff_match_patch_uncompressed: 'bower-libs/google-diff-match-patch-js/diff_match_patch_uncompressed',
|
||||
jsondiffpatch: 'bower-libs/jsondiffpatch/build/bundle'
|
||||
jsondiffpatch: 'bower-libs/jsondiffpatch/build/bundle',
|
||||
hammerjs: 'bower-libs/hammerjs/hammer'
|
||||
},
|
||||
shim: {
|
||||
underscore: {
|
||||
|
@ -262,14 +262,14 @@ define([
|
||||
// Initialize the AutoSync dialog fields
|
||||
gdriveProvider.setAutosyncDialogConfig = function() {
|
||||
var config = gdriveProvider.autosyncConfig;
|
||||
utils.setInputChecked('#input-autosync-' + providerId + '-enabled', config.enabled);
|
||||
utils.setInputRadio('radio-autosync-' + providerId + '-mode', config.mode || 'off');
|
||||
utils.setInputValue('#input-autosync-' + providerId + '-parentid', config.parentId);
|
||||
};
|
||||
|
||||
// Retrieve the AutoSync dialog fields
|
||||
gdriveProvider.getAutosyncDialogConfig = function() {
|
||||
var config = {};
|
||||
config.enabled = utils.getInputChecked('#input-autosync-' + providerId + '-enabled');
|
||||
config.mode = utils.getInputRadio('radio-autosync-' + providerId + '-mode');
|
||||
config.parentId = utils.getInputTextValue('#input-autosync-' + providerId + '-parentid');
|
||||
return config;
|
||||
};
|
||||
|
@ -297,9 +297,7 @@ define([
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
$(".action-process-publish").click(performNewLocation);
|
||||
$(".action-update-publication").click(publisher.publish);
|
||||
|
||||
var $customTmplCollapseElt = $('.publish-custom-template-collapse').collapse({
|
||||
toggle: false
|
||||
|
@ -288,6 +288,7 @@ kbd {
|
||||
// Custom icons (not from Font Awesome)
|
||||
.icon-code {
|
||||
font-size: 83%;
|
||||
line-height: 1.65em;
|
||||
&:before {
|
||||
margin-left: 0.1em;
|
||||
margin-right: 0.6em;
|
||||
|
@ -111,6 +111,7 @@
|
||||
@btn-info-color: fade(@secondary-desaturated, 35%);
|
||||
@btn-info-bg: @transparent;
|
||||
@btn-info-border: @transparent;
|
||||
@btn-info-hover-border: fade(@secondary, 8%);
|
||||
@btn-info-hover-bg: lighten(@secondary-desaturated, 45%);
|
||||
@gray-lighter: @body-bg;
|
||||
@modal-header-border-color: @secondary-border-color-light;
|
||||
@ -318,7 +319,7 @@ a {
|
||||
.info-tooltip &,
|
||||
.open &.dropdown-toggle {
|
||||
color: darken(@secondary, 30%);
|
||||
border-color: fade(@secondary, 8%);
|
||||
border-color: @btn-info-hover-border;
|
||||
background-color: @btn-info-hover-bg !important; // important to override .nav > li > a:hover
|
||||
}
|
||||
}
|
||||
@ -583,10 +584,17 @@ a {
|
||||
.layout-panel();
|
||||
width: @menu-panel-width;
|
||||
.alert {
|
||||
padding: 15px 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
i {
|
||||
margin-right: 8px;
|
||||
}
|
||||
small {
|
||||
color: @dropdown-header-color;
|
||||
padding-left: 30px;
|
||||
}
|
||||
.nav {
|
||||
margin: 20px 0;
|
||||
margin: 10px 0 20px;
|
||||
> li > * {
|
||||
padding: 8px 30px;
|
||||
}
|
||||
@ -794,18 +802,20 @@ a {
|
||||
.extension-preview-buttons {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
right: 35px;
|
||||
right: 50px;
|
||||
margin-top: 6px;
|
||||
.ui-layout-resizer-south-closed & {
|
||||
display: none !important;
|
||||
}
|
||||
background-color: @btn-info-hover-bg;
|
||||
border: 1px solid @btn-info-hover-border;
|
||||
border-radius: @border-radius-base;
|
||||
.transition-transform(350ms ease-in-out);
|
||||
.btn-group {
|
||||
.btn {
|
||||
position: initial;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
.dropdown-menu {
|
||||
margin-top: 4px;
|
||||
margin-top: 6px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
@ -1435,10 +1445,6 @@ div.dropdown-menu, {
|
||||
z-index: 1040 !important;
|
||||
}
|
||||
|
||||
.action-import-image-gplus {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
text-align: left;
|
||||
}
|
||||
@ -1614,10 +1620,6 @@ div.jGrowl {
|
||||
}
|
||||
}
|
||||
|
||||
.ui-layout-toggler {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.navbar .file-title-navbar {
|
||||
cursor: initial;
|
||||
.box-shadow(none);
|
||||
|
@ -74,118 +74,149 @@ define([
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* Standard synchronization
|
||||
* Synchronization
|
||||
**************************************************************************/
|
||||
|
||||
// Recursive function to upload a single file on multiple locations
|
||||
var uploadSyncAttributesList = [];
|
||||
var uploadContent;
|
||||
var uploadContentCRC;
|
||||
var uploadTitle;
|
||||
var uploadTitleCRC;
|
||||
var uploadDiscussionList;
|
||||
var uploadDiscussionListCRC;
|
||||
function locationUp(callback) {
|
||||
|
||||
// No more synchronized location for this document
|
||||
if(uploadSyncAttributesList.length === 0) {
|
||||
return fileUp(callback);
|
||||
}
|
||||
|
||||
// Dequeue a synchronized location
|
||||
var syncAttributes = uploadSyncAttributesList.pop();
|
||||
|
||||
syncAttributes.provider.syncUp(
|
||||
uploadContent,
|
||||
uploadContentCRC,
|
||||
uploadTitle,
|
||||
uploadTitleCRC,
|
||||
uploadDiscussionList,
|
||||
uploadDiscussionListCRC,
|
||||
syncAttributes,
|
||||
function(error, uploadFlag) {
|
||||
if(uploadFlag === true) {
|
||||
// If uploadFlag is true, request another upload cycle
|
||||
uploadCycle = true;
|
||||
}
|
||||
if(error) {
|
||||
return callback(error);
|
||||
}
|
||||
if(uploadFlag) {
|
||||
// Update syncAttributes in storage
|
||||
utils.storeAttributes(syncAttributes);
|
||||
}
|
||||
locationUp(callback);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Recursive function to upload multiple files
|
||||
var uploadFileList = [];
|
||||
function fileUp(callback) {
|
||||
|
||||
// No more fileDesc to synchronize
|
||||
if(uploadFileList.length === 0) {
|
||||
return syncUp(callback);
|
||||
}
|
||||
|
||||
// Dequeue a fileDesc to synchronize
|
||||
var fileDesc = uploadFileList.pop();
|
||||
uploadSyncAttributesList = _.values(fileDesc.syncLocations);
|
||||
if(uploadSyncAttributesList.length === 0) {
|
||||
return fileUp(callback);
|
||||
}
|
||||
|
||||
// Get document title/content
|
||||
uploadContent = fileDesc.content;
|
||||
uploadContentCRC = utils.crc32(uploadContent);
|
||||
uploadTitle = fileDesc.title;
|
||||
uploadTitleCRC = utils.crc32(uploadTitle);
|
||||
uploadDiscussionList = fileDesc.discussionListJSON;
|
||||
uploadDiscussionListCRC = utils.crc32(uploadDiscussionList);
|
||||
locationUp(callback);
|
||||
}
|
||||
|
||||
// Entry point for up synchronization (upload changes)
|
||||
var uploadCycle = false;
|
||||
function syncUp(callback) {
|
||||
var uploadFileList = [];
|
||||
|
||||
// Recursive function to upload multiple files
|
||||
function fileUp() {
|
||||
// No more fileDesc to synchronize
|
||||
if(uploadFileList.length === 0) {
|
||||
return syncUp(callback);
|
||||
}
|
||||
|
||||
// Dequeue a fileDesc to synchronize
|
||||
var fileDesc = uploadFileList.pop();
|
||||
var uploadSyncAttributesList = _.values(fileDesc.syncLocations);
|
||||
if(uploadSyncAttributesList.length === 0) {
|
||||
return fileUp();
|
||||
}
|
||||
|
||||
var uploadContent = fileDesc.content;
|
||||
var uploadContentCRC = utils.crc32(uploadContent);
|
||||
var uploadTitle = fileDesc.title;
|
||||
var uploadTitleCRC = utils.crc32(uploadTitle);
|
||||
var uploadDiscussionList = fileDesc.discussionListJSON;
|
||||
var uploadDiscussionListCRC = utils.crc32(uploadDiscussionList);
|
||||
|
||||
// Recursive function to upload a single file on multiple locations
|
||||
function locationUp() {
|
||||
|
||||
// No more synchronized location for this document
|
||||
if(uploadSyncAttributesList.length === 0) {
|
||||
return fileUp();
|
||||
}
|
||||
|
||||
// Dequeue a synchronized location
|
||||
var syncAttributes = uploadSyncAttributesList.pop();
|
||||
|
||||
syncAttributes.provider.syncUp(
|
||||
uploadContent,
|
||||
uploadContentCRC,
|
||||
uploadTitle,
|
||||
uploadTitleCRC,
|
||||
uploadDiscussionList,
|
||||
uploadDiscussionListCRC,
|
||||
syncAttributes,
|
||||
function(error, uploadFlag) {
|
||||
if(uploadFlag === true) {
|
||||
// If uploadFlag is true, request another upload cycle
|
||||
uploadCycle = true;
|
||||
}
|
||||
if(error) {
|
||||
return callback(error);
|
||||
}
|
||||
if(uploadFlag) {
|
||||
// Update syncAttributes in storage
|
||||
utils.storeAttributes(syncAttributes);
|
||||
}
|
||||
locationUp();
|
||||
}
|
||||
);
|
||||
}
|
||||
locationUp();
|
||||
}
|
||||
|
||||
if(uploadCycle === true) {
|
||||
// New upload cycle
|
||||
uploadCycle = false;
|
||||
uploadFileList = _.values(fileSystem);
|
||||
fileUp(callback);
|
||||
fileUp();
|
||||
}
|
||||
else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive function to download changes from multiple providers
|
||||
var providerList = [];
|
||||
function providerDown(callback) {
|
||||
if(providerList.length === 0) {
|
||||
return callback();
|
||||
}
|
||||
var provider = providerList.pop();
|
||||
|
||||
// Check that provider has files to sync
|
||||
if(!synchronizer.hasSync(provider)) {
|
||||
return providerDown(callback);
|
||||
}
|
||||
|
||||
// Perform provider's syncDown
|
||||
provider.syncDown(function(error) {
|
||||
if(error) {
|
||||
return callback(error);
|
||||
}
|
||||
providerDown(callback);
|
||||
});
|
||||
}
|
||||
|
||||
// Entry point for down synchronization (download changes)
|
||||
function syncDown(callback) {
|
||||
providerList = _.values(providerMap);
|
||||
providerDown(callback);
|
||||
var providerList = _.values(providerMap);
|
||||
|
||||
// Recursive function to download changes from multiple providers
|
||||
function providerDown() {
|
||||
if(providerList.length === 0) {
|
||||
return callback();
|
||||
}
|
||||
var provider = providerList.pop();
|
||||
|
||||
// Check that provider has files to sync
|
||||
if(!synchronizer.hasSync(provider)) {
|
||||
return providerDown();
|
||||
}
|
||||
|
||||
// Perform provider's syncDown
|
||||
provider.syncDown(function(error) {
|
||||
if(error) {
|
||||
return callback(error);
|
||||
}
|
||||
providerDown();
|
||||
});
|
||||
}
|
||||
providerDown();
|
||||
}
|
||||
|
||||
// Entry point for the autosync feature
|
||||
function autosyncAll(callback) {
|
||||
var autosyncFileList = _.filter(fileSystem, function(fileDesc) {
|
||||
return _.size(fileDesc.syncLocations) === 0;
|
||||
});
|
||||
|
||||
// Recursive function to autosync multiple files
|
||||
function fileAutosync() {
|
||||
// No more fileDesc to synchronize
|
||||
if(autosyncFileList.length === 0) {
|
||||
return callback();
|
||||
}
|
||||
var fileDesc = autosyncFileList.pop();
|
||||
|
||||
var providerList = _.filter(providerMap, function(provider) {
|
||||
return provider.autosyncConfig.mode == 'all';
|
||||
});
|
||||
function providerAutosync() {
|
||||
// No more provider
|
||||
if(providerList.length === 0) {
|
||||
return fileAutosync();
|
||||
}
|
||||
var provider = providerList.pop();
|
||||
|
||||
provider.autosyncFile(fileDesc.title, fileDesc.content, fileDesc.discussionListJSON, provider.autosyncConfig, function(error, syncAttributes) {
|
||||
if(error) {
|
||||
return callback(error);
|
||||
}
|
||||
fileDesc.addSyncLocation(syncAttributes);
|
||||
eventMgr.onSyncExportSuccess(fileDesc, syncAttributes);
|
||||
providerAutosync();
|
||||
});
|
||||
}
|
||||
|
||||
providerAutosync();
|
||||
}
|
||||
|
||||
fileAutosync();
|
||||
}
|
||||
|
||||
// Listen to offline status changes
|
||||
@ -214,17 +245,22 @@ define([
|
||||
return false;
|
||||
}
|
||||
|
||||
syncDown(function(error) {
|
||||
autosyncAll(function(error) {
|
||||
if(isError(error)) {
|
||||
return;
|
||||
}
|
||||
syncUp(function(error) {
|
||||
syncDown(function(error) {
|
||||
if(isError(error)) {
|
||||
return;
|
||||
}
|
||||
syncRunning = false;
|
||||
eventMgr.onSyncRunning(false);
|
||||
eventMgr.onSyncSuccess();
|
||||
syncUp(function(error) {
|
||||
if(isError(error)) {
|
||||
return;
|
||||
}
|
||||
syncRunning = false;
|
||||
eventMgr.onSyncRunning(false);
|
||||
eventMgr.onSyncSuccess();
|
||||
});
|
||||
});
|
||||
});
|
||||
return true;
|
||||
@ -261,7 +297,10 @@ define([
|
||||
eventMgr.addListener("onFileCreated", function(fileDesc) {
|
||||
if(_.size(fileDesc.syncLocations) === 0) {
|
||||
_.each(providerMap, function(provider) {
|
||||
provider.autosyncConfig.enabled && provider.autosyncFile(fileDesc.title, fileDesc.content, fileDesc.discussionListJSON, provider.autosyncConfig, function(error, syncAttributes) {
|
||||
if(provider.autosyncConfig.mode != 'new') {
|
||||
return;
|
||||
}
|
||||
provider.autosyncFile(fileDesc.title, fileDesc.content, fileDesc.discussionListJSON, provider.autosyncConfig, function(error, syncAttributes) {
|
||||
if(error) {
|
||||
return;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
<link rel="shortcut icon" href="res-min/img/stackedit-32.ico" type="image/x-icon">
|
||||
<meta name="description" content="Full-featured, open-source Markdown editor based on PageDown, the Markdown library used by Stack Overflow and the other Stack Exchange sites.">
|
||||
<meta name="author" content="Benoit Schweblin">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="msvalidate.01" content="5E47EE6F67B069C17E3CDD418351A612"
|
||||
/>
|
||||
<script>
|
||||
|
Loading…
Reference in New Issue
Block a user