mirror of
https://github.com/laurent22/joplin.git
synced 2025-06-06 22:46:29 +02:00
Android: Fixed resource loading issue, and improved logging on desktop
This commit is contained in:
parent
43624ffa75
commit
aaaf27af6e
@ -671,6 +671,10 @@ class NoteTextComponent extends React.Component {
|
|||||||
|
|
||||||
const newBody = shared.toggleCheckbox(msg, this.state.note.body);
|
const newBody = shared.toggleCheckbox(msg, this.state.note.body);
|
||||||
this.saveOneProperty('body', newBody);
|
this.saveOneProperty('body', newBody);
|
||||||
|
} else if (msg.indexOf('error:') === 0) {
|
||||||
|
const s = msg.split(':');
|
||||||
|
s.splice(0, 1);
|
||||||
|
reg.logger().error(s.join(':'));
|
||||||
} else if (msg === 'setMarkerCount') {
|
} else if (msg === 'setMarkerCount') {
|
||||||
const ls = Object.assign({}, this.state.localSearch);
|
const ls = Object.assign({}, this.state.localSearch);
|
||||||
ls.resultCount = arg0;
|
ls.resultCount = arg0;
|
||||||
|
@ -38,281 +38,286 @@
|
|||||||
<script src="./lib.js"></script>
|
<script src="./lib.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const contentElement = document.getElementById('content');
|
|
||||||
|
|
||||||
const ipc = {};
|
|
||||||
|
|
||||||
window.addEventListener('message', (event) => {
|
|
||||||
// Here we only deal with messages that are sent from the main Electro process to the webview.
|
|
||||||
if (!event.data || event.data.target !== 'webview') return;
|
|
||||||
|
|
||||||
const callName = event.data.name;
|
|
||||||
const callData = event.data.data;
|
|
||||||
|
|
||||||
if (!ipc[callName]) {
|
|
||||||
console.warn('Missing IPC function:', event.data);
|
|
||||||
} else {
|
|
||||||
ipc[callName](callData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const loadedCssFiles_ = {};
|
|
||||||
function loadCssFiles(cssFiles) {
|
|
||||||
for (let i = 0; i < cssFiles.length; i++) {
|
|
||||||
const f = cssFiles[i];
|
|
||||||
if (loadedCssFiles_[f]) continue;
|
|
||||||
const link = document.createElement('link');
|
|
||||||
link.rel = 'stylesheet';
|
|
||||||
link.href = f;
|
|
||||||
document.getElementById('styleContainer').appendChild(link);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: the scroll position source of truth is "percentScroll_". This is easier to manage than scrollTop because
|
|
||||||
// the scrollTop value depends on the images being loaded or not. For example, if the scrollTop is saved while
|
|
||||||
// images are being displayed then restored while images are being reloaded, the new scrollTop might be changed
|
|
||||||
// so that it is not greater than contentHeight. On the other hand, with percentScroll it is possible to restore
|
|
||||||
// it at any time knowing that it's not going to be changed because the content height has changed.
|
|
||||||
// To restore percentScroll the "checkScrollIID" interval is used. It constantly resets the scroll position during
|
|
||||||
// one second after the content has been updated.
|
|
||||||
//
|
|
||||||
// ignoreNextScroll is used to differentiate between scroll event from the users and those that are the result
|
|
||||||
// of programmatically changing scrollTop. We only want to respond to events initiated by the user.
|
|
||||||
|
|
||||||
let percentScroll_ = 0;
|
|
||||||
let checkScrollIID_ = null;
|
|
||||||
|
|
||||||
function setPercentScroll(percent) {
|
|
||||||
percentScroll_ = percent;
|
|
||||||
contentElement.scrollTop = percentScroll_ * maxScrollTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
function percentScroll() {
|
|
||||||
return percentScroll_;
|
|
||||||
}
|
|
||||||
|
|
||||||
function restorePercentScroll() {
|
|
||||||
setPercentScroll(percentScroll_);
|
|
||||||
}
|
|
||||||
|
|
||||||
ipc.setHtml = (event) => {
|
|
||||||
const html = event.html;
|
|
||||||
|
|
||||||
markJsHackMarkerInserted_ = false;
|
|
||||||
|
|
||||||
updateBodyHeight();
|
|
||||||
|
|
||||||
contentElement.innerHTML = html;
|
|
||||||
|
|
||||||
let previousContentHeight = contentElement.scrollHeight;
|
|
||||||
let startTime = Date.now();
|
|
||||||
restorePercentScroll();
|
|
||||||
|
|
||||||
if (!checkScrollIID_) {
|
|
||||||
checkScrollIID_ = setInterval(() => {
|
|
||||||
const h = contentElement.scrollHeight;
|
|
||||||
if (h !== previousContentHeight) {
|
|
||||||
previousContentHeight = h;
|
|
||||||
restorePercentScroll();
|
|
||||||
}
|
|
||||||
if (Date.now() - startTime >= 1000) {
|
|
||||||
clearInterval(checkScrollIID_);
|
|
||||||
checkScrollIID_ = null;
|
|
||||||
}
|
|
||||||
}, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadCssFiles(event.options.cssFiles);
|
|
||||||
|
|
||||||
if (event.options.downloadResources === 'manual') {
|
|
||||||
webviewLib.setupResourceManualDownload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ignoreNextScrollEvent = false;
|
|
||||||
ipc.setPercentScroll = (event) => {
|
|
||||||
const percent = event.percent;
|
|
||||||
|
|
||||||
if (checkScrollIID_) {
|
|
||||||
clearInterval(checkScrollIID_);
|
|
||||||
checkScrollIID_ = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ignoreNextScrollEvent = true;
|
|
||||||
setPercentScroll(percent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// HACK for Mark.js bug - https://github.com/julmot/mark.js/issues/127
|
|
||||||
let markJsHackMarkerInserted_ = false;
|
|
||||||
function addMarkJsSpaceHack(document) {
|
|
||||||
if (markJsHackMarkerInserted_) return;
|
|
||||||
|
|
||||||
const prepareElementsForMarkJs = (elements, type) => {
|
|
||||||
// const markJsHackMarker_ = '​ ​'
|
|
||||||
const markJsHackMarker_ = ' ';
|
|
||||||
for (let i = 0; i < elements.length; i++) {
|
|
||||||
if (!type) {
|
|
||||||
elements[i].innerHTML = elements[i].innerHTML + markJsHackMarker_;
|
|
||||||
} else if (type === 'insertBefore') {
|
|
||||||
elements[i].insertAdjacentHTML('beforeBegin', markJsHackMarker_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareElementsForMarkJs(document.getElementsByTagName('p'));
|
|
||||||
prepareElementsForMarkJs(document.getElementsByTagName('div'));
|
|
||||||
prepareElementsForMarkJs(document.getElementsByTagName('br'), 'insertBefore');
|
|
||||||
markJsHackMarkerInserted_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mark_ = null;
|
|
||||||
let markSelectedElement_ = null;
|
|
||||||
function setMarkers(keywords, options = null) {
|
|
||||||
if (!options) options = {};
|
|
||||||
|
|
||||||
// TODO: Add support for scriptType on mobile and CLI
|
|
||||||
|
|
||||||
if (!mark_) {
|
|
||||||
mark_ = new Mark(document.getElementById('content'), {
|
|
||||||
exclude: ['img'],
|
|
||||||
acrossElements: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addMarkJsSpaceHack(document);
|
|
||||||
|
|
||||||
mark_.unmark()
|
|
||||||
|
|
||||||
if (markSelectedElement_) markSelectedElement_.classList.remove('mark-selected');
|
|
||||||
|
|
||||||
let selectedElement = null;
|
|
||||||
let elementIndex = 0;
|
|
||||||
|
|
||||||
const onEachElement = (element) => {
|
|
||||||
if (!('selectedIndex' in options)) return;
|
|
||||||
|
|
||||||
if (('selectedIndex' in options) && elementIndex === options.selectedIndex) {
|
|
||||||
markSelectedElement_ = element;
|
|
||||||
element.classList.add('mark-selected');
|
|
||||||
selectedElement = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
elementIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < keywords.length; i++) {
|
|
||||||
let keyword = keywords[i];
|
|
||||||
|
|
||||||
markJsUtils.markKeyword(mark_, keyword, {
|
|
||||||
pregQuote: pregQuote,
|
|
||||||
replaceRegexDiacritics: replaceRegexDiacritics,
|
|
||||||
}, {
|
|
||||||
each: onEachElement,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ipcProxySendToHost('setMarkerCount', elementIndex);
|
|
||||||
|
|
||||||
if (selectedElement) selectedElement.scrollIntoView();
|
|
||||||
}
|
|
||||||
|
|
||||||
let markLoaded_ = false;
|
|
||||||
ipc.setMarkers = (event) => {
|
|
||||||
const keywords = event.keywords;
|
|
||||||
const options = event.options;
|
|
||||||
|
|
||||||
if (!keywords.length && !markLoaded_) return;
|
|
||||||
|
|
||||||
if (!markLoaded_) {
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.onload = function() {
|
|
||||||
setMarkers(keywords, options);
|
|
||||||
};
|
|
||||||
|
|
||||||
script.src = '../../node_modules/mark.js/dist/mark.min.js';
|
|
||||||
document.getElementById('markScriptContainer').appendChild(script);
|
|
||||||
markLoaded_ = true;
|
|
||||||
} else {
|
|
||||||
setMarkers(keywords, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function maxScrollTop() {
|
|
||||||
return Math.max(0, contentElement.scrollHeight - contentElement.clientHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The body element needs to have a fixed height for the content to be scrollable
|
|
||||||
function updateBodyHeight() {
|
|
||||||
document.getElementById('body').style.height = window.innerHeight + 'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
const ipcProxySendToHost = (methodName, arg) => {
|
const ipcProxySendToHost = (methodName, arg) => {
|
||||||
window.postMessage({ target: 'main', name: methodName, args: [ arg ] }, '*');
|
window.postMessage({ target: 'main', name: methodName, args: [ arg ] }, '*');
|
||||||
}
|
}
|
||||||
|
|
||||||
contentElement.addEventListener('scroll', function(e) {
|
try {
|
||||||
if (ignoreNextScrollEvent) {
|
const contentElement = document.getElementById('content');
|
||||||
ignoreNextScrollEvent = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const m = maxScrollTop();
|
|
||||||
const percent = m ? contentElement.scrollTop / m : 0;
|
|
||||||
setPercentScroll(percent);
|
|
||||||
|
|
||||||
ipcProxySendToHost('percentScroll', percent);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.addEventListener('contextmenu', function(event) {
|
const ipc = {};
|
||||||
let element = event.target;
|
|
||||||
|
|
||||||
// To handle right clicks on resource icons
|
window.addEventListener('message', webviewLib.logEnabledEventHandler(event => {
|
||||||
if (element && !element.getAttribute('data-resource-id')) element = element.parentElement;
|
// Here we only deal with messages that are sent from the main Electro process to the webview.
|
||||||
|
if (!event.data || event.data.target !== 'webview') return;
|
||||||
|
|
||||||
if (element && element.getAttribute('data-resource-id')) {
|
const callName = event.data.name;
|
||||||
ipcProxySendToHost('contextMenu', {
|
const callData = event.data.data;
|
||||||
type: element.getAttribute('src') ? 'image' : 'resource',
|
|
||||||
resourceId: element.getAttribute('data-resource-id'),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const selectedText = window.getSelection().toString();
|
|
||||||
|
|
||||||
if (selectedText) {
|
if (!ipc[callName]) {
|
||||||
ipcProxySendToHost('contextMenu', {
|
console.warn('Missing IPC function:', event.data);
|
||||||
type: 'text',
|
} else {
|
||||||
textToCopy: selectedText,
|
ipc[callName](callData);
|
||||||
});
|
}
|
||||||
} else if (event.target.getAttribute('href')) {
|
}));
|
||||||
ipcProxySendToHost('contextMenu', {
|
|
||||||
type: 'link',
|
const loadedCssFiles_ = {};
|
||||||
textToCopy: event.target.getAttribute('href'),
|
function loadCssFiles(cssFiles) {
|
||||||
});
|
for (let i = 0; i < cssFiles.length; i++) {
|
||||||
|
const f = cssFiles[i];
|
||||||
|
if (loadedCssFiles_[f]) continue;
|
||||||
|
const link = document.createElement('link');
|
||||||
|
link.rel = 'stylesheet';
|
||||||
|
link.href = f;
|
||||||
|
document.getElementById('styleContainer').appendChild(link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
webviewLib.initialize({
|
// Note: the scroll position source of truth is "percentScroll_". This is easier to manage than scrollTop because
|
||||||
postMessage: ipcProxySendToHost,
|
// the scrollTop value depends on the images being loaded or not. For example, if the scrollTop is saved while
|
||||||
});
|
// images are being displayed then restored while images are being reloaded, the new scrollTop might be changed
|
||||||
|
// so that it is not greater than contentHeight. On the other hand, with percentScroll it is possible to restore
|
||||||
|
// it at any time knowing that it's not going to be changed because the content height has changed.
|
||||||
|
// To restore percentScroll the "checkScrollIID" interval is used. It constantly resets the scroll position during
|
||||||
|
// one second after the content has been updated.
|
||||||
|
//
|
||||||
|
// ignoreNextScroll is used to differentiate between scroll event from the users and those that are the result
|
||||||
|
// of programmatically changing scrollTop. We only want to respond to events initiated by the user.
|
||||||
|
|
||||||
// Disable drag and drop otherwise it's possible to drop a URL
|
let percentScroll_ = 0;
|
||||||
// on it and it will open in the view as a website.
|
let checkScrollIID_ = null;
|
||||||
document.addEventListener('drop', function(e) {
|
|
||||||
e.preventDefault();
|
function setPercentScroll(percent) {
|
||||||
e.stopPropagation();
|
percentScroll_ = percent;
|
||||||
});
|
contentElement.scrollTop = percentScroll_ * maxScrollTop();
|
||||||
document.addEventListener('dragover', function(e) {
|
}
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
function percentScroll() {
|
||||||
});
|
return percentScroll_;
|
||||||
document.addEventListener('dragover', function(e) {
|
}
|
||||||
e.preventDefault();
|
|
||||||
});
|
function restorePercentScroll() {
|
||||||
|
setPercentScroll(percentScroll_);
|
||||||
|
}
|
||||||
|
|
||||||
|
ipc.setHtml = (event) => {
|
||||||
|
const html = event.html;
|
||||||
|
|
||||||
|
markJsHackMarkerInserted_ = false;
|
||||||
|
|
||||||
|
updateBodyHeight();
|
||||||
|
|
||||||
|
contentElement.innerHTML = html;
|
||||||
|
|
||||||
|
let previousContentHeight = contentElement.scrollHeight;
|
||||||
|
let startTime = Date.now();
|
||||||
|
restorePercentScroll();
|
||||||
|
|
||||||
|
if (!checkScrollIID_) {
|
||||||
|
checkScrollIID_ = setInterval(() => {
|
||||||
|
const h = contentElement.scrollHeight;
|
||||||
|
if (h !== previousContentHeight) {
|
||||||
|
previousContentHeight = h;
|
||||||
|
restorePercentScroll();
|
||||||
|
}
|
||||||
|
if (Date.now() - startTime >= 1000) {
|
||||||
|
clearInterval(checkScrollIID_);
|
||||||
|
checkScrollIID_ = null;
|
||||||
|
}
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadCssFiles(event.options.cssFiles);
|
||||||
|
|
||||||
|
if (event.options.downloadResources === 'manual') {
|
||||||
|
webviewLib.setupResourceManualDownload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ignoreNextScrollEvent = false;
|
||||||
|
ipc.setPercentScroll = (event) => {
|
||||||
|
const percent = event.percent;
|
||||||
|
|
||||||
|
if (checkScrollIID_) {
|
||||||
|
clearInterval(checkScrollIID_);
|
||||||
|
checkScrollIID_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ignoreNextScrollEvent = true;
|
||||||
|
setPercentScroll(percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK for Mark.js bug - https://github.com/julmot/mark.js/issues/127
|
||||||
|
let markJsHackMarkerInserted_ = false;
|
||||||
|
function addMarkJsSpaceHack(document) {
|
||||||
|
if (markJsHackMarkerInserted_) return;
|
||||||
|
|
||||||
|
const prepareElementsForMarkJs = (elements, type) => {
|
||||||
|
// const markJsHackMarker_ = '​ ​'
|
||||||
|
const markJsHackMarker_ = ' ';
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
if (!type) {
|
||||||
|
elements[i].innerHTML = elements[i].innerHTML + markJsHackMarker_;
|
||||||
|
} else if (type === 'insertBefore') {
|
||||||
|
elements[i].insertAdjacentHTML('beforeBegin', markJsHackMarker_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareElementsForMarkJs(document.getElementsByTagName('p'));
|
||||||
|
prepareElementsForMarkJs(document.getElementsByTagName('div'));
|
||||||
|
prepareElementsForMarkJs(document.getElementsByTagName('br'), 'insertBefore');
|
||||||
|
markJsHackMarkerInserted_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mark_ = null;
|
||||||
|
let markSelectedElement_ = null;
|
||||||
|
function setMarkers(keywords, options = null) {
|
||||||
|
if (!options) options = {};
|
||||||
|
|
||||||
|
// TODO: Add support for scriptType on mobile and CLI
|
||||||
|
|
||||||
|
if (!mark_) {
|
||||||
|
mark_ = new Mark(document.getElementById('content'), {
|
||||||
|
exclude: ['img'],
|
||||||
|
acrossElements: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addMarkJsSpaceHack(document);
|
||||||
|
|
||||||
|
mark_.unmark()
|
||||||
|
|
||||||
|
if (markSelectedElement_) markSelectedElement_.classList.remove('mark-selected');
|
||||||
|
|
||||||
|
let selectedElement = null;
|
||||||
|
let elementIndex = 0;
|
||||||
|
|
||||||
|
const onEachElement = (element) => {
|
||||||
|
if (!('selectedIndex' in options)) return;
|
||||||
|
|
||||||
|
if (('selectedIndex' in options) && elementIndex === options.selectedIndex) {
|
||||||
|
markSelectedElement_ = element;
|
||||||
|
element.classList.add('mark-selected');
|
||||||
|
selectedElement = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
elementIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < keywords.length; i++) {
|
||||||
|
let keyword = keywords[i];
|
||||||
|
|
||||||
|
markJsUtils.markKeyword(mark_, keyword, {
|
||||||
|
pregQuote: pregQuote,
|
||||||
|
replaceRegexDiacritics: replaceRegexDiacritics,
|
||||||
|
}, {
|
||||||
|
each: onEachElement,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcProxySendToHost('setMarkerCount', elementIndex);
|
||||||
|
|
||||||
|
if (selectedElement) selectedElement.scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
|
let markLoaded_ = false;
|
||||||
|
ipc.setMarkers = (event) => {
|
||||||
|
const keywords = event.keywords;
|
||||||
|
const options = event.options;
|
||||||
|
|
||||||
|
if (!keywords.length && !markLoaded_) return;
|
||||||
|
|
||||||
|
if (!markLoaded_) {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.onload = function() {
|
||||||
|
setMarkers(keywords, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
script.src = '../../node_modules/mark.js/dist/mark.min.js';
|
||||||
|
document.getElementById('markScriptContainer').appendChild(script);
|
||||||
|
markLoaded_ = true;
|
||||||
|
} else {
|
||||||
|
setMarkers(keywords, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function maxScrollTop() {
|
||||||
|
return Math.max(0, contentElement.scrollHeight - contentElement.clientHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The body element needs to have a fixed height for the content to be scrollable
|
||||||
|
function updateBodyHeight() {
|
||||||
|
document.getElementById('body').style.height = window.innerHeight + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
contentElement.addEventListener('scroll', webviewLib.logEnabledEventHandler(e => {
|
||||||
|
if (ignoreNextScrollEvent) {
|
||||||
|
ignoreNextScrollEvent = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const m = maxScrollTop();
|
||||||
|
const percent = m ? contentElement.scrollTop / m : 0;
|
||||||
|
setPercentScroll(percent);
|
||||||
|
|
||||||
|
ipcProxySendToHost('percentScroll', percent);
|
||||||
|
}));
|
||||||
|
|
||||||
|
document.addEventListener('contextmenu', webviewLib.logEnabledEventHandler(event => {
|
||||||
|
let element = event.target;
|
||||||
|
|
||||||
|
// To handle right clicks on resource icons
|
||||||
|
if (element && !element.getAttribute('data-resource-id')) element = element.parentElement;
|
||||||
|
|
||||||
|
if (element && element.getAttribute('data-resource-id')) {
|
||||||
|
ipcProxySendToHost('contextMenu', {
|
||||||
|
type: element.getAttribute('src') ? 'image' : 'resource',
|
||||||
|
resourceId: element.getAttribute('data-resource-id'),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const selectedText = window.getSelection().toString();
|
||||||
|
|
||||||
|
if (selectedText) {
|
||||||
|
ipcProxySendToHost('contextMenu', {
|
||||||
|
type: 'text',
|
||||||
|
textToCopy: selectedText,
|
||||||
|
});
|
||||||
|
} else if (event.target.getAttribute('href')) {
|
||||||
|
ipcProxySendToHost('contextMenu', {
|
||||||
|
type: 'link',
|
||||||
|
textToCopy: event.target.getAttribute('href'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
webviewLib.initialize({
|
||||||
|
postMessage: ipcProxySendToHost,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disable drag and drop otherwise it's possible to drop a URL
|
||||||
|
// on it and it will open in the view as a website.
|
||||||
|
document.addEventListener('drop', webviewLib.logEnabledEventHandler(e => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}));
|
||||||
|
document.addEventListener('dragover', webviewLib.logEnabledEventHandler(e => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}));
|
||||||
|
document.addEventListener('dragover', webviewLib.logEnabledEventHandler(e => {
|
||||||
|
e.preventDefault();
|
||||||
|
}));
|
||||||
|
|
||||||
|
window.addEventListener('resize', webviewLib.logEnabledEventHandler(() => {
|
||||||
|
updateBodyHeight();
|
||||||
|
}));
|
||||||
|
|
||||||
window.addEventListener('resize', function() {
|
|
||||||
updateBodyHeight();
|
updateBodyHeight();
|
||||||
});
|
} catch (error) {
|
||||||
|
ipcProxySendToHost('error:' + JSON.stringify(webviewLib.cloneError(error)));
|
||||||
updateBodyHeight();
|
throw error;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@ -46,7 +46,12 @@ utils.errorImage = function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils.loaderImage = function() {
|
utils.loaderImage = function() {
|
||||||
return '<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0" width="16px" height="16px" viewBox="0 0 128 128" xml:space="preserve"><g><circle cx="16" cy="64" r="16" fill="#000000" fill-opacity="1"/><circle cx="16" cy="64" r="16" fill="#555555" fill-opacity="0.67" transform="rotate(45,64,64)"/><circle cx="16" cy="64" r="16" fill="#949494" fill-opacity="0.42" transform="rotate(90,64,64)"/><circle cx="16" cy="64" r="16" fill="#cccccc" fill-opacity="0.2" transform="rotate(135,64,64)"/><circle cx="16" cy="64" r="16" fill="#e1e1e1" fill-opacity="0.12" transform="rotate(180,64,64)"/><circle cx="16" cy="64" r="16" fill="#e1e1e1" fill-opacity="0.12" transform="rotate(225,64,64)"/><circle cx="16" cy="64" r="16" fill="#e1e1e1" fill-opacity="0.12" transform="rotate(270,64,64)"/><circle cx="16" cy="64" r="16" fill="#e1e1e1" fill-opacity="0.12" transform="rotate(315,64,64)"/><animateTransform attributeName="transform" type="rotate" values="0 64 64;315 64 64;270 64 64;225 64 64;180 64 64;135 64 64;90 64 64;45 64 64" calcMode="discrete" dur="720ms" repeatCount="indefinite"></animateTransform></g></svg>';
|
// https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/hourglass-half.svg
|
||||||
|
return `
|
||||||
|
<svg width="1536" height="1790" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1408 128c0 370-177 638-373 768 196 130 373 398 373 768h96c18 0 32 14 32 32v64c0 18-14 32-32 32H32c-18 0-32-14-32-32v-64c0-18 14-32 32-32h96c0-370 177-638 373-768-196-130-373-398-373-768H32c-18 0-32-14-32-32V32C0 14 14 0 32 0h1472c18 0 32 14 32 32v64c0 18-14 32-32 32h-96zm-128 0H256c0 146 33 275 85 384h854c52-109 85-238 85-384zm-57 1216c-74-193-207-330-340-384H653c-133 54-266 191-340 384h910z"/>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.resourceStatusImage = function(state) {
|
utils.resourceStatusImage = function(state) {
|
||||||
|
@ -63,6 +63,24 @@ webviewLib.getParentAnchorElement = function(element) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webviewLib.cloneError = function(error) {
|
||||||
|
return {
|
||||||
|
message: error.message,
|
||||||
|
stack: error.stack
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
webviewLib.logEnabledEventHandler = function(fn) {
|
||||||
|
return function(event) {
|
||||||
|
try {
|
||||||
|
return fn(event);
|
||||||
|
} catch (error) {
|
||||||
|
webviewLib.options_.postMessage('error:' + JSON.stringify(webviewLib.cloneError(error)));
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
webviewLib.initialize = function(options) {
|
webviewLib.initialize = function(options) {
|
||||||
webviewLib.options_ = options;
|
webviewLib.options_ = options;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ class NoteBodyViewer extends Component {
|
|||||||
|
|
||||||
const injectedJs = [this.mdToHtml_.injectedJavaScript()];
|
const injectedJs = [this.mdToHtml_.injectedJavaScript()];
|
||||||
injectedJs.push(shim.injectedJs('webviewLib'));
|
injectedJs.push(shim.injectedJs('webviewLib'));
|
||||||
injectedJs.push('webviewLib.initialize({ postMessage: postMessage });');
|
injectedJs.push('webviewLib.initialize({ postMessage: msg => { return postMessage(msg); } });');
|
||||||
injectedJs.push(`
|
injectedJs.push(`
|
||||||
const readyStateCheckInterval = setInterval(function() {
|
const readyStateCheckInterval = setInterval(function() {
|
||||||
if (document.readyState === "complete") {
|
if (document.readyState === "complete") {
|
||||||
@ -177,6 +177,8 @@ class NoteBodyViewer extends Component {
|
|||||||
onMessage={(event) => {
|
onMessage={(event) => {
|
||||||
let msg = event.nativeEvent.data;
|
let msg = event.nativeEvent.data;
|
||||||
|
|
||||||
|
console.info('Got IPC message: ', msg);
|
||||||
|
|
||||||
if (msg.indexOf('checkboxclick:') === 0) {
|
if (msg.indexOf('checkboxclick:') === 0) {
|
||||||
const newBody = shared.toggleCheckbox(msg, this.props.note.body);
|
const newBody = shared.toggleCheckbox(msg, this.props.note.body);
|
||||||
if (this.props.onCheckboxChange) this.props.onCheckboxChange(newBody);
|
if (this.props.onCheckboxChange) this.props.onCheckboxChange(newBody);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user