wente
2024-06-13 c97306058f396705c10572b1d75b6f5891c9a25f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
function embedded_svg_edit(frame){
  //initialize communication
  this.frame = frame;
  this.stack = []; //callback stack
  
  var editapi = this;
  
  window.addEventListener("message", function(e){
    if(e.data.substr(0,5) == "ERROR"){
      editapi.stack.splice(0,1)[0](e.data,"error")
    }else{
      editapi.stack.splice(0,1)[0](e.data)
    }
  }, false)
}
 
embedded_svg_edit.prototype.call = function(code, callback){
  this.stack.push(callback);
  this.frame.contentWindow.postMessage(code,"*");
}
 
embedded_svg_edit.prototype.getSvgString = function(callback){
  this.call("svgCanvas.getSvgString()",callback)
}
 
embedded_svg_edit.prototype.setSvgString = function(svg){
  this.call("svgCanvas.setSvgString('"+svg.replace(/'/g, "\\'")+"')");
}
*/
 
 
/*
Embedded SVG-edit API
 
General usage:
- Have an iframe somewhere pointing to a version of svg-edit > r1000
- Initialize the magic with:
var svgCanvas = new embedded_svg_edit(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. The only difference is
when handling returns, the callback notation is used instead. 
 
var blah = new embedded_svg_edit(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",arguments)})
*/
 
function embedded_svg_edit(frame){
  //initialize communication
  this.frame = frame;
  //this.stack = [] //callback stack
  this.callbacks = {}; //successor to stack
  this.encode = embedded_svg_edit.encode;
  //List of functions extracted with this:
  //Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
  
  //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"];
  
  
  //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
  //var l=[];for(var i in svgCanvas){if(typeof svgCanvas[i] == "function"){l.push(i)}};
  //run in svgedit itself
  var 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",
    "ungroupSelectedElement", "moveToTopSelectedElement", "moveToBottomSelectedElement", "moveSelectedElements",
    "getStrokedBBox", "getVisibleElements", "cycleElement", "getUndoStackSize", "getRedoStackSize", "getNextUndoCommandText",
    "getNextRedoCommandText", "undo", "redo", "cloneSelectedElements", "alignSelectedElements", "getZoom", "getVersion",
    "setIconSize", "setLang", "setCustomHandlers"];
  
  //TODO: rewrite the following, it's pretty scary.
  for(var i = 0; i < functions.length; i++){
    this[functions[i]] = (function(d){
      return function(){
        var t = this //new callback
        for(var g = 0, args = []; g < arguments.length; g++){
          args.push(arguments[g]);
        }
        var cbid = t.send(d,args, function(){})  //the callback (currently it's nothing, but will be set later
        
        return function(newcallback){
          t.callbacks[cbid] = newcallback; //set callback
        }
      }
    })(functions[i])
  }
  //TODO: use AddEvent for Trident browsers, currently they dont support SVG, but they do support onmessage
  var t = this;
  window.addEventListener("message", function(e){
    if(e.data.substr(0,4)=="SVGe"){ //because svg-edit is too longish
      var data = e.data.substr(4);
      var cbid = data.substr(0, data.indexOf(";"));
      if(t.callbacks[cbid]){
        if(data.substr(0,6) != "error:"){
          t.callbacks[cbid](eval("("+data.substr(cbid.length+1)+")"))
        }else{
          t.callbacks[cbid](data, "error");
        }
      }
    }
    //this.stack.shift()[0](e.data,e.data.substr(0,5) == "ERROR"?'error':null) //replace with shift
  }, false)
}
 
embedded_svg_edit.encode = function(obj){
  //simple partial JSON encoder implementation
  if(window.JSON && JSON.stringify) return JSON.stringify(obj);
  var enc = arguments.callee; //for purposes of recursion
  
  if(typeof obj == "boolean" || typeof obj == "number"){
      return obj+'' //should work...
  }else if(typeof obj == "string"){
    //a large portion of this is stolen from Douglas Crockford's json2.js
    return '"'+
          obj.replace(
            /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g
          , function (a) {
            return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
          })
          +'"'; //note that this isn't quite as purtyful as the usualness
  }else if(obj.length){ //simple hackish test for arrayish-ness
    for(var i = 0; i < obj.length; i++){
      obj[i] = enc(obj[i]); //encode every sub-thingy on top
    }
    return "["+obj.join(",")+"]";
  }else{
    var pairs = []; //pairs will be stored here
    for(var k in obj){ //loop through thingys
      pairs.push(enc(k)+":"+enc(obj[k])); //key: value
    }
    return "{"+pairs.join(",")+"}" //wrap in the braces
  }
}
 
embedded_svg_edit.prototype.send = function(name, args, callback){
  var cbid = Math.floor(Math.random()*31776352877+993577).toString();
  //this.stack.push(callback);
  this.callbacks[cbid] = callback;
  for(var argstr = [], i = 0; i < args.length; i++){
    argstr.push(this.encode(args[i]))
  }
  var t = this;
  setTimeout(function(){//delay for the callback to be set in case its synchronous
    t.frame.contentWindow.postMessage(cbid+";svgCanvas['"+name+"']("+argstr.join(",")+")","*");
  }, 0);
  return cbid;
  //this.stack.shift()("svgCanvas['"+name+"']("+argstr.join(",")+")")
}