2010-01-12 20:39:03 +00:00
/ *
2009-11-22 20:13:06 +00:00
Embedded SVG - edit API
General usage :
- Have an iframe somewhere pointing to a version of svg - edit > r1000
- Initialize the magic with :
2014-01-31 04:54:49 +00:00
var svgCanvas = new EmbeddedSVGEdit ( window . frames . svgedit ) ;
2009-11-22 20:13:06 +00:00
- Pass functions in this format :
2014-02-22 04:08:24 +00:00
svgCanvas . setSvgString ( 'string' )
2009-11-22 20:13:06 +00:00
- Or if a callback is needed :
2014-02-22 04:08:24 +00:00
svgCanvas . setSvgString ( 'string' ) ( function ( data , error ) {
2014-01-31 04:54:49 +00:00
if ( error ) {
// There was an error
} else {
// Handle data
2009-11-22 20:13:06 +00:00
}
} )
2013-02-23 17:37:05 +00:00
Everything is done with the same API as the real svg - edit ,
2013-10-14 03:25:35 +00:00
and all documentation is unchanged .
2014-01-31 04:54:49 +00:00
However , this file depends on the postMessage API which
can only support JSON - serializable arguments and
2013-10-14 03:25:35 +00:00
return values , so , for example , arguments whose value is
2014-02-22 04:08:24 +00:00
'undefined' , a function , a non - finite number , or a built - in
2013-10-14 03:25:35 +00:00
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 .
2009-11-22 20:13:06 +00:00
2014-01-31 04:54:49 +00:00
var blah = new EmbeddedSVGEdit ( window . frames . svgedit ) ;
2014-02-22 04:08:24 +00:00
blah . clearSelection ( 'woot' , 'blah' , 1337 , [ 1 , 2 , 3 , 4 , 5 , 'moo' ] , - 42 , { a : 'tree' , b : 6 , c : 9 } ) ( function ( ) { console . log ( 'GET DATA' , arguments ) } )
2009-11-22 20:13:06 +00:00
* /
2013-10-13 23:59:32 +00:00
( function ( ) { 'use strict' ;
var cbid = 0 ;
function getCallbackSetter ( d ) {
2014-02-22 04:08:24 +00:00
return function ( ) {
2014-01-31 07:13:17 +00:00
var t = this , // New callback
2013-10-13 23:59:32 +00:00
args = [ ] . slice . call ( arguments ) ,
2014-01-31 07:13:17 +00:00
cbid = t . send ( d , args , function ( ) { } ) ; // The callback (currently it's nothing, but will be set later)
2013-10-13 23:59:32 +00:00
return function ( newcallback ) {
2014-01-31 07:13:17 +00:00
t . callbacks [ cbid ] = newcallback ; // Set callback
2013-10-13 23:59:32 +00:00
} ;
} ;
}
2014-02-22 04:08:24 +00:00
/ *
* Having this separate from messageListener allows us to
* avoid using JSON parsing ( and its limitations ) in the case
* of same domain control
* /
function addCallback ( t , data ) {
var result = data . result || data . error ;
cbid = data . id ;
if ( t . callbacks [ cbid ] ) {
if ( data . result ) {
t . callbacks [ cbid ] ( result ) ;
} else {
t . callbacks [ cbid ] ( result , 'error' ) ;
}
}
}
function messageListener ( e ) {
2014-03-02 01:11:23 +00:00
// We accept and post strings as opposed to objects for the sake of IE9 support; this
2014-02-22 04:08:24 +00:00
// will most likely be changed in the future
if ( typeof e . data !== 'string' ) {
return ;
}
2014-03-02 01:25:39 +00:00
var allowedOrigins = this . allowedOrigins ,
data = e . data && JSON . parse ( e . data ) ;
2014-03-02 01:11:23 +00:00
if ( ! data || typeof data !== 'object' || data . namespace !== 'svg-edit' ||
2014-03-02 01:25:39 +00:00
e . source !== this . frame . contentWindow ||
( allowedOrigins . indexOf ( '*' ) === - 1 && allowedOrigins . indexOf ( e . origin ) === - 1 )
2014-03-02 01:11:23 +00:00
) {
2014-02-22 04:08:24 +00:00
return ;
}
addCallback ( this , data ) ;
}
function getMessageListener ( t ) {
return function ( e ) {
messageListener . call ( t , e ) ;
} ;
}
2014-03-02 01:25:39 +00:00
/ * *
* @ param { HTMLFrame } frame
* @ param { array } [ 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
* /
function EmbeddedSVGEdit ( frame , allowedOrigins ) {
2014-02-22 04:08:24 +00:00
if ( ! ( this instanceof EmbeddedSVGEdit ) ) { // Allow invocation without 'new' keyword
2013-10-13 23:59:32 +00:00
return new EmbeddedSVGEdit ( frame ) ;
}
2014-03-02 01:25:39 +00:00
this . allowedOrigins = allowedOrigins || [ ] ;
2014-01-31 07:13:17 +00:00
// Initialize communication
2009-11-22 20:13:06 +00:00
this . frame = frame ;
2014-01-31 07:13:17 +00:00
this . callbacks = { } ;
// List of functions extracted with this:
// Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
2013-02-23 17:37:05 +00:00
2014-02-22 04:08:24 +00:00
// for (var i=0,q=[],f = document.querySelectorAll('div.CFunction h3.CTitle a'); i < f.length; i++) { q.push(f[i].name); }; q
// var functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString',
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
// 'moveSelectedToLayer', 'clear'];
2013-02-23 17:37:05 +00:00
2014-01-31 07:13:17 +00:00
// 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
2014-02-22 04:08:24 +00:00
// var l = []; for (var i in svgCanvas){ if (typeof svgCanvas[i] == 'function') { l.push(i);} };
2014-01-31 07:13:17 +00:00
// Run in svgedit itself
2013-10-13 23:59:32 +00:00
var i ,
2014-02-22 04:08:24 +00:00
functions = [ 'updateElementFromJson' , 'embedImage' , 'fixOperaXML' , 'clearSelection' ,
'addToSelection' ,
'removeFromSelection' , 'addNodeToSelection' , 'open' , 'save' , 'getSvgString' , 'setSvgString' , 'createLayer' ,
'deleteCurrentLayer' , 'getCurrentDrawing' , 'setCurrentLayer' , 'renameCurrentLayer' , 'setCurrentLayerPosition' ,
'setLayerVisibility' , 'moveSelectedToLayer' , 'clear' , 'clearPath' , 'getNodePoint' , 'clonePathNode' , 'deletePathNode' ,
'getResolution' , 'getImageTitle' , 'setImageTitle' , 'setResolution' , 'setBBoxZoom' , 'setZoom' , 'getMode' , 'setMode' ,
'getStrokeColor' , 'setStrokeColor' , 'getFillColor' , 'setFillColor' , 'setStrokePaint' , 'setFillPaint' , 'getStrokeWidth' ,
'setStrokeWidth' , 'getStrokeStyle' , 'setStrokeStyle' , 'getOpacity' , 'setOpacity' , 'getFillOpacity' , 'setFillOpacity' ,
'getStrokeOpacity' , 'setStrokeOpacity' , 'getTransformList' , 'getBBox' , 'getRotationAngle' , 'setRotationAngle' , 'each' ,
'bind' , 'setIdPrefix' , 'getBold' , 'setBold' , 'getItalic' , 'setItalic' , 'getFontFamily' , 'setFontFamily' , 'getFontSize' ,
'setFontSize' , 'getText' , 'setTextContent' , 'setImageURL' , 'setRectRadius' , 'setSegType' , 'quickClone' ,
'changeSelectedAttributeNoUndo' , 'changeSelectedAttribute' , 'deleteSelectedElements' , 'groupSelectedElements' , 'zoomChanged' ,
'ungroupSelectedElement' , 'moveToTopSelectedElement' , 'moveToBottomSelectedElement' , 'moveSelectedElements' ,
'getStrokedBBox' , 'getVisibleElements' , 'cycleElement' , 'getUndoStackSize' , 'getRedoStackSize' , 'getNextUndoCommandText' ,
'getNextRedoCommandText' , 'undo' , 'redo' , 'cloneSelectedElements' , 'alignSelectedElements' , 'getZoom' , 'getVersion' ,
'setIconSize' , 'setLang' , 'setCustomHandlers' ] ;
2013-02-23 17:37:05 +00:00
2013-10-13 23:59:32 +00:00
// TODO: rewrite the following, it's pretty scary.
2014-01-31 07:13:17 +00:00
for ( i = 0 ; i < functions . length ; i ++ ) {
2013-10-13 23:59:32 +00:00
this [ functions [ i ] ] = getCallbackSetter ( functions [ i ] ) ;
2009-11-22 20:13:06 +00:00
}
2014-02-22 04:08:24 +00:00
2013-10-13 23:59:32 +00:00
// Older IE may need a polyfill for addEventListener, but so it would for SVG
2014-02-22 04:08:24 +00:00
window . addEventListener ( 'message' , getMessageListener ( this ) , false ) ;
2009-11-22 20:13:06 +00:00
}
2014-02-22 04:08:24 +00:00
EmbeddedSVGEdit . prototype . send = function ( name , args , callback ) {
2009-11-22 20:33:12 +00:00
var t = this ;
2013-10-13 23:59:32 +00:00
cbid ++ ;
this . callbacks [ cbid ] = callback ;
2014-02-22 04:08:24 +00:00
setTimeout ( 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
* /
2013-10-14 01:24:52 +00:00
// We accept and post strings for the sake of IE9 support
2014-02-22 04:08:24 +00:00
if ( window . location . origin === t . frame . contentWindow . location . origin ) {
// 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.
var message = { id : cbid } ,
svgCanvas = t . frame . contentWindow . svgCanvas ;
try {
message . result = svgCanvas [ name ] . apply ( svgCanvas , args ) ;
}
catch ( err ) {
message . error = err . message ;
}
addCallback ( t , message ) ;
}
else { // Requires the ext-xdomain-messaging.js extension
t . frame . contentWindow . postMessage ( JSON . stringify ( { namespace : 'svgCanvas' , id : cbid , name : name , args : args } ) , '*' ) ;
}
2009-11-22 20:33:12 +00:00
} , 0 ) ;
return cbid ;
2013-02-23 17:37:05 +00:00
} ;
2013-10-13 23:59:32 +00:00
window . embedded _svg _edit = EmbeddedSVGEdit ; // Export old, deprecated API
window . EmbeddedSVGEdit = EmbeddedSVGEdit ; // Follows common JS convention of CamelCase and, as enforced in JSLint, of initial caps for constructors
} ( ) ) ;