mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +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);
|
||||
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') {
|
||||
const ls = Object.assign({}, this.state.localSearch);
|
||||
ls.resultCount = arg0;
|
||||
|
@ -38,281 +38,286 @@
|
||||
<script src="./lib.js"></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) => {
|
||||
window.postMessage({ target: 'main', name: methodName, args: [ arg ] }, '*');
|
||||
}
|
||||
|
||||
contentElement.addEventListener('scroll', function(e) {
|
||||
if (ignoreNextScrollEvent) {
|
||||
ignoreNextScrollEvent = false;
|
||||
return;
|
||||
}
|
||||
const m = maxScrollTop();
|
||||
const percent = m ? contentElement.scrollTop / m : 0;
|
||||
setPercentScroll(percent);
|
||||
|
||||
ipcProxySendToHost('percentScroll', percent);
|
||||
});
|
||||
try {
|
||||
const contentElement = document.getElementById('content');
|
||||
|
||||
document.addEventListener('contextmenu', function(event) {
|
||||
let element = event.target;
|
||||
const ipc = {};
|
||||
|
||||
// To handle right clicks on resource icons
|
||||
if (element && !element.getAttribute('data-resource-id')) element = element.parentElement;
|
||||
window.addEventListener('message', webviewLib.logEnabledEventHandler(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;
|
||||
|
||||
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();
|
||||
const callName = event.data.name;
|
||||
const callData = event.data.data;
|
||||
|
||||
if (selectedText) {
|
||||
ipcProxySendToHost('contextMenu', {
|
||||
type: 'text',
|
||||
textToCopy: selectedText,
|
||||
});
|
||||
} else if (event.target.getAttribute('href')) {
|
||||
ipcProxySendToHost('contextMenu', {
|
||||
type: 'link',
|
||||
textToCopy: event.target.getAttribute('href'),
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
webviewLib.initialize({
|
||||
postMessage: ipcProxySendToHost,
|
||||
});
|
||||
// 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.
|
||||
|
||||
// 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', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
document.addEventListener('dragover', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
document.addEventListener('dragover', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
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';
|
||||
}
|
||||
|
||||
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)));
|
||||
throw error;
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -46,7 +46,12 @@ utils.errorImage = 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) {
|
||||
|
@ -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.options_ = options;
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ class NoteBodyViewer extends Component {
|
||||
|
||||
const injectedJs = [this.mdToHtml_.injectedJavaScript()];
|
||||
injectedJs.push(shim.injectedJs('webviewLib'));
|
||||
injectedJs.push('webviewLib.initialize({ postMessage: postMessage });');
|
||||
injectedJs.push('webviewLib.initialize({ postMessage: msg => { return postMessage(msg); } });');
|
||||
injectedJs.push(`
|
||||
const readyStateCheckInterval = setInterval(function() {
|
||||
if (document.readyState === "complete") {
|
||||
@ -177,6 +177,8 @@ class NoteBodyViewer extends Component {
|
||||
onMessage={(event) => {
|
||||
let msg = event.nativeEvent.data;
|
||||
|
||||
console.info('Got IPC message: ', msg);
|
||||
|
||||
if (msg.indexOf('checkboxclick:') === 0) {
|
||||
const newBody = shared.toggleCheckbox(msg, this.props.note.body);
|
||||
if (this.props.onCheckboxChange) this.props.onCheckboxChange(newBody);
|
||||
|
Loading…
Reference in New Issue
Block a user