Files
svgedit/dist/editor/embedapi.js
JFH 1af0cd0572 V7 preview (#480)
* #issue-fix The new menu will ask if you want to erase the current content but it will ignore the answer

* #issue-fix  dialog needs to be closer than the original

* #issue-fix main menu alignment changes

* #issue_fix double click and opensvg issue fixed

* #issue-fix process_cancel change to seConfirm

* #issue-fix review how the top toolbar display when many buttons are displayed

* #issue-fix unwanted css reoved

* #issue-fix BOTTOM TOOLS Make sure all features of the bottom toolbar are working

* #issue-fix IMPORT IMAGE menu open issue fixed

* #issue-fix alert dialog overwrite style

* #issue-fix lint issue fixed

* npm update + associated fixes

* #36 look of opacity button should like the zoom button (without the dropdown button)

* #37 Clicking anywhere on the bottom bar (for example below the opacity button is displaying the “color popup”.)

* #38 The opacity button does not update with the current element

* #42 When you import an image, it works well but the dialog should disappear automatically

* Fixes #53: 4th option for the background display fixed

* Fixes #53: 4th option for the background fixed

* #49 the x button does not work

* Fixes #41: Alignment fixes in bottom bar

* fix test scenario

* #39 opacity button/stroke size/radius button don’t allow the 0 value

* #41 The look and alignment of stroke size and stroke style should be consistent with the rest of the bottom bar.

* #44 Text font dropdown is broken

* #52 Fix the export

* Fixes #44: Text font dropdown fixed

* Fixes #44: Text font dropdown fixed

* Fixes #44: Text font dropdown fixed

* Fixes #44: Text font dropdown fixed

* Update index.html

* update husky

* fixes

* moves from index.html to js

* fix #66

* fix #48 first set of new icons

* Reorganize tools in left panel to be more intuitive

* Update button styles to adapt to new icons

* Fix #48 new set of icons for alignments

* Variabilisation of icon bkgd colors
Update of color choice to fit new icons design

* Update canvas and rulers colors

* Improve layer handle design

* Modernize SVG Logo but keeping original spirit

* Fix #48 continue improve icons

* Continue to reorganise left panel

* Update right panel handle for layers

* Fix #48 new set of icons for main menu

* Improve main menu design

* Rework menu organisation

* Rework menu organisation

* Update input element design

* New icons

* Improve Zoom Module

* Improve Color Picker Module

* New icons

* New icons

* #65 restore the feature of start/end marker lines partially did

* #64 The export dialog needs to include the quality options (except for PDF)

* #39 opacity button/stroke size/radius button don’t allow the 0 value

* #39 eslint changes

* #69 menu button style overwrite

* #65 restore the feature of start/end marker lines

* #43 With a small window, the look of the top toolbar is broken

* #43 tool top alignment revert

* #46 Move this jQuery component to a web component  for graduate and picker components

* #46 Move this jQuery component to a web component

* remove some non standard lint rules

* #46 picker convert as pure javascript changes

* #46 jquery plugin convert to pure javascript

* #46 jquery plugin change to pure javascript

* #46 jquery remove and convert to pure javascript

* #46 slider issue fixed

* #46 ColorValuePicker and js convertion

* #46 globals $ remov from slider class

* #46 jquery convert pure javascript changes

* #46 jquery to js convertion changes

* #46 paintbox and current element color set issue fixed

* #46 unwanted files removed

* #46 $.extend modify changes

* #46 extend modifiey changes

* #46 $.extend change to pure javascript

* #46 extend and data changes

* #46 jquery removed

* #45 These buttons don't work and dropdown is broken

* #45 These buttons don't work and dropdown is broken

* #45 These buttons don't work and dropdown is broken commit reverted

* #43 With a small window, the look of the top toolbar is broken

* Update jQuery.jPicker.js

* #76 draggable modification changes

* #76 jquery-ui-1.8.17.custom.min.js removed from editor

* #76 jquery ui file removed

* npm update

* #77 console issue fixed

* #77 <SVG> button issue fixed

* #77 shortkey issue fixed

* #77 jquery hotkeys plugin changes

* #77 hotkey plugin related changes

* #78 hotkey related code comment.

* #78 js-hotkeys/jquery.hotkeys.min.js file removed from svgedit.js

* #51 Rewrite the color palette without elix

* #81 unwanted files removed

* #81 folder name renamed

* #81 folder rename changes

* #81 jquery-ui  folder renamed

* #81 jquery modify changes

* #81 globals $ removed

Co-authored-by: Agriya Dev5 <agriya.dev5@agriya.in>
Co-authored-by: mathieucura <mathieu@optimistik.fr>
2021-03-05 12:45:07 +01:00

395 lines
12 KiB
JavaScript

/**
* Handles underlying communication between the embedding window and the
* editor frame.
* @module EmbeddedSVGEdit
*/
let cbid = 0;
/**
* @callback module:EmbeddedSVGEdit.CallbackSetter
* @param {GenericCallback} newCallback Callback to be stored (signature dependent on function)
* @returns {void}
*/
/**
* @callback module:EmbeddedSVGEdit.CallbackSetGetter
* @param {...any} args Signature dependent on the function
* @returns {module:EmbeddedSVGEdit.CallbackSetter}
*/
/**
* @param {string} funcName
* @returns {module:EmbeddedSVGEdit.CallbackSetGetter}
*/
function getCallbackSetter (funcName) {
return function (...args) {
const that = this, // New callback
callbackID = this.send(funcName, args, function () { /* empty fn */ }); // The callback (currently it's nothing, but will be set later)
return function (newCallback) {
that.callbacks[callbackID] = newCallback; // Set callback
};
};
}
/**
* Having this separate from messageListener allows us to
* avoid using JSON parsing (and its limitations) in the case
* of same domain control.
* @param {module:EmbeddedSVGEdit.EmbeddedSVGEdit} t The `this` value
* @param {PlainObject} data
* @param {JSON} data.result
* @param {string} data.error
* @param {Integer} data.id
* @returns {void}
*/
function addCallback (t, {result, error, id: callbackID}) {
if (typeof callbackID === 'number' && t.callbacks[callbackID]) {
// These should be safe both because we check `cbid` is numeric and
// because the calls are from trusted origins
if (result) {
t.callbacks[callbackID](result); // lgtm [js/unvalidated-dynamic-method-call]
} else {
t.callbacks[callbackID](error, 'error'); // lgtm [js/unvalidated-dynamic-method-call]
}
}
}
/**
* @param {Event} e
* @returns {void}
*/
function messageListener (e) {
// We accept and post strings as opposed to objects for the sake of IE9 support; this
// will most likely be changed in the future
if (!e.data || !['string', 'object'].includes(typeof e.data)) {
return;
}
const {allowedOrigins} = this,
data = typeof e.data === 'object' ? e.data : JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' ||
e.source !== this.frame.contentWindow ||
(!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin))
) {
console.error(
`The origin ${e.origin} was not whitelisted as an origin from ` +
`which responses may be received by this ${window.origin} script.`
);
return;
}
addCallback(this, data);
}
/**
* @callback module:EmbeddedSVGEdit.MessageListener
* @param {MessageEvent} e
* @returns {void}
*/
/**
* @param {module:EmbeddedSVGEdit.EmbeddedSVGEdit} t The `this` value
* @returns {module:EmbeddedSVGEdit.MessageListener} Event listener
*/
function getMessageListener (t) {
return function (e) {
messageListener.call(t, e);
};
}
/**
* Embedded SVG-edit API.
* General usage:
* - Have an iframe somewhere pointing to a version of svg-edit > r1000.
* @example
// Initialize the magic with:
const svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
// Pass functions in this format:
svgCanvas.setSvgString('string');
// Or if a callback is needed:
svgCanvas.setSvgString('string')(function (data, error) {
if (error) {
// There was an error
} else {
// Handle data
}
});
// Everything is done with the same API as the real svg-edit,
// and all documentation is unchanged.
// However, this file depends on the postMessage API which
// can only support JSON-serializable arguments and
// return values, so, for example, arguments whose value is
// 'undefined', a function, a non-finite number, or a built-in
// object like Date(), RegExp(), etc. will most likely not behave
// as expected. In such a case one may need to host
// the SVG editor on the same domain and reference the
// JavaScript methods on the frame itself.
// The only other difference is when handling returns:
// the callback notation is used instead.
const blah = new EmbeddedSVGEdit(window.frames.svgedit);
blah.clearSelection('woot', 'blah', 1337, [1, 2, 3, 4, 5, 'moo'], -42, {
a: 'tree', b: 6, c: 9
})(function () { console.log('GET DATA', args); });
*
* @memberof module:EmbeddedSVGEdit
*/
class EmbeddedSVGEdit {
/**
* @param {HTMLIFrameElement} frame
* @param {string[]} [allowedOrigins=[]] Array of origins from which incoming
* messages will be allowed when same origin is not used; defaults to none.
* If supplied, it should probably be the same as svgEditor's allowedOrigins
*/
constructor (frame, allowedOrigins) {
const that = this;
this.allowedOrigins = allowedOrigins || [];
// Initialize communication
this.frame = frame;
this.callbacks = {};
// List of functions extracted with this:
// Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
// for (const i=0,q=[],f = document.querySelectorAll('div.CFunction h3.CTitle a'); i < f.length; i++) { q.push(f[i].name); }; q
// const functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString',
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
// 'moveSelectedToLayer', 'clear'];
// Newer, well, it extracts things that aren't documented as well. All functions accessible through the normal thingy can now be accessed though the API
// const {svgCanvas} = frame.contentWindow;
// const l = [];
// for (const i in svgCanvas) { if (typeof svgCanvas[i] === 'function') { l.push(i);} };
// alert("['" + l.join("', '") + "']");
// Run in svgedit itself
const functions = [
'addExtension',
'addSVGElementFromJson',
'addToSelection',
'alignSelectedElements',
'assignAttributes',
'bind',
'call',
'changeSelectedAttribute',
'cleanupElement',
'clear',
'clearSelection',
'clearSvgContentElement',
'cloneLayer',
'cloneSelectedElements',
'convertGradients',
'convertToGroup',
'convertToNum',
'convertToPath',
'copySelectedElements',
'createLayer',
'cutSelectedElements',
'cycleElement',
'deleteCurrentLayer',
'deleteSelectedElements',
'embedImage',
'exportPDF',
'findDefs',
'getBBox',
'getBlur',
'getBold',
'getColor',
'getContentElem',
'getCurrentDrawing',
'getDocumentTitle',
'getEditorNS',
'getElem',
'getFillOpacity',
'getFontColor',
'getFontFamily',
'getFontSize',
'getHref',
'getId',
'getIntersectionList',
'getItalic',
'getMode',
'getMouseTarget',
'getNextId',
'getOffset',
'getOpacity',
'getPaintOpacity',
'getPrivateMethods',
'getRefElem',
'getResolution',
'getRootElem',
'getRotationAngle',
'getSelectedElems',
'getStrokeOpacity',
'getStrokeWidth',
'getStrokedBBox',
'getStyle',
'getSvgString',
'getText',
'getTitle',
'getTransformList',
'getUIStrings',
'getUrlFromAttr',
'getVersion',
'getVisibleElements',
'getVisibleElementsAndBBoxes',
'getZoom',
'groupSelectedElements',
'groupSvgElem',
'hasMatrixTransform',
'identifyLayers',
'importSvgString',
'leaveContext',
'linkControlPoints',
'makeHyperlink',
'matrixMultiply',
'mergeAllLayers',
'mergeLayer',
'moveSelectedElements',
'moveSelectedToLayer',
'moveToBottomSelectedElement',
'moveToTopSelectedElement',
'moveUpDownSelected',
'open',
'pasteElements',
'prepareSvg',
'pushGroupProperties',
'randomizeIds',
'rasterExport',
'ready',
'recalculateAllSelectedDimensions',
'recalculateDimensions',
'remapElement',
'removeFromSelection',
'removeHyperlink',
'removeUnusedDefElems',
'renameCurrentLayer',
'round',
'runExtensions',
'sanitizeSvg',
'save',
'selectAllInCurrentLayer',
'selectOnly',
'setBBoxZoom',
'setBackground',
'setBlur',
'setBlurNoUndo',
'setBlurOffsets',
'setBold',
'setColor',
'setConfig',
'setContext',
'setCurrentLayer',
'setCurrentLayerPosition',
'setDocumentTitle',
'setFillPaint',
'setFontColor',
'setFontFamily',
'setFontSize',
'setGoodImage',
'setGradient',
'setGroupTitle',
'setHref',
'setIdPrefix',
'setImageURL',
'setItalic',
'setLayerVisibility',
'setLinkURL',
'setMode',
'setOpacity',
'setPaint',
'setPaintOpacity',
'setRectRadius',
'setResolution',
'setRotationAngle',
'setSegType',
'setStrokeAttr',
'setStrokePaint',
'setStrokeWidth',
'setSvgString',
'setTextContent',
'setUiStrings',
'setUseData',
'setZoom',
'svgCanvasToString',
'svgToString',
'transformListToTransform',
'ungroupSelectedElement',
'uniquifyElems',
'updateCanvas',
'zoomChanged'
];
// TODO: rewrite the following, it's pretty scary.
for (const func of functions) {
this[func] = getCallbackSetter(func);
}
// Older IE may need a polyfill for addEventListener, but so it would for SVG
window.addEventListener('message', getMessageListener(this));
window.addEventListener('keydown', (e) => {
const {type, key} = e;
if (key === 'Backspace') {
e.preventDefault();
const keyboardEvent = new KeyboardEvent(type, {key});
that.frame.contentDocument.dispatchEvent(keyboardEvent);
}
});
}
/**
* @param {string} name
* @param {ArgumentsArray} args Signature dependent on function
* @param {GenericCallback} callback (This may be better than a promise in case adding an event.)
* @returns {Integer}
*/
send (name, args, callback) {
const that = this;
cbid++;
this.callbacks[cbid] = callback;
setTimeout((function (callbackID) {
return function () { // Delay for the callback to be set in case its synchronous
/*
* Todo: Handle non-JSON arguments and return values (undefined,
* nonfinite numbers, functions, and built-in objects like Date,
* RegExp), etc.? Allow promises instead of callbacks? Review
* SVG-Edit functions for whether JSON-able parameters can be
* made compatile with all API functionality
*/
// We accept and post strings for the sake of IE9 support
let sameOriginWithGlobal = false;
try {
sameOriginWithGlobal = window.location.origin === that.frame.contentWindow.location.origin &&
that.frame.contentWindow.svgEditor.svgCanvas;
}catch (err) {/* empty */}
if (sameOriginWithGlobal) {
// Although we do not really need this API if we are working same
// domain, it could allow us to write in a way that would work
// cross-domain as well, assuming we stick to the argument limitations
// of the current JSON-based communication API (e.g., not passing
// callbacks). We might be able to address these shortcomings; see
// the todo elsewhere in this file.
const message = {id: callbackID},
{svgEditor: {canvas: svgCanvas}} = that.frame.contentWindow;
try {
message.result = svgCanvas[name](...args);
} catch (err) {
message.error = err.message;
}
addCallback(that, message);
} else { // Requires the ext-xdomain-messaging.js extension
that.frame.contentWindow.postMessage(JSON.stringify({
namespace: 'svgCanvas', id: callbackID, name, args
}), '*');
}
};
}(cbid)), 0);
return cbid;
}
}
export default EmbeddedSVGEdit;