aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/CurrentUserUtils.ts2
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx2
-rw-r--r--src/client/views/nodes/WebBox.tsx24
-rw-r--r--src/client/views/nodes/WebBoxRenderer.js183
-rw-r--r--src/client/views/nodes/formattedText/DashDocView.tsx2
5 files changed, 111 insertions, 102 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index eb0812cba..1c9f89fa0 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -689,7 +689,7 @@ export class CurrentUserUtils {
};
const reqdFuncs:{[key:string]:any} = {
...params.funcs,
- backgroundColor: params.scripts?.onClick /// a bit hacky. if onClick is set, then we assume it returns a color value when queried with '_readOnly_'. This will be true for toggle buttons, but not generally
+ backgroundColor: params.btnType === ButtonType.ToggleButton ? params.scripts?.onClick:undefined /// a bit hacky. if onClick is set, then we assume it returns a color value when queried with '_readOnly_'. This will be true for toggle buttons, but not generally
}
return DocUtils.AssignScripts(DocUtils.AssignOpts(btnDoc, reqdOpts) ?? Docs.Create.FontIconDocument(reqdOpts), params.scripts, reqdFuncs);
}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index a48906372..04c7b96e3 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -222,7 +222,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
panelWidth = () => this.sizeProvider?.width || this.props.PanelWidth?.();
panelHeight = () => this.sizeProvider?.height || this.props.PanelHeight?.();
screenToLocalTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.X, -this.Y);
- focusDoc = (doc: Doc) => this.props.focus(doc);
+ focusDoc = (doc: Doc) => this.props.focus(doc, {});
returnThis = () => this;
render() {
TraceMobx();
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 460edb7c2..db493934a 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -156,6 +156,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.rootDoc.thumbLockout = true; // lock to prevent multiple thumb updates.
CreateImage(this._webUrl.endsWith('/') ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl, this._iframe.contentDocument?.styleSheets ?? [], htmlString, nativeWidth, nativeHeight, scrollTop)
.then((data_url: any) => {
+ if (data_url.includes('<!DOCTYPE')) {
+ console.log('BAD DATA IN THUMB CREATION');
+ return;
+ }
VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + '-icon' + new Date().getTime(), true, this.layoutDoc[Id] + '-icon').then(returnedfilename =>
setTimeout(
action(() => {
@@ -369,10 +373,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
iframeScaling = () => 1 / this.props.ScreenToLocalTransform().Scale;
addStyleSheet(document: any, styleType: string = 'text/css') {
- const style = document.createElement('style');
- style.type = styleType;
- const sheets = document.head.appendChild(style);
- return (sheets as any).sheet;
+ if (document) {
+ const style = document.createElement('style');
+ style.type = styleType;
+ const sheets = document.head.appendChild(style);
+ return (sheets as any).sheet;
+ }
}
addStyleSheetRule(sheet: any, selector: any, css: any, selectorPrefix = '.') {
const propText =
@@ -381,7 +387,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
: Object.keys(css)
.map(p => p + ':' + (p === 'content' ? "'" + css[p] + "'" : css[p]))
.join(';');
- return sheet.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length);
+ return sheet?.insertRule(selectorPrefix + selector + '{' + propText + '}', sheet.cssRules.length);
}
_iframetimeout: any = undefined;
@@ -394,7 +400,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
this.addStyleSheetRule(this.addStyleSheet(this._iframe?.contentDocument), '::selection', { color: 'white', background: 'orange' }, '');
- let requrlraw = decodeURIComponent(iframe?.contentWindow?.location.href.replace(Utils.prepend('') + '/corsProxy/', '') ?? this._url.toString());
+ let href: Opt<string>;
+ try {
+ href = iframe?.contentWindow?.location.href;
+ } catch (e) {
+ href = undefined;
+ }
+ let requrlraw = decodeURIComponent(href?.replace(Utils.prepend('') + '/corsProxy/', '') ?? this._url.toString());
if (requrlraw !== this._url.toString()) {
if (requrlraw.match(/q=.*&/)?.length && this._url.toString().match(/q=.*&/)?.length) {
const matches = requrlraw.match(/[^a-zA-z]q=[^&]*/g);
diff --git a/src/client/views/nodes/WebBoxRenderer.js b/src/client/views/nodes/WebBoxRenderer.js
index f3f1bcf5c..cebb94d86 100644
--- a/src/client/views/nodes/WebBoxRenderer.js
+++ b/src/client/views/nodes/WebBoxRenderer.js
@@ -1,14 +1,13 @@
/**
- *
- * @param {StyleSheetList} styleSheets
+ *
+ * @param {StyleSheetList} styleSheets
*/
var ForeignHtmlRenderer = function (styleSheets) {
-
const self = this;
/**
- *
- * @param {String} binStr
+ *
+ * @param {String} binStr
*/
const binaryStringToBase64 = function (binStr) {
return new Promise(function (resolve) {
@@ -16,7 +15,7 @@ var ForeignHtmlRenderer = function (styleSheets) {
reader.readAsDataURL(binStr);
reader.onloadend = function () {
resolve(reader.result);
- }
+ };
});
};
@@ -24,11 +23,11 @@ var ForeignHtmlRenderer = function (styleSheets) {
return window.location.origin + extension;
}
function CorsProxy(url) {
- return prepend("/corsProxy/") + encodeURIComponent(url);
+ return prepend('/corsProxy/') + encodeURIComponent(url);
}
/**
- *
- * @param {String} url
+ *
+ * @param {String} url
* @returns {Promise}
*/
const getResourceAsBase64 = function (webUrl, inurl) {
@@ -37,35 +36,30 @@ var ForeignHtmlRenderer = function (styleSheets) {
//const url = inurl.startsWith("/") && !inurl.startsWith("//") ? webUrl + inurl : inurl;
//const url = CorsProxy(inurl.startsWith("/") && !inurl.startsWith("//") ? webUrl + inurl : inurl);// inurl.startsWith("http") ? CorsProxy(inurl) : inurl;
var url = inurl;
- if (inurl.startsWith("/static")) {
- url = (new URL(webUrl).origin + inurl);
- } else
- if ((inurl.startsWith("/") && !inurl.startsWith("//"))) {
- url = CorsProxy(new URL(webUrl).origin + inurl);
- } else if (!inurl.startsWith("http") && !inurl.startsWith("//")) {
- url = CorsProxy(webUrl + "/" + inurl);
- }
- xhr.open("GET", url);
+ if (inurl.startsWith('/static')) {
+ url = new URL(webUrl).origin + inurl;
+ } else if (inurl.startsWith('/') && !inurl.startsWith('//')) {
+ url = CorsProxy(new URL(webUrl).origin + inurl);
+ } else if (!inurl.startsWith('http') && !inurl.startsWith('//')) {
+ url = CorsProxy(webUrl + '/' + inurl);
+ }
+ xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.onreadystatechange = async function () {
if (xhr.readyState === 4 && xhr.status === 200) {
const resBase64 = await binaryStringToBase64(xhr.response);
- resolve(
- {
- "resourceUrl": inurl,
- "resourceBase64": resBase64
- }
- );
+ resolve({
+ resourceUrl: inurl,
+ resourceBase64: resBase64,
+ });
} else if (xhr.readyState === 4) {
- console.log("COULDN'T FIND: " + (inurl.startsWith("/") ? webUrl + inurl : inurl));
- resolve(
- {
- "resourceUrl": "",
- "resourceBase64": inurl
- }
- );
+ console.log("COULDN'T FIND: " + (inurl.startsWith('/') ? webUrl + inurl : inurl));
+ resolve({
+ resourceUrl: '',
+ resourceBase64: inurl,
+ });
}
};
@@ -74,8 +68,8 @@ var ForeignHtmlRenderer = function (styleSheets) {
};
/**
- *
- * @param {String[]} urls
+ *
+ * @param {String[]} urls
* @returns {Promise}
*/
const getMultipleResourcesAsBase64 = function (webUrl, urls) {
@@ -87,13 +81,13 @@ var ForeignHtmlRenderer = function (styleSheets) {
};
/**
- *
- * @param {String} str
- * @param {Number} startIndex
- * @param {String} prefixToken
+ *
+ * @param {String} str
+ * @param {Number} startIndex
+ * @param {String} prefixToken
* @param {String[]} suffixTokens
- *
- * @returns {String|null}
+ *
+ * @returns {String|null}
*/
const parseValue = function (str, startIndex, prefixToken, suffixTokens) {
const idx = str.indexOf(prefixToken, startIndex);
@@ -111,17 +105,17 @@ var ForeignHtmlRenderer = function (styleSheets) {
}
return {
- "foundAtIndex": idx,
- "value": val
- }
+ foundAtIndex: idx,
+ value: val,
+ };
};
/**
- *
- * @param {String} cssRuleStr
+ *
+ * @param {String} cssRuleStr
* @returns {String[]}
*/
- const getUrlsFromCssString = function (cssRuleStr, selector = "url(", delimiters = [')'], mustEndWithQuote = false) {
+ const getUrlsFromCssString = function (cssRuleStr, selector = 'url(', delimiters = [')'], mustEndWithQuote = false) {
const urlsFound = [];
let searchStartIndex = 0;
@@ -133,7 +127,7 @@ var ForeignHtmlRenderer = function (styleSheets) {
searchStartIndex = url.foundAtIndex + url.value.length;
if (mustEndWithQuote && url.value[url.value.length - 1] !== '"') continue;
const unquoted = removeQuotes(url.value);
- if (!unquoted /* || (!unquoted.startsWith('http')&& !unquoted.startsWith("/") )*/ || unquoted === 'http://' || unquoted === 'https://') {
+ if (!unquoted /* || (!unquoted.startsWith('http')&& !unquoted.startsWith("/") )*/ || unquoted === 'http://' || unquoted === 'https://') {
continue;
}
@@ -144,24 +138,24 @@ var ForeignHtmlRenderer = function (styleSheets) {
};
/**
- *
- * @param {String} html
+ *
+ * @param {String} html
* @returns {String[]}
*/
const getImageUrlsFromFromHtml = function (html) {
- return getUrlsFromCssString(html, "src=", [' ', '>', '\t'], true);
+ return getUrlsFromCssString(html, 'src=', [' ', '>', '\t'], true);
};
const getSourceUrlsFromFromHtml = function (html) {
- return getUrlsFromCssString(html, "source=", [' ', '>', '\t'], true);
+ return getUrlsFromCssString(html, 'source=', [' ', '>', '\t'], true);
};
/**
- *
+ *
* @param {String} str
* @returns {String}
*/
const removeQuotes = function (str) {
- return str.replace(/["']/g, "");
+ return str.replace(/["']/g, '');
};
const escapeRegExp = function (string) {
@@ -169,37 +163,33 @@ var ForeignHtmlRenderer = function (styleSheets) {
};
/**
- *
- * @param {String} contentHtml
+ *
+ * @param {String} contentHtml
* @param {Number} width
* @param {Number} height
- *
+ *
* @returns {Promise<String>}
*/
const buildSvgDataUri = async function (webUrl, contentHtml, width, height, scroll, xoff) {
-
return new Promise(async function (resolve, reject) {
-
/* !! The problems !!
- * 1. CORS (not really an issue, expect perhaps for images, as this is a general security consideration to begin with)
- * 2. Platform won't wait for external assets to load (fonts, images, etc.)
- */
+ * 1. CORS (not really an issue, expect perhaps for images, as this is a general security consideration to begin with)
+ * 2. Platform won't wait for external assets to load (fonts, images, etc.)
+ */
// copy styles
- let cssStyles = "";
+ let cssStyles = '';
let urlsFoundInCss = [];
for (let i = 0; i < styleSheets.length; i++) {
try {
- const rules = styleSheets[i].cssRules
+ const rules = styleSheets[i].cssRules;
for (let j = 0; j < rules.length; j++) {
const cssRuleStr = rules[j].cssText;
urlsFoundInCss.push(...getUrlsFromCssString(cssRuleStr));
cssStyles += cssRuleStr;
}
- } catch (e) {
-
- }
+ } catch (e) {}
}
// const fetchedResourcesFromStylesheets = await getMultipleResourcesAsBase64(webUrl, urlsFoundInCss);
@@ -210,30 +200,32 @@ var ForeignHtmlRenderer = function (styleSheets) {
// }
// }
- contentHtml = contentHtml.replace(/<source[^>]*>/g, "") // <picture> tags have a <source> which has a srcset field of image refs. instead of converting each, just use the default <img> of the picture
- .replace(/noscript/g, "div").replace(/<div class="mediaset"><\/div>/g, "") // when scripting isn't available (ie, rendering web pages here), <noscript> tags should become <div>'s. But for Brown CS, there's a layout problem if you leave the empty <mediaset> tag
- .replace(/<link[^>]*>/g, "") // don't need to keep any linked style sheets because we've already processed all style sheets above
- .replace(/srcset="([^ "]*)[^"]*"/g, "src=\"$1\""); // instead of converting each item in the srcset to a data url, just convert the first one and use that
- let urlsFoundInHtml = getImageUrlsFromFromHtml(contentHtml).filter(url => !url.startsWith("data:"));
+ contentHtml = contentHtml
+ .replace(/<source[^>]*>/g, '') // <picture> tags have a <source> which has a srcset field of image refs. instead of converting each, just use the default <img> of the picture
+ .replace(/noscript/g, 'div')
+ .replace(/<div class="mediaset"><\/div>/g, '') // when scripting isn't available (ie, rendering web pages here), <noscript> tags should become <div>'s. But for Brown CS, there's a layout problem if you leave the empty <mediaset> tag
+ .replace(/<link[^>]*>/g, '') // don't need to keep any linked style sheets because we've already processed all style sheets above
+ .replace(/srcset="([^ "]*)[^"]*"/g, 'src="$1"'); // instead of converting each item in the srcset to a data url, just convert the first one and use that
+ let urlsFoundInHtml = getImageUrlsFromFromHtml(contentHtml).filter(url => !url.startsWith('data:'));
const fetchedResources = webUrl ? await getMultipleResourcesAsBase64(webUrl, urlsFoundInHtml) : [];
for (let i = 0; i < fetchedResources.length; i++) {
const r = fetchedResources[i];
if (r.resourceUrl) {
- contentHtml = contentHtml.replace(new RegExp(escapeRegExp(r.resourceUrl), "g"), r.resourceBase64);
+ contentHtml = contentHtml.replace(new RegExp(escapeRegExp(r.resourceUrl), 'g'), r.resourceBase64);
}
}
- const styleElem = document.createElement("style");
- styleElem.innerHTML = cssStyles.replace("&gt;", ">").replace("&lt;", "<");
+ const styleElem = document.createElement('style');
+ styleElem.innerHTML = cssStyles.replace('&gt;', '>').replace('&lt;', '<');
- const styleElemString = new XMLSerializer().serializeToString(styleElem).replace(/&gt;/g, ">").replace(/&lt;/g, "<");
+ const styleElemString = new XMLSerializer().serializeToString(styleElem).replace(/&gt;/g, '>').replace(/&lt;/g, '<');
// create DOM element string that encapsulates styles + content
- const contentRootElem = document.createElement("body");
- contentRootElem.style.zIndex = "1111";
+ const contentRootElem = document.createElement('body');
+ contentRootElem.style.zIndex = '1111';
// contentRootElem.style.transform = "scale(0.08)"
contentRootElem.innerHTML = styleElemString + contentHtml;
- contentRootElem.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
+ contentRootElem.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
//document.body.appendChild(contentRootElem);
const contentRootElemString = new XMLSerializer().serializeToString(contentRootElem);
@@ -256,17 +248,17 @@ var ForeignHtmlRenderer = function (styleSheets) {
* @param {String} html
* @param {Number} width
* @param {Number} height
- *
+ *
* @return {Promise<Image>}
*/
this.renderToImage = async function (webUrl, html, width, height, scroll, xoff) {
return new Promise(async function (resolve, reject) {
const img = new Image();
- console.log("BUILDING SVG for:" + webUrl);
+ console.log('BUILDING SVG for:' + webUrl);
img.src = await buildSvgDataUri(webUrl, html, width, height, scroll, xoff);
img.onload = function () {
- console.log("IMAGE SVG created:" + webUrl);
+ console.log('IMAGE SVG created:' + webUrl);
resolve(img);
};
});
@@ -276,7 +268,7 @@ var ForeignHtmlRenderer = function (styleSheets) {
* @param {String} html
* @param {Number} width
* @param {Number} height
- *
+ *
* @return {Promise<Image>}
*/
this.renderToCanvas = async function (webUrl, html, width, height, scroll, xoff, oversample) {
@@ -298,7 +290,7 @@ var ForeignHtmlRenderer = function (styleSheets) {
* @param {String} html
* @param {Number} width
* @param {Number} height
- *
+ *
* @return {Promise<String>}
*/
this.renderToBase64Png = async function (webUrl, html, width, height, scroll, xoff, oversample) {
@@ -307,24 +299,30 @@ var ForeignHtmlRenderer = function (styleSheets) {
resolve(canvas.toDataURL('image/png'));
});
};
-
};
-
export function CreateImage(webUrl, styleSheets, html, width, height, scroll, xoff = 0, oversample = 1) {
- const val = (new ForeignHtmlRenderer(styleSheets)).renderToBase64Png(webUrl, html.replace(/docView-hack/g, 'documentView-hack').replace(/\n/g, "").replace(/<script((?!\/script).)*<\/script>/g, ""), width, height, scroll, xoff, oversample);
- return val;
+ return new ForeignHtmlRenderer(styleSheets).renderToBase64Png(
+ webUrl,
+ html
+ .replace(/docView-hack/g, 'documentView-hack')
+ .replace(/\n/g, '')
+ .replace(/<script((?!\/script).)*<\/script>/g, ''),
+ width,
+ height,
+ scroll,
+ xoff,
+ oversample
+ );
}
-
-
-var ClipboardUtils = new function () {
+var ClipboardUtils = new (function () {
var permissions = {
'image/bmp': true,
'image/gif': true,
'image/png': true,
'image/jpeg': true,
- 'image/tiff': true
+ 'image/tiff': true,
};
function getType(types) {
@@ -387,9 +385,8 @@ var ClipboardUtils = new function () {
callback(null, 'Clipboard is not supported.');
}
};
-};
-
+})();
export function pasteImageBitmap(callback) {
return ClipboardUtils.readImage(callback);
-} \ No newline at end of file
+}
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 73a711b9d..5f576be41 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -149,7 +149,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
const { scale, translateX, translateY } = Utils.GetScreenTransform(this._spanRef.current);
return new Transform(-translateX, -translateY, 1).scale(1 / scale);
};
- outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document); // ideally, this would scroll to show the focus target
+ outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document, {}); // ideally, this would scroll to show the focus target
onKeyDown = (e: any) => {
e.stopPropagation();