sketchily 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4969 +0,0 @@
1
- /*
2
- * svg-editor.js
3
- *
4
- * Licensed under the MIT License
5
- *
6
- * Copyright(c) 2010 Alexis Deveria
7
- * Copyright(c) 2010 Pavol Rusnak
8
- * Copyright(c) 2010 Jeff Schiller
9
- * Copyright(c) 2010 Narendra Sisodiya
10
- *
11
- */
12
-
13
- // Dependencies:
14
- // 1) units.js
15
- // 2) browser.js
16
- // 3) svgcanvas.js
17
-
18
- (function() {
19
-
20
- document.addEventListener("touchstart", touchHandler, true);
21
- document.addEventListener("touchmove", touchHandler, true);
22
- document.addEventListener("touchend", touchHandler, true);
23
- document.addEventListener("touchcancel", touchHandler, true);
24
-
25
- if(!window.svgEditor) window.svgEditor = function($) {
26
- var svgCanvas;
27
- var Editor = {};
28
- var is_ready = false;
29
-
30
- var defaultPrefs = {
31
- lang:'en',
32
- iconsize:'m',
33
- bkgd_color:'#FFF',
34
- bkgd_url:'',
35
- img_save:'embed'
36
- },
37
- curPrefs = {},
38
-
39
- // Note: Difference between Prefs and Config is that Prefs can be
40
- // changed in the UI and are stored in the browser, config can not
41
-
42
- curConfig = {
43
- canvasName: 'default',
44
- canvas_expansion: 3,
45
- dimensions: [640,480],
46
- initFill: {
47
- color: 'FF0000', // solid red
48
- opacity: 1
49
- },
50
- initStroke: {
51
- width: 5,
52
- color: '000000', // solid black
53
- opacity: 1
54
- },
55
- initOpacity: 1,
56
- imgPath: '/assets/images/',
57
- langPath: '/assets/locale/',
58
- extPath: '/assets/extensions/',
59
- jGraduatePath: '/assets/jgraduate/images/',
60
- extensions: ['ext-markers.js','ext-connector.js', 'ext-eyedropper.js', 'ext-shapes.js', 'ext-imagelib.js','ext-grid.js'],
61
- initTool: 'select',
62
- wireframe: false,
63
- colorPickerCSS: null,
64
- gridSnapping: false,
65
- gridColor: "#000",
66
- baseUnit: 'px',
67
- snappingStep: 10,
68
- showRulers: true
69
- },
70
- uiStrings = Editor.uiStrings = {
71
- common: {
72
- "ok":"OK",
73
- "cancel":"Cancel",
74
- "key_up":"Up",
75
- "key_down":"Down",
76
- "key_backspace":"Backspace",
77
- "key_del":"Del"
78
-
79
- },
80
- // This is needed if the locale is English, since the locale strings are not read in that instance.
81
- layers: {
82
- "layer":"Layer"
83
- },
84
- notification: {
85
- "invalidAttrValGiven":"Invalid value given",
86
- "noContentToFitTo":"No content to fit to",
87
- "dupeLayerName":"There is already a layer named that!",
88
- "enterUniqueLayerName":"Please enter a unique layer name",
89
- "enterNewLayerName":"Please enter the new layer name",
90
- "layerHasThatName":"Layer already has that name",
91
- "QmoveElemsToLayer":"Move selected elements to layer \"%s\"?",
92
- "QwantToClear":"Do you want to clear the drawing?\nThis will also erase your undo history!",
93
- "QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!",
94
- "QerrorsRevertToSource":"There were parsing errors in your SVG source.\nRevert back to original SVG source?",
95
- "QignoreSourceChanges":"Ignore changes made to SVG source?",
96
- "featNotSupported":"Feature not supported",
97
- "enterNewImgURL":"Enter the new image URL",
98
- "defsFailOnSave": "NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.",
99
- "loadingImage":"Loading image, please wait...",
100
- "saveFromBrowser": "Select \"Save As...\" in your browser to save this image as a %s file.",
101
- "noteTheseIssues": "Also note the following issues: ",
102
- "unsavedChanges": "There are unsaved changes.",
103
- "enterNewLinkURL": "Enter the new hyperlink URL",
104
- "errorLoadingSVG": "Error: Unable to load SVG data",
105
- "URLloadFail": "Unable to load from URL",
106
- "retrieving": 'Retrieving "%s" ...'
107
- }
108
- };
109
-
110
- var curPrefs = {}; //$.extend({}, defaultPrefs);
111
-
112
- var customHandlers = {};
113
-
114
- Editor.curConfig = curConfig;
115
-
116
- Editor.tool_scale = 1;
117
-
118
- // Store and retrieve preferences
119
- $.pref = function(key, val) {
120
- if(val) curPrefs[key] = val;
121
- key = 'svg-edit-'+key;
122
- var host = location.hostname,
123
- onweb = host && host.indexOf('.') >= 0,
124
- store = (val != undefined),
125
- storage = false;
126
- // Some FF versions throw security errors here
127
- try {
128
- if(window.localStorage) { // && onweb removed so Webkit works locally
129
- storage = localStorage;
130
- }
131
- } catch(e) {}
132
- try {
133
- if(window.globalStorage && onweb) {
134
- storage = globalStorage[host];
135
- }
136
- } catch(e) {}
137
-
138
- if(storage) {
139
- if(store) storage.setItem(key, val);
140
- else if (storage.getItem(key)) return storage.getItem(key) + ''; // Convert to string for FF (.value fails in Webkit)
141
- } else if(window.widget) {
142
- if(store) widget.setPreferenceForKey(val, key);
143
- else return widget.preferenceForKey(key);
144
- } else {
145
- if(store) {
146
- var d = new Date();
147
- d.setTime(d.getTime() + 31536000000);
148
- val = encodeURIComponent(val);
149
- document.cookie = key+'='+val+'; expires='+d.toUTCString();
150
- } else {
151
- var result = document.cookie.match(new RegExp(key + "=([^;]+)"));
152
- return result?decodeURIComponent(result[1]):'';
153
- }
154
- }
155
- }
156
-
157
- Editor.setConfig = function(opts) {
158
- $.each(opts, function(key, val) {
159
- // Only allow prefs defined in defaultPrefs
160
- if(key in defaultPrefs) {
161
- $.pref(key, val);
162
- }
163
- });
164
- $.extend(true, curConfig, opts);
165
- if(opts.extensions) {
166
- curConfig.extensions = opts.extensions;
167
- }
168
-
169
- }
170
-
171
- // Extension mechanisms must call setCustomHandlers with two functions: opts.open and opts.save
172
- // opts.open's responsibilities are:
173
- // - invoke a file chooser dialog in 'open' mode
174
- // - let user pick a SVG file
175
- // - calls setCanvas.setSvgString() with the string contents of that file
176
- // opts.save's responsibilities are:
177
- // - accept the string contents of the current document
178
- // - invoke a file chooser dialog in 'save' mode
179
- // - save the file to location chosen by the user
180
- Editor.setCustomHandlers = function(opts) {
181
- Editor.ready(function() {
182
- if(opts.open) {
183
- $('#tool_open > input[type="file"]').remove();
184
- $('#tool_open').show();
185
- svgCanvas.open = opts.open;
186
- }
187
- if(opts.save) {
188
- Editor.show_save_warning = false;
189
- svgCanvas.bind("saved", opts.save);
190
- }
191
- if(opts.pngsave) {
192
- svgCanvas.bind("exported", opts.pngsave);
193
- }
194
- customHandlers = opts;
195
- });
196
- }
197
-
198
- Editor.randomizeIds = function() {
199
- svgCanvas.randomizeIds(arguments)
200
- }
201
-
202
- Editor.init = function() {
203
- // For external openers
204
- (function() {
205
- // let the opener know SVG Edit is ready
206
- var w = window.opener;
207
- if (w) {
208
- try {
209
- var svgEditorReadyEvent = w.document.createEvent("Event");
210
- svgEditorReadyEvent.initEvent("svgEditorReady", true, true);
211
- w.document.documentElement.dispatchEvent(svgEditorReadyEvent);
212
- }
213
- catch(e) {}
214
- }
215
- })();
216
-
217
- /*(function() {
218
- // Load config/data from URL if given
219
- var urldata = $.deparam.querystring(true);
220
- if(!$.isEmptyObject(urldata)) {
221
- if(urldata.dimensions) {
222
- urldata.dimensions = urldata.dimensions.split(',');
223
- }
224
-
225
- if(urldata.extensions) {
226
- urldata.extensions = urldata.extensions.split(',');
227
- }
228
-
229
- if(urldata.bkgd_color) {
230
- urldata.bkgd_color = '#' + urldata.bkgd_color;
231
- }
232
-
233
- svgEditor.setConfig(urldata);
234
-
235
- var src = urldata.source;
236
- var qstr = $.param.querystring();
237
-
238
- if(!src) { // urldata.source may have been null if it ended with '='
239
- if(qstr.indexOf('source=data:') >= 0) {
240
- src = qstr.match(/source=(data:[^&]*)/)[1];
241
- }
242
- }
243
-
244
- if(src) {
245
- if(src.indexOf("data:") === 0) {
246
- // plusses get replaced by spaces, so re-insert
247
- src = src.replace(/ /g, "+");
248
- Editor.loadFromDataURI(src);
249
- } else {
250
- Editor.loadFromString(src);
251
- }
252
- } else if(qstr.indexOf('paramurl=') !== -1) {
253
- // Get paramater URL (use full length of remaining location.href)
254
- svgEditor.loadFromURL(qstr.substr(9));
255
- } else if(urldata.url) {
256
- svgEditor.loadFromURL(urldata.url);
257
- }
258
- } else {
259
- var name = 'svgedit-' + Editor.curConfig.canvasName;
260
- var cached = window.localStorage.getItem(name);
261
- if (cached) {
262
- Editor.loadFromString(cached);
263
- }
264
- }
265
- })();*/
266
-
267
- var extFunc = function() {
268
- $.each(curConfig.extensions, function() {
269
- var extname = this;
270
- $.getScript(curConfig.extPath + extname, function(d) {
271
- // Fails locally in Chrome 5
272
- if(!d) {
273
- var s = document.createElement('script');
274
- s.src = curConfig.extPath + extname;
275
- document.querySelector('head').appendChild(s);
276
- }
277
- });
278
- });
279
-
280
- var good_langs = [];
281
-
282
- $('#lang_select option').each(function() {
283
- good_langs.push(this.value);
284
- });
285
-
286
- // var lang = ('lang' in curPrefs) ? curPrefs.lang : null;
287
- Editor.putLocale(null, good_langs);
288
- }
289
-
290
- // Load extensions
291
- // Bit of a hack to run extensions in local Opera/IE9
292
- if(document.location.protocol === 'file:') {
293
- setTimeout(extFunc, 100);
294
- } else {
295
- extFunc();
296
- }
297
- $.svgIcons(curConfig.imgPath + 'svg_edit_icons.svg', {
298
- w:24, h:24,
299
- id_match: false,
300
- no_img: !svgedit.browser.isWebkit(), // Opera & Firefox 4 gives odd behavior w/images
301
- fallback_path: curConfig.imgPath,
302
- fallback:{
303
- 'new_image':'clear.png',
304
- 'save':'save.png',
305
- 'open':'open.png',
306
- 'source':'source.png',
307
- 'docprops':'document-properties.png',
308
- 'wireframe':'wireframe.png',
309
-
310
- 'undo':'undo.png',
311
- 'redo':'redo.png',
312
-
313
- 'select':'select.png',
314
- 'select_node':'select_node.png',
315
- 'pencil':'fhpath.png',
316
- 'pen':'line.png',
317
- 'square':'square.png',
318
- 'rect':'rect.png',
319
- 'fh_rect':'freehand-square.png',
320
- 'circle':'circle.png',
321
- 'ellipse':'ellipse.png',
322
- 'fh_ellipse':'freehand-circle.png',
323
- 'path':'path.png',
324
- 'text':'text.png',
325
- 'image':'image.png',
326
- 'zoom':'zoom.png',
327
-
328
- 'clone':'clone.png',
329
- 'node_clone':'node_clone.png',
330
- 'delete':'delete.png',
331
- 'node_delete':'node_delete.png',
332
- 'group':'shape_group.png',
333
- 'ungroup':'shape_ungroup.png',
334
- 'move_top':'move_top.png',
335
- 'move_bottom':'move_bottom.png',
336
- 'to_path':'to_path.png',
337
- 'link_controls':'link_controls.png',
338
- 'reorient':'reorient.png',
339
-
340
- 'align_left':'align-left.png',
341
- 'align_center':'align-center',
342
- 'align_right':'align-right',
343
- 'align_top':'align-top',
344
- 'align_middle':'align-middle',
345
- 'align_bottom':'align-bottom',
346
-
347
- 'go_up':'go-up.png',
348
- 'go_down':'go-down.png',
349
-
350
- 'ok':'save.png',
351
- 'cancel':'cancel.png',
352
-
353
- 'arrow_right':'flyouth.png',
354
- 'arrow_down':'dropdown.gif'
355
- },
356
- placement: {
357
- '#logo':'logo',
358
-
359
- '#tool_clear div,#layer_new':'new_image',
360
- '#tool_save div':'save',
361
- '#tool_export div':'export',
362
- '#tool_open div div':'open',
363
- '#tool_import div div':'import',
364
- '#tool_source':'source',
365
- '#tool_docprops > div':'docprops',
366
- '#tool_wireframe':'wireframe',
367
-
368
- '#tool_undo':'undo',
369
- '#tool_redo':'redo',
370
-
371
- '#tool_select':'select',
372
- '#tool_fhpath':'pencil',
373
- '#tool_line':'pen',
374
- '#tool_rect,#tools_rect_show':'rect',
375
- '#tool_square':'square',
376
- '#tool_fhrect':'fh_rect',
377
- '#tool_ellipse,#tools_ellipse_show':'ellipse',
378
- '#tool_circle':'circle',
379
- '#tool_fhellipse':'fh_ellipse',
380
- '#tool_path':'path',
381
- '#tool_text,#layer_rename':'text',
382
- '#tool_image':'image',
383
- '#tool_zoom':'zoom',
384
-
385
- '#tool_clone,#tool_clone_multi':'clone',
386
- '#tool_node_clone':'node_clone',
387
- '#layer_delete,#tool_delete,#tool_delete_multi':'delete',
388
- '#tool_node_delete':'node_delete',
389
- '#tool_add_subpath':'add_subpath',
390
- '#tool_openclose_path':'open_path',
391
- '#tool_move_top':'move_top',
392
- '#tool_move_bottom':'move_bottom',
393
- '#tool_topath':'to_path',
394
- '#tool_node_link':'link_controls',
395
- '#tool_reorient':'reorient',
396
- '#tool_group':'group',
397
- '#tool_ungroup':'ungroup',
398
- '#tool_unlink_use':'unlink_use',
399
-
400
- '#tool_alignleft, #tool_posleft':'align_left',
401
- '#tool_aligncenter, #tool_poscenter':'align_center',
402
- '#tool_alignright, #tool_posright':'align_right',
403
- '#tool_aligntop, #tool_postop':'align_top',
404
- '#tool_alignmiddle, #tool_posmiddle':'align_middle',
405
- '#tool_alignbottom, #tool_posbottom':'align_bottom',
406
- '#cur_position':'align',
407
-
408
- '#linecap_butt,#cur_linecap':'linecap_butt',
409
- '#linecap_round':'linecap_round',
410
- '#linecap_square':'linecap_square',
411
-
412
- '#linejoin_miter,#cur_linejoin':'linejoin_miter',
413
- '#linejoin_round':'linejoin_round',
414
- '#linejoin_bevel':'linejoin_bevel',
415
-
416
- '#url_notice':'warning',
417
-
418
- '#layer_up':'go_up',
419
- '#layer_down':'go_down',
420
- '#layer_moreopts':'context_menu',
421
- '#layerlist td.layervis':'eye',
422
-
423
- '#tool_source_save,#tool_docprops_save,#tool_prefs_save':'ok',
424
- '#tool_source_cancel,#tool_docprops_cancel,#tool_prefs_cancel':'cancel',
425
-
426
- '#rwidthLabel, #iwidthLabel':'width',
427
- '#rheightLabel, #iheightLabel':'height',
428
- '#cornerRadiusLabel span':'c_radius',
429
- '#angleLabel':'angle',
430
- '#linkLabel,#tool_make_link,#tool_make_link_multi':'globe_link',
431
- '#zoomLabel':'zoom',
432
- '#tool_fill label': 'fill',
433
- '#tool_stroke .icon_label': 'stroke',
434
- '#group_opacityLabel': 'opacity',
435
- '#blurLabel': 'blur',
436
- '#font_sizeLabel': 'fontsize',
437
-
438
- '.flyout_arrow_horiz':'arrow_right',
439
- '.dropdown button, #main_button .dropdown':'arrow_down',
440
- '#palette .palette_item:first, #fill_bg, #stroke_bg':'no_color'
441
- },
442
- resize: {
443
- '#logo .svg_icon': 28,
444
- '.flyout_arrow_horiz .svg_icon': 5,
445
- '.layer_button .svg_icon, #layerlist td.layervis .svg_icon': 14,
446
- '.dropdown button .svg_icon': 7,
447
- '#main_button .dropdown .svg_icon': 9,
448
- '.palette_item:first .svg_icon' : 15,
449
- '#fill_bg .svg_icon, #stroke_bg .svg_icon': 16,
450
- '.toolbar_button button .svg_icon':16,
451
- '.stroke_tool div div .svg_icon': 20,
452
- '#tools_bottom label .svg_icon': 18
453
- },
454
- callback: function(icons) {
455
- $('.toolbar_button button > svg, .toolbar_button button > img').each(function() {
456
- $(this).parent().prepend(this);
457
- });
458
-
459
- var tleft = $('#tools_left');
460
- if (tleft.length != 0) {
461
- var min_height = tleft.offset().top + tleft.outerHeight();
462
- }
463
- // var size = $.pref('iconsize');
464
- // if(size && size != 'm') {
465
- // svgEditor.setIconSize(size);
466
- // } else if($(window).height() < min_height) {
467
- // // Make smaller
468
- // svgEditor.setIconSize('s');
469
- // }
470
-
471
- // Look for any missing flyout icons from plugins
472
- $('.tools_flyout').each(function() {
473
- var shower = $('#' + this.id + '_show');
474
- var sel = shower.attr('data-curopt');
475
- // Check if there's an icon here
476
- if(!shower.children('svg, img').length) {
477
- var clone = $(sel).children().clone();
478
- if(clone.length) {
479
- clone[0].removeAttribute('style'); //Needed for Opera
480
- shower.append(clone);
481
- }
482
- }
483
- });
484
-
485
- svgEditor.runCallbacks();
486
-
487
- setTimeout(function() {
488
- $('.flyout_arrow_horiz:empty').each(function() {
489
- $(this).append($.getSvgIcon('arrow_right').width(5).height(5));
490
- });
491
- }, 1);
492
- }
493
- });
494
-
495
- Editor.canvas = svgCanvas = new $.SvgCanvas(document.getElementById("svgcanvas"), curConfig);
496
- Editor.show_save_warning = false;
497
- var palette = ["#000000", "#3f3f3f", "#7f7f7f", "#bfbfbf", "#ffffff",
498
- "#ff0000", "#ff7f00", "#ffff00", "#7fff00",
499
- "#00ff00", "#00ff7f", "#00ffff", "#007fff",
500
- "#0000ff", "#7f00ff", "#ff00ff", "#ff007f",
501
- "#7f0000", "#7f3f00", "#7f7f00", "#3f7f00",
502
- "#007f00", "#007f3f", "#007f7f", "#003f7f",
503
- "#00007f", "#3f007f", "#7f007f", "#7f003f",
504
- "#ffaaaa", "#ffd4aa", "#ffffaa", "#d4ffaa",
505
- "#aaffaa", "#aaffd4", "#aaffff", "#aad4ff",
506
- "#aaaaff", "#d4aaff", "#ffaaff", "#ffaad4"
507
- ],
508
- isMac = (navigator.platform.indexOf("Mac") >= 0),
509
- isWebkit = (navigator.userAgent.indexOf("AppleWebKit") >= 0),
510
- modKey = (isMac ? "meta+" : "ctrl+"), // ⌘
511
- path = svgCanvas.pathActions,
512
- undoMgr = svgCanvas.undoMgr,
513
- Utils = svgedit.utilities,
514
- default_img_url = curConfig.imgPath + "logo.png",
515
- workarea = $("#workarea"),
516
- canv_menu = $("#cmenu_canvas"),
517
- layer_menu = $("#cmenu_layers"),
518
- exportWindow = null,
519
- tool_scale = 1,
520
- zoomInIcon = 'crosshair',
521
- zoomOutIcon = 'crosshair',
522
- ui_context = 'toolbars',
523
- orig_source = '',
524
- paintBox = {fill: null, stroke:null};
525
-
526
- // This sets up alternative dialog boxes. They mostly work the same way as
527
- // their UI counterparts, expect instead of returning the result, a callback
528
- // needs to be included that returns the result as its first parameter.
529
- // In the future we may want to add additional types of dialog boxes, since
530
- // they should be easy to handle this way.
531
- (function() {
532
- $('#dialog_container').draggable({cancel:'#dialog_content, #dialog_buttons *', containment: 'window'});
533
- var box = $('#dialog_box'), btn_holder = $('#dialog_buttons');
534
-
535
- var dbox = function(type, msg, callback, defText) {
536
- $('#dialog_content').html('<p>'+msg.replace(/\n/g,'</p><p>')+'</p>')
537
- .toggleClass('prompt',(type=='prompt'));
538
- btn_holder.empty();
539
-
540
- var ok = $('<input type="button" value="' + uiStrings.common.ok + '">').appendTo(btn_holder);
541
-
542
- if(type != 'alert') {
543
- $('<input type="button" value="' + uiStrings.common.cancel + '">')
544
- .appendTo(btn_holder)
545
- .click(function() { box.hide();callback(false)});
546
- }
547
-
548
- if(type == 'prompt') {
549
- var input = $('<input type="text">').prependTo(btn_holder);
550
- input.val(defText || '');
551
- input.bind('keydown', 'return', function() {ok.click();});
552
- }
553
-
554
- if(type == 'process') {
555
- ok.hide();
556
- }
557
-
558
- box.show();
559
-
560
- ok.click(function() {
561
- box.hide();
562
- var resp = (type == 'prompt')?input.val():true;
563
- if(callback) callback(resp);
564
- }).focus();
565
-
566
- if(type == 'prompt') input.focus();
567
- }
568
-
569
- $.alert = function(msg, cb) { dbox('alert', msg, cb);};
570
- $.confirm = function(msg, cb) { dbox('confirm', msg, cb);};
571
- $.process_cancel = function(msg, cb) { dbox('process', msg, cb);};
572
- $.prompt = function(msg, txt, cb) { dbox('prompt', msg, cb, txt);};
573
- }());
574
-
575
- var setSelectMode = function() {
576
- var curr = $('.tool_button_current');
577
- if(curr.length && curr[0].id !== 'tool_select') {
578
- curr.removeClass('tool_button_current').addClass('tool_button');
579
- $('#tool_select').addClass('tool_button_current').removeClass('tool_button');
580
- $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}');
581
- }
582
- svgCanvas.setMode('select');
583
- workarea.css('cursor','auto');
584
- };
585
-
586
- var togglePathEditMode = function(editmode, elems) {
587
- $('#path_node_panel').toggle(editmode);
588
- $('#tools_bottom_2,#tools_bottom_3').toggle(!editmode);
589
- if(editmode) {
590
- // Change select icon
591
- $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button');
592
- $('#tool_select').addClass('tool_button_current').removeClass('tool_button');
593
- setIcon('#tool_select', 'select_node');
594
- multiselected = false;
595
- if(elems.length) {
596
- selectedElement = elems[0];
597
- }
598
- } else {
599
- setIcon('#tool_select', 'select');
600
- }
601
- }
602
-
603
- // used to make the flyouts stay on the screen longer the very first time
604
- var flyoutspeed = 1250;
605
- var textBeingEntered = false;
606
- var selectedElement = null;
607
- var multiselected = false;
608
- var editingsource = false;
609
- var docprops = false;
610
- var preferences = false;
611
- var cur_context = '';
612
- var orig_title = $('title:first').text();
613
-
614
- var saveHandler = function(window,svg) {
615
- Editor.show_save_warning = false;
616
-
617
- // by default, we add the XML prolog back, systems integrating SVG-edit (wikis, CMSs)
618
- // can just provide their own custom save handler and might not want the XML prolog
619
- svg = '<?xml version="1.0"?>\n' + svg;
620
-
621
- // Opens the SVG in new window, with warning about Mozilla bug #308590 when applicable
622
-
623
- var ua = navigator.userAgent;
624
-
625
- // Chrome 5 (and 6?) don't allow saving, show source instead ( http://code.google.com/p/chromium/issues/detail?id=46735 )
626
- // IE9 doesn't allow standalone Data URLs ( https://connect.microsoft.com/IE/feedback/details/542600/data-uri-images-fail-when-loaded-by-themselves )
627
- if((~ua.indexOf('Chrome') && $.browser.version >= 533) || ~ua.indexOf('MSIE')) {
628
- showSourceEditor(0,true);
629
- return;
630
- }
631
- var win = window.open("data:image/svg+xml;base64," + Utils.encode64(svg));
632
-
633
- // Alert will only appear the first time saved OR the first time the bug is encountered
634
- var done = $.pref('save_notice_done');
635
- if(done !== "all") {
636
-
637
- var note = uiStrings.notification.saveFromBrowser.replace('%s', 'SVG');
638
-
639
- // Check if FF and has <defs/>
640
- if(ua.indexOf('Gecko/') !== -1) {
641
- if(svg.indexOf('<defs') !== -1) {
642
- note += "\n\n" + uiStrings.notification.defsFailOnSave;
643
- $.pref('save_notice_done', 'all');
644
- done = "all";
645
- } else {
646
- $.pref('save_notice_done', 'part');
647
- }
648
- } else {
649
- $.pref('save_notice_done', 'all');
650
- }
651
-
652
- if(done !== 'part') {
653
- win.alert(note);
654
- }
655
- }
656
- };
657
-
658
- var exportHandler = function(window, data) {
659
- var issues = data.issues;
660
-
661
- if(!$('#export_canvas').length) {
662
- $('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
663
- }
664
- var c = $('#export_canvas')[0];
665
-
666
- c.width = svgCanvas.contentW;
667
- c.height = svgCanvas.contentH;
668
- canvg(c, data.svg, {renderCallback: function() {
669
- var datauri = c.toDataURL('image/png');
670
- exportWindow.location.href = datauri;
671
- var done = $.pref('export_notice_done');
672
- if(done !== "all") {
673
- var note = uiStrings.notification.saveFromBrowser.replace('%s', 'PNG');
674
-
675
- // Check if there's issues
676
- if(issues.length) {
677
- var pre = "\n \u2022 ";
678
- note += ("\n\n" + uiStrings.notification.noteTheseIssues + pre + issues.join(pre));
679
- }
680
-
681
- // Note that this will also prevent the notice even though new issues may appear later.
682
- // May want to find a way to deal with that without annoying the user
683
- $.pref('export_notice_done', 'all');
684
- exportWindow.alert(note);
685
- }
686
- }});
687
- };
688
-
689
- // called when we've selected a different element
690
- var selectedChanged = function(window,elems) {
691
- var mode = svgCanvas.getMode();
692
- if(mode === "select") setSelectMode();
693
- var is_node = (mode == "pathedit");
694
- // if elems[1] is present, then we have more than one element
695
- selectedElement = (elems.length == 1 || elems[1] == null ? elems[0] : null);
696
- multiselected = (elems.length >= 2 && elems[1] != null);
697
- if (selectedElement != null) {
698
- // unless we're already in always set the mode of the editor to select because
699
- // upon creation of a text element the editor is switched into
700
- // select mode and this event fires - we need our UI to be in sync
701
-
702
- if (!is_node) {
703
- updateToolbar();
704
- }
705
-
706
- } // if (elem != null)
707
-
708
- // Deal with pathedit mode
709
- togglePathEditMode(is_node, elems);
710
- updateContextPanel();
711
- svgCanvas.runExtensions("selectedChanged", {
712
- elems: elems,
713
- selectedElement: selectedElement,
714
- multiselected: multiselected
715
- });
716
- };
717
-
718
- // Call when part of element is in process of changing, generally
719
- // on mousemove actions like rotate, move, etc.
720
- var elementTransition = function(window,elems) {
721
- var mode = svgCanvas.getMode();
722
- var elem = elems[0];
723
-
724
- if(!elem) return;
725
-
726
- multiselected = (elems.length >= 2 && elems[1] != null);
727
- // Only updating fields for single elements for now
728
- if(!multiselected) {
729
- switch ( mode ) {
730
- case "rotate":
731
- var ang = svgCanvas.getRotationAngle(elem);
732
- $('#angle').val(ang);
733
- $('#tool_reorient').toggleClass('disabled', ang == 0);
734
- break;
735
-
736
- // TODO: Update values that change on move/resize, etc
737
- // case "select":
738
- // case "resize":
739
- // break;
740
- }
741
- }
742
- svgCanvas.runExtensions("elementTransition", {
743
- elems: elems
744
- });
745
- };
746
-
747
- // called when any element has changed
748
- var elementChanged = function(window,elems) {
749
- var mode = svgCanvas.getMode();
750
- if(mode === "select") {
751
- setSelectMode();
752
- }
753
-
754
- for (var i = 0; i < elems.length; ++i) {
755
- var elem = elems[i];
756
-
757
- // if the element changed was the svg, then it could be a resolution change
758
- if (elem && elem.tagName === "svg") {
759
- populateLayers();
760
- updateCanvas();
761
- }
762
- // Update selectedElement if element is no longer part of the image.
763
- // This occurs for the text elements in Firefox
764
- else if(elem && selectedElement && selectedElement.parentNode == null) {
765
- // || elem && elem.tagName == "path" && !multiselected) { // This was added in r1430, but not sure why
766
- selectedElement = elem;
767
- }
768
- }
769
-
770
- Editor.show_save_warning = true;
771
-
772
- // we update the contextual panel with potentially new
773
- // positional/sizing information (we DON'T want to update the
774
- // toolbar here as that creates an infinite loop)
775
- // also this updates the history buttons
776
-
777
- // we tell it to skip focusing the text control if the
778
- // text element was previously in focus
779
- updateContextPanel();
780
-
781
- // In the event a gradient was flipped:
782
- if(selectedElement && mode === "select") {
783
- paintBox.fill.update();
784
- paintBox.stroke.update();
785
- }
786
-
787
- svgCanvas.runExtensions("elementChanged", {
788
- elems: elems
789
- });
790
- };
791
-
792
- var zoomChanged = svgCanvas.zoomChanged = function(window, bbox, autoCenter) {
793
- var scrbar = 15,
794
- res = svgCanvas.getResolution(),
795
- w_area = workarea,
796
- canvas_pos = $('#svgcanvas').position();
797
- var z_info = svgCanvas.setBBoxZoom(bbox, w_area.width()-scrbar, w_area.height()-scrbar);
798
- if(!z_info) return;
799
- var zoomlevel = z_info.zoom,
800
- bb = z_info.bbox;
801
-
802
- if(zoomlevel < .001) {
803
- changeZoom({value: .1});
804
- return;
805
- }
806
-
807
- // $('#zoom').val(Math.round(zoomlevel*100));
808
- $('#zoom').val(zoomlevel*100);
809
-
810
- if(autoCenter) {
811
- updateCanvas();
812
- } else {
813
- updateCanvas(false, {x: bb.x * zoomlevel + (bb.width * zoomlevel)/2, y: bb.y * zoomlevel + (bb.height * zoomlevel)/2});
814
- }
815
-
816
- if(svgCanvas.getMode() == 'zoom' && bb.width) {
817
- // Go to select if a zoom box was drawn
818
- setSelectMode();
819
- }
820
-
821
- zoomDone();
822
- }
823
-
824
-
825
- $('#cur_context_panel').delegate('a', 'click', function() {
826
- var link = $(this);
827
- if(link.attr('data-root')) {
828
- svgCanvas.leaveContext();
829
- } else {
830
- svgCanvas.setContext(link.text());
831
- }
832
- svgCanvas.clearSelection();
833
- return false;
834
- });
835
-
836
- var contextChanged = function(win, context) {
837
- var link_str = '';
838
- if(context) {
839
- var str = '';
840
- link_str = '<a href="#" data-root="y">' + svgCanvas.getCurrentDrawing().getCurrentLayerName() + '</a>';
841
-
842
- $(context).parentsUntil('#svgcontent > g').andSelf().each(function() {
843
- if(this.id) {
844
- str += ' > ' + this.id;
845
- if(this !== context) {
846
- link_str += ' > <a href="#">' + this.id + '</a>';
847
- } else {
848
- link_str += ' > ' + this.id;
849
- }
850
- }
851
- });
852
-
853
- cur_context = str;
854
- } else {
855
- cur_context = null;
856
- }
857
- $('#cur_context_panel').toggle(!!context).html(link_str);
858
-
859
-
860
- updateTitle();
861
- }
862
-
863
- // Makes sure the current selected paint is available to work with
864
- var prepPaints = function() {
865
- paintBox.fill.prep();
866
- paintBox.stroke.prep();
867
- }
868
-
869
- var flyout_funcs = {};
870
-
871
- var setupFlyouts = function(holders) {
872
- $.each(holders, function(hold_sel, btn_opts) {
873
- var buttons = $(hold_sel).children();
874
- var show_sel = hold_sel + '_show';
875
- var shower = $(show_sel);
876
- var def = false;
877
- buttons.addClass('tool_button')
878
- .unbind('click mousedown mouseup') // may not be necessary
879
- .each(function(i) {
880
- // Get this buttons options
881
- var opts = btn_opts[i];
882
-
883
- // Remember the function that goes with this ID
884
- flyout_funcs[opts.sel] = opts.fn;
885
-
886
- if(opts.isDefault) def = i;
887
-
888
- // Clicking the icon in flyout should set this set's icon
889
- var func = function(event) {
890
- var options = opts;
891
- //find the currently selected tool if comes from keystroke
892
- if (event.type === "keydown") {
893
- var flyoutIsSelected = $(options.parent + "_show").hasClass('tool_button_current');
894
- var currentOperation = $(options.parent + "_show").attr("data-curopt");
895
- $.each(holders[opts.parent], function(i, tool){
896
- if (tool.sel == currentOperation) {
897
- if(!event.shiftKey || !flyoutIsSelected) {
898
- options = tool;
899
- }
900
- else {
901
- options = holders[opts.parent][i+1] || holders[opts.parent][0];
902
- }
903
- }
904
- });
905
- }
906
- if($(this).hasClass('disabled')) return false;
907
- if (toolButtonClick(show_sel)) {
908
- options.fn();
909
- }
910
- if(options.icon) {
911
- var icon = $.getSvgIcon(options.icon, true);
912
- } else {
913
- var icon = $(options.sel).children().eq(0).clone();
914
- }
915
-
916
- icon[0].setAttribute('width',shower.width());
917
- icon[0].setAttribute('height',shower.height());
918
- shower.children(':not(.flyout_arrow_horiz)').remove();
919
- shower.append(icon).attr('data-curopt', options.sel); // This sets the current mode
920
- }
921
-
922
- $(this).mouseup(func);
923
-
924
- if(opts.key) {
925
- $(document).bind('keydown', opts.key[0] + " shift+" + opts.key[0], func);
926
- }
927
- });
928
-
929
- if(def) {
930
- shower.attr('data-curopt', btn_opts[def].sel);
931
- } else if(!shower.attr('data-curopt')) {
932
- // Set first as default
933
- shower.attr('data-curopt', btn_opts[0].sel);
934
- }
935
-
936
- var timer;
937
-
938
- var pos = $(show_sel).position();
939
- $(hold_sel).css({'left': pos.left+34, 'top': pos.top+40});
940
-
941
- // Clicking the "show" icon should set the current mode
942
- shower.mousedown(function(evt) {
943
- if(shower.hasClass('disabled')) return false;
944
- var holder = $(hold_sel);
945
- var l = pos.left+34;
946
- var w = holder.width()*-1;
947
- var time = holder.data('shown_popop')?200:0;
948
- timer = setTimeout(function() {
949
- // Show corresponding menu
950
- if(!shower.data('isLibrary')) {
951
- holder.css('left', w).show().animate({
952
- left: l
953
- },150);
954
- } else {
955
- holder.css('left', l).show();
956
- }
957
- holder.data('shown_popop',true);
958
- },time);
959
- evt.preventDefault();
960
- }).mouseup(function(evt) {
961
- clearTimeout(timer);
962
- var opt = $(this).attr('data-curopt');
963
- // Is library and popped up, so do nothing
964
- if(shower.data('isLibrary') && $(show_sel.replace('_show','')).is(':visible')) {
965
- toolButtonClick(show_sel, true);
966
- return;
967
- }
968
- if (toolButtonClick(show_sel) && (opt in flyout_funcs)) {
969
- flyout_funcs[opt]();
970
- }
971
- });
972
-
973
- // $('#tools_rect').mouseleave(function(){$('#tools_rect').fadeOut();});
974
- });
975
-
976
- setFlyoutTitles();
977
- }
978
-
979
- var makeFlyoutHolder = function(id, child) {
980
- var div = $('<div>',{
981
- 'class': 'tools_flyout',
982
- id: id
983
- }).appendTo('#svg_editor').append(child);
984
-
985
- return div;
986
- }
987
-
988
- var setFlyoutPositions = function() {
989
- $('.tools_flyout').each(function() {
990
- var shower = $('#' + this.id + '_show');
991
- var pos = shower.offset();
992
- var w = shower.outerWidth();
993
- $(this).css({left: (pos.left + w)*tool_scale, top: pos.top});
994
- });
995
- }
996
-
997
- var setFlyoutTitles = function() {
998
- $('.tools_flyout').each(function() {
999
- var shower = $('#' + this.id + '_show');
1000
- if(shower.data('isLibrary')) return;
1001
-
1002
- var tooltips = [];
1003
- $(this).children().each(function() {
1004
- tooltips.push(this.title);
1005
- });
1006
- shower[0].title = tooltips.join(' / ');
1007
- });
1008
- }
1009
-
1010
- var resize_timer;
1011
-
1012
- var extAdded = function(window, ext) {
1013
-
1014
- var cb_called = false;
1015
- var resize_done = false;
1016
- var cb_ready = true; // Set to false to delay callback (e.g. wait for $.svgIcons)
1017
-
1018
- function prepResize() {
1019
- if(resize_timer) {
1020
- clearTimeout(resize_timer);
1021
- resize_timer = null;
1022
- }
1023
- if(!resize_done) {
1024
- resize_timer = setTimeout(function() {
1025
- resize_done = true;
1026
- setIconSize(curPrefs.iconsize);
1027
- }, 50);
1028
- }
1029
- }
1030
-
1031
-
1032
- var runCallback = function() {
1033
- if(ext.callback && !cb_called && cb_ready) {
1034
- cb_called = true;
1035
- ext.callback();
1036
- }
1037
- }
1038
-
1039
- var btn_selects = [];
1040
-
1041
- if(ext.context_tools) {
1042
- $.each(ext.context_tools, function(i, tool) {
1043
- // Add select tool
1044
- var cont_id = tool.container_id?(' id="' + tool.container_id + '"'):"";
1045
-
1046
- var panel = $('#' + tool.panel);
1047
-
1048
- // create the panel if it doesn't exist
1049
- if(!panel.length)
1050
- panel = $('<div>', {id: tool.panel}).appendTo("#tools_top");
1051
-
1052
- // TODO: Allow support for other types, or adding to existing tool
1053
- switch (tool.type) {
1054
- case 'tool_button':
1055
- var html = '<div class="tool_button">' + tool.id + '</div>';
1056
- var div = $(html).appendTo(panel);
1057
- if (tool.events) {
1058
- $.each(tool.events, function(evt, func) {
1059
- $(div).bind(evt, func);
1060
- });
1061
- }
1062
- break;
1063
- case 'select':
1064
- var html = '<label' + cont_id + '>'
1065
- + '<select id="' + tool.id + '">';
1066
- $.each(tool.options, function(val, text) {
1067
- var sel = (val == tool.defval) ? " selected":"";
1068
- html += '<option value="'+val+'"' + sel + '>' + text + '</option>';
1069
- });
1070
- html += "</select></label>";
1071
- // Creates the tool, hides & adds it, returns the select element
1072
- var sel = $(html).appendTo(panel).find('select');
1073
-
1074
- $.each(tool.events, function(evt, func) {
1075
- $(sel).bind(evt, func);
1076
- });
1077
- break;
1078
- case 'button-select':
1079
- var html = '<div id="' + tool.id + '" class="dropdown toolset" title="' + tool.title + '">'
1080
- + '<div id="cur_' + tool.id + '" class="icon_label"></div><button></button></div>';
1081
-
1082
- var list = $('<ul id="' + tool.id + '_opts"></ul>').appendTo('#option_lists');
1083
-
1084
- if(tool.colnum) {
1085
- list.addClass('optcols' + tool.colnum);
1086
- }
1087
-
1088
- // Creates the tool, hides & adds it, returns the select element
1089
- var dropdown = $(html).appendTo(panel).children();
1090
-
1091
- btn_selects.push({
1092
- elem: ('#' + tool.id),
1093
- list: ('#' + tool.id + '_opts'),
1094
- title: tool.title,
1095
- callback: tool.events.change,
1096
- cur: ('#cur_' + tool.id)
1097
- });
1098
-
1099
- break;
1100
- case 'input':
1101
- var html = '<label' + cont_id + '>'
1102
- + '<span id="' + tool.id + '_label">'
1103
- + tool.label + ':</span>'
1104
- + '<input id="' + tool.id + '" title="' + tool.title
1105
- + '" size="' + (tool.size || "4") + '" value="' + (tool.defval || "") + '" type="text"/></label>'
1106
-
1107
- // Creates the tool, hides & adds it, returns the select element
1108
-
1109
- // Add to given tool.panel
1110
- var inp = $(html).appendTo(panel).find('input');
1111
-
1112
- if(tool.spindata) {
1113
- inp.SpinButton(tool.spindata);
1114
- }
1115
-
1116
- if(tool.events) {
1117
- $.each(tool.events, function(evt, func) {
1118
- inp.bind(evt, func);
1119
- });
1120
- }
1121
- break;
1122
-
1123
- default:
1124
- break;
1125
- }
1126
- });
1127
- }
1128
-
1129
- if(ext.buttons) {
1130
- var fallback_obj = {},
1131
- placement_obj = {},
1132
- svgicons = ext.svgicons;
1133
- var holders = {};
1134
-
1135
-
1136
- // Add buttons given by extension
1137
- $.each(ext.buttons, function(i, btn) {
1138
- var icon;
1139
- var id = btn.id;
1140
- var num = i;
1141
-
1142
- // Give button a unique ID
1143
- while($('#'+id).length) {
1144
- id = btn.id + '_' + (++num);
1145
- }
1146
-
1147
- if(!svgicons) {
1148
- icon = $('<img src="' + btn.icon + '">');
1149
- } else {
1150
- fallback_obj[id] = btn.icon;
1151
- var svgicon = btn.svgicon?btn.svgicon:btn.id;
1152
- if(btn.type == 'app_menu') {
1153
- placement_obj['#' + id + ' > div'] = svgicon;
1154
- } else {
1155
- placement_obj['#' + id] = svgicon;
1156
- }
1157
- }
1158
-
1159
- var cls, parent;
1160
-
1161
- // Set button up according to its type
1162
- switch ( btn.type ) {
1163
- case 'mode_flyout':
1164
- case 'mode':
1165
- cls = 'tool_button';
1166
- parent = "#tools_left";
1167
- break;
1168
- case 'context':
1169
- cls = 'tool_button';
1170
- parent = "#" + btn.panel;
1171
- // create the panel if it doesn't exist
1172
- if(!$(parent).length)
1173
- $('<div>', {id: btn.panel}).appendTo("#tools_top");
1174
- break;
1175
- case 'app_menu':
1176
- cls = '';
1177
- parent = '#main_menu ul';
1178
- break;
1179
- }
1180
-
1181
- var button = $((btn.list || btn.type == 'app_menu')?'<li/>':'<div/>')
1182
- .attr("id", id)
1183
- .attr("title", btn.title)
1184
- .addClass(cls);
1185
- if(!btn.includeWith && !btn.list) {
1186
- if("position" in btn) {
1187
- $(parent).children().eq(btn.position).before(button);
1188
- } else {
1189
- button.appendTo(parent);
1190
- }
1191
-
1192
- if(btn.type =='mode_flyout') {
1193
- // Add to flyout menu / make flyout menu
1194
- // var opts = btn.includeWith;
1195
- // // opts.button, default, position
1196
- var ref_btn = $(button);
1197
-
1198
- var flyout_holder = ref_btn.parent();
1199
- // Create a flyout menu if there isn't one already
1200
- if(!ref_btn.parent().hasClass('tools_flyout')) {
1201
- // Create flyout placeholder
1202
- var tls_id = ref_btn[0].id.replace('tool_','tools_')
1203
- var show_btn = ref_btn.clone()
1204
- .attr('id',tls_id + '_show')
1205
- .append($('<div>',{'class':'flyout_arrow_horiz'}));
1206
-
1207
- ref_btn.before(show_btn);
1208
-
1209
- // Create a flyout div
1210
- flyout_holder = makeFlyoutHolder(tls_id, ref_btn);
1211
- flyout_holder.data('isLibrary', true);
1212
- show_btn.data('isLibrary', true);
1213
- }
1214
-
1215
-
1216
-
1217
- // var ref_data = Actions.getButtonData(opts.button);
1218
-
1219
- placement_obj['#' + tls_id + '_show'] = btn.id;
1220
- // TODO: Find way to set the current icon using the iconloader if this is not default
1221
-
1222
- // Include data for extension button as well as ref button
1223
- var cur_h = holders['#'+flyout_holder[0].id] = [{
1224
- sel: '#'+id,
1225
- fn: btn.events.click,
1226
- icon: btn.id,
1227
- // key: btn.key,
1228
- isDefault: true
1229
- }, ref_data];
1230
- //
1231
- // // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'}
1232
- //
1233
- // var pos = ("position" in opts)?opts.position:'last';
1234
- // var len = flyout_holder.children().length;
1235
- //
1236
- // // Add at given position or end
1237
- // if(!isNaN(pos) && pos >= 0 && pos < len) {
1238
- // flyout_holder.children().eq(pos).before(button);
1239
- // } else {
1240
- // flyout_holder.append(button);
1241
- // cur_h.reverse();
1242
- // }
1243
- } else if(btn.type == 'app_menu') {
1244
- button.append('<div>').append(btn.title);
1245
- }
1246
-
1247
- } else if(btn.list) {
1248
- // Add button to list
1249
- button.addClass('push_button');
1250
- $('#' + btn.list + '_opts').append(button);
1251
- if(btn.isDefault) {
1252
- $('#cur_' + btn.list).append(button.children().clone());
1253
- var svgicon = btn.svgicon?btn.svgicon:btn.id;
1254
- placement_obj['#cur_' + btn.list] = svgicon;
1255
- }
1256
- } else if(btn.includeWith) {
1257
- // Add to flyout menu / make flyout menu
1258
- var opts = btn.includeWith;
1259
- // opts.button, default, position
1260
- var ref_btn = $(opts.button);
1261
-
1262
- var flyout_holder = ref_btn.parent();
1263
- // Create a flyout menu if there isn't one already
1264
- if(!ref_btn.parent().hasClass('tools_flyout')) {
1265
- // Create flyout placeholder
1266
- var tls_id = ref_btn[0].id.replace('tool_','tools_')
1267
- var show_btn = ref_btn.clone()
1268
- .attr('id',tls_id + '_show')
1269
- .append($('<div>',{'class':'flyout_arrow_horiz'}));
1270
-
1271
- ref_btn.before(show_btn);
1272
-
1273
- // Create a flyout div
1274
- flyout_holder = makeFlyoutHolder(tls_id, ref_btn);
1275
- }
1276
-
1277
- var ref_data = Actions.getButtonData(opts.button);
1278
-
1279
- if(opts.isDefault) {
1280
- placement_obj['#' + tls_id + '_show'] = btn.id;
1281
- }
1282
- // TODO: Find way to set the current icon using the iconloader if this is not default
1283
-
1284
- // Include data for extension button as well as ref button
1285
- var cur_h = holders['#'+flyout_holder[0].id] = [{
1286
- sel: '#'+id,
1287
- fn: btn.events.click,
1288
- icon: btn.id,
1289
- key: btn.key,
1290
- isDefault: btn.includeWith?btn.includeWith.isDefault:0
1291
- }, ref_data];
1292
-
1293
- // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'}
1294
-
1295
- var pos = ("position" in opts)?opts.position:'last';
1296
- var len = flyout_holder.children().length;
1297
-
1298
- // Add at given position or end
1299
- if(!isNaN(pos) && pos >= 0 && pos < len) {
1300
- flyout_holder.children().eq(pos).before(button);
1301
- } else {
1302
- flyout_holder.append(button);
1303
- cur_h.reverse();
1304
- }
1305
- }
1306
-
1307
- if(!svgicons) {
1308
- button.append(icon);
1309
- }
1310
-
1311
- if(!btn.list) {
1312
- // Add given events to button
1313
- $.each(btn.events, function(name, func) {
1314
- if(name == "click") {
1315
- if(btn.type == 'mode') {
1316
- if(btn.includeWith) {
1317
- button.bind(name, func);
1318
- } else {
1319
- button.bind(name, function() {
1320
- if(toolButtonClick(button)) {
1321
- func();
1322
- }
1323
- });
1324
- }
1325
- if(btn.key) {
1326
- $(document).bind('keydown', btn.key, func);
1327
- if(btn.title) button.attr("title", btn.title + ' ['+btn.key+']');
1328
- }
1329
- } else {
1330
- button.bind(name, func);
1331
- }
1332
- } else {
1333
- button.bind(name, func);
1334
- }
1335
- });
1336
- }
1337
-
1338
- setupFlyouts(holders);
1339
- });
1340
-
1341
- $.each(btn_selects, function() {
1342
- addAltDropDown(this.elem, this.list, this.callback, {seticon: true});
1343
- });
1344
-
1345
- if (svgicons)
1346
- cb_ready = false; // Delay callback
1347
-
1348
- $.svgIcons(svgicons, {
1349
- w:24, h:24,
1350
- id_match: false,
1351
- no_img: (!isWebkit),
1352
- fallback: fallback_obj,
1353
- placement: placement_obj,
1354
- callback: function(icons) {
1355
- // Non-ideal hack to make the icon match the current size
1356
- if(curPrefs.iconsize && curPrefs.iconsize != 'm') {
1357
- prepResize();
1358
- }
1359
- cb_ready = true; // Ready for callback
1360
- runCallback();
1361
- }
1362
-
1363
- });
1364
- }
1365
-
1366
- runCallback();
1367
- };
1368
-
1369
- var getPaint = function(color, opac, type) {
1370
- // update the editor's fill paint
1371
- var opts = null;
1372
- if (color.indexOf("url(#") === 0) {
1373
- var refElem = svgCanvas.getRefElem(color);
1374
- if(refElem) {
1375
- refElem = refElem.cloneNode(true);
1376
- } else {
1377
- refElem = $("#" + type + "_color defs *")[0];
1378
- }
1379
-
1380
- opts = { alpha: opac };
1381
- opts[refElem.tagName] = refElem;
1382
- }
1383
- else if (color.indexOf("#") === 0) {
1384
- opts = {
1385
- alpha: opac,
1386
- solidColor: color.substr(1)
1387
- };
1388
- }
1389
- else {
1390
- opts = {
1391
- alpha: opac,
1392
- solidColor: 'none'
1393
- };
1394
- }
1395
- return new $.jGraduate.Paint(opts);
1396
- };
1397
-
1398
-
1399
- // updates the toolbar (colors, opacity, etc) based on the selected element
1400
- // This function also updates the opacity and id elements that are in the context panel
1401
- var updateToolbar = function() {
1402
- if (selectedElement != null) {
1403
-
1404
- switch ( selectedElement.tagName ) {
1405
- case 'use':
1406
- case 'image':
1407
- case 'foreignObject':
1408
- break;
1409
- case 'g':
1410
- case 'a':
1411
- // Look for common styles
1412
-
1413
- var gWidth = null;
1414
-
1415
- var childs = selectedElement.getElementsByTagName('*');
1416
- for(var i = 0, len = childs.length; i < len; i++) {
1417
- var swidth = childs[i].getAttribute("stroke-width");
1418
-
1419
- if(i === 0) {
1420
- gWidth = swidth;
1421
- } else if(gWidth !== swidth) {
1422
- gWidth = null;
1423
- }
1424
- }
1425
-
1426
- $('#stroke_width').val(gWidth === null ? "" : gWidth);
1427
-
1428
- paintBox.fill.update(true);
1429
- paintBox.stroke.update(true);
1430
-
1431
-
1432
- break;
1433
- default:
1434
- paintBox.fill.update(true);
1435
- paintBox.stroke.update(true);
1436
- //console.log(paintBox.fill);
1437
-
1438
- $('#stroke_width').val(selectedElement.getAttribute("stroke-width") || 1);
1439
- $('#stroke_style').val(selectedElement.getAttribute("stroke-dasharray")||"none");
1440
-
1441
- var attr = selectedElement.getAttribute("stroke-linejoin") || 'miter';
1442
-
1443
- if ($('#linejoin_' + attr).length != 0)
1444
- setStrokeOpt($('#linejoin_' + attr)[0]);
1445
-
1446
- attr = selectedElement.getAttribute("stroke-linecap") || 'butt';
1447
-
1448
- if ($('#linecap_' + attr).length != 0)
1449
- setStrokeOpt($('#linecap_' + attr)[0]);
1450
- }
1451
-
1452
- }
1453
-
1454
- // All elements including image and group have opacity
1455
- if(selectedElement != null) {
1456
- var opac_perc = ((selectedElement.getAttribute("opacity")||1.0)*100);
1457
- $('#group_opacity').val(opac_perc);
1458
- $('#opac_slider').slider('option', 'value', opac_perc);
1459
- $('#elem_id').val(selectedElement.id);
1460
- }
1461
-
1462
- updateToolButtonState();
1463
- };
1464
-
1465
- var setImageURL = Editor.setImageURL = function(url) {
1466
- if(!url) url = default_img_url;
1467
-
1468
- svgCanvas.setImageURL(url);
1469
- $('#image_url').val(url);
1470
-
1471
- if(url.indexOf('data:') === 0) {
1472
- // data URI found
1473
- $('#image_url').hide();
1474
- $('#change_image_url').show();
1475
- } else {
1476
- // regular URL
1477
-
1478
- svgCanvas.embedImage(url, function(datauri) {
1479
- if(!datauri) {
1480
- // Couldn't embed, so show warning
1481
- $('#url_notice').show();
1482
- } else {
1483
- $('#url_notice').hide();
1484
- }
1485
- default_img_url = url;
1486
- });
1487
- $('#image_url').show();
1488
- $('#change_image_url').hide();
1489
- }
1490
- }
1491
-
1492
- var setInputWidth = function(elem) {
1493
- var w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300);
1494
- $(elem).width(w);
1495
- }
1496
-
1497
- // updates the context panel tools based on the selected element
1498
- var updateContextPanel = function() {
1499
- var elem = selectedElement;
1500
- // If element has just been deleted, consider it null
1501
- if(elem != null && !elem.parentNode) elem = null;
1502
- var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName();
1503
- var currentMode = svgCanvas.getMode();
1504
- var unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null;
1505
-
1506
- var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false;
1507
- var menu_items = $('#cmenu_canvas li');
1508
- $('#selected_panel, #multiselected_panel, #g_panel, #rect_panel, #circle_panel,\
1509
- #ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel, #a_panel').hide();
1510
- if (elem != null) {
1511
- var elname = elem.nodeName;
1512
-
1513
- // If this is a link with no transform and one child, pretend
1514
- // its child is selected
1515
- // console.log('go', elem)
1516
- // if(elname === 'a') { // && !$(elem).attr('transform')) {
1517
- // elem = elem.firstChild;
1518
- // }
1519
-
1520
- var angle = svgCanvas.getRotationAngle(elem);
1521
- $('#angle').val(angle);
1522
-
1523
- var blurval = svgCanvas.getBlur(elem);
1524
- $('#blur').val(blurval);
1525
- $('#blur_slider').slider('option', 'value', blurval);
1526
-
1527
- if(svgCanvas.addedNew) {
1528
- if(elname === 'image') {
1529
- // Prompt for URL if not a data URL
1530
- if(svgCanvas.getHref(elem).indexOf('data:') !== 0) {
1531
- promptImgURL();
1532
- }
1533
- } /*else if(elname == 'text') {
1534
- // TODO: Do something here for new text
1535
- }*/
1536
- }
1537
-
1538
- if(!is_node && currentMode != 'pathedit') {
1539
- $('#selected_panel').show();
1540
- // Elements in this array already have coord fields
1541
- if(['line', 'circle', 'ellipse'].indexOf(elname) >= 0) {
1542
- $('#xy_panel').hide();
1543
- } else {
1544
- var x,y;
1545
-
1546
- // Get BBox vals for g, polyline and path
1547
- if(['g', 'polyline', 'path'].indexOf(elname) >= 0) {
1548
- var bb = svgCanvas.getStrokedBBox([elem]);
1549
- if(bb) {
1550
- x = bb.x;
1551
- y = bb.y;
1552
- }
1553
- } else {
1554
- x = elem.getAttribute('x');
1555
- y = elem.getAttribute('y');
1556
- }
1557
-
1558
- if(unit) {
1559
- x = svgedit.units.convertUnit(x);
1560
- y = svgedit.units.convertUnit(y);
1561
- }
1562
-
1563
- $('#selected_x').val(x || 0);
1564
- $('#selected_y').val(y || 0);
1565
- $('#xy_panel').show();
1566
- }
1567
-
1568
- // Elements in this array cannot be converted to a path
1569
- var no_path = ['image', 'text', 'path', 'g', 'use'].indexOf(elname) == -1;
1570
- $('#tool_topath').toggle(no_path);
1571
- $('#tool_reorient').toggle(elname == 'path');
1572
- $('#tool_reorient').toggleClass('disabled', angle == 0);
1573
- } else {
1574
- var point = path.getNodePoint();
1575
- $('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button');
1576
- $('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes);
1577
-
1578
- // Show open/close button based on selected point
1579
- setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path');
1580
-
1581
- if(point) {
1582
- var seg_type = $('#seg_type');
1583
- if(unit) {
1584
- point.x = svgedit.units.convertUnit(point.x);
1585
- point.y = svgedit.units.convertUnit(point.y);
1586
- }
1587
- $('#path_node_x').val(point.x);
1588
- $('#path_node_y').val(point.y);
1589
- if(point.type) {
1590
- seg_type.val(point.type).removeAttr('disabled');
1591
- } else {
1592
- seg_type.val(4).attr('disabled','disabled');
1593
- }
1594
- }
1595
- return;
1596
- }
1597
-
1598
- // update contextual tools here
1599
- var panels = {
1600
- g: [],
1601
- a: [],
1602
- rect: ['rx','width','height'],
1603
- image: ['width','height'],
1604
- circle: ['cx','cy','r'],
1605
- ellipse: ['cx','cy','rx','ry'],
1606
- line: ['x1','y1','x2','y2'],
1607
- text: [],
1608
- 'use': []
1609
- };
1610
-
1611
- var el_name = elem.tagName;
1612
-
1613
- // if($(elem).data('gsvg')) {
1614
- // $('#g_panel').show();
1615
- // }
1616
-
1617
- var link_href = null;
1618
- if (el_name === 'a') {
1619
- link_href = svgCanvas.getHref(elem);
1620
- $('#g_panel').show();
1621
- }
1622
-
1623
- if(elem.parentNode.tagName === 'a') {
1624
- if(!$(elem).siblings().length) {
1625
- $('#a_panel').show();
1626
- link_href = svgCanvas.getHref(elem.parentNode);
1627
- }
1628
- }
1629
-
1630
- // Hide/show the make_link buttons
1631
- $('#tool_make_link, #tool_make_link').toggle(!link_href);
1632
-
1633
- if(link_href) {
1634
- $('#link_url').val(link_href);
1635
- }
1636
-
1637
- if(panels[el_name]) {
1638
- var cur_panel = panels[el_name];
1639
-
1640
- $('#' + el_name + '_panel').show();
1641
-
1642
- $.each(cur_panel, function(i, item) {
1643
- var attrVal = elem.getAttribute(item);
1644
- if(curConfig.baseUnit !== 'px' && elem[item]) {
1645
- var bv = elem[item].baseVal.value;
1646
- attrVal = svgedit.units.convertUnit(bv);
1647
- }
1648
-
1649
- $('#' + el_name + '_' + item).val(attrVal || 0);
1650
- });
1651
-
1652
- if(el_name == 'text') {
1653
- $('#text_panel').css("display", "inline");
1654
- if (svgCanvas.getItalic()) {
1655
- $('#tool_italic').addClass('push_button_pressed').removeClass('tool_button');
1656
- }
1657
- else {
1658
- $('#tool_italic').removeClass('push_button_pressed').addClass('tool_button');
1659
- }
1660
- if (svgCanvas.getBold()) {
1661
- $('#tool_bold').addClass('push_button_pressed').removeClass('tool_button');
1662
- }
1663
- else {
1664
- $('#tool_bold').removeClass('push_button_pressed').addClass('tool_button');
1665
- }
1666
- $('#font_family').val(elem.getAttribute("font-family"));
1667
- $('#font_size').val(elem.getAttribute("font-size"));
1668
- $('#text').val(elem.textContent);
1669
- if (svgCanvas.addedNew) {
1670
- // Timeout needed for IE9
1671
- setTimeout(function() {
1672
- $('#text').focus().select();
1673
- },100);
1674
- }
1675
- } // text
1676
- else if(el_name == 'image') {
1677
- setImageURL(svgCanvas.getHref(elem));
1678
- } // image
1679
- else if(el_name === 'g' || el_name === 'use') {
1680
- $('#container_panel').show();
1681
- var title = svgCanvas.getTitle();
1682
- var label = $('#g_title')[0];
1683
- label.value = title;
1684
- setInputWidth(label);
1685
- var d = 'disabled';
1686
- if(el_name == 'use') {
1687
- label.setAttribute(d, d);
1688
- } else {
1689
- label.removeAttribute(d);
1690
- }
1691
- }
1692
- }
1693
- menu_items[(el_name === 'g' ? 'en':'dis') + 'ableContextMenuItems']('#ungroup');
1694
- menu_items[((el_name === 'g' || !multiselected) ? 'dis':'en') + 'ableContextMenuItems']('#group');
1695
- } // if (elem != null)
1696
- else if (multiselected) {
1697
- $('#multiselected_panel').show();
1698
- menu_items
1699
- .enableContextMenuItems('#group')
1700
- .disableContextMenuItems('#ungroup');
1701
- } else {
1702
- menu_items.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back');
1703
- }
1704
-
1705
- // update history buttons
1706
- if (undoMgr.getUndoStackSize() > 0) {
1707
- $('#tool_undo').removeClass( 'disabled');
1708
- }
1709
- else {
1710
- $('#tool_undo').addClass( 'disabled');
1711
- }
1712
- if (undoMgr.getRedoStackSize() > 0) {
1713
- $('#tool_redo').removeClass( 'disabled');
1714
- }
1715
- else {
1716
- $('#tool_redo').addClass( 'disabled');
1717
- }
1718
-
1719
- svgCanvas.addedNew = false;
1720
-
1721
- if ( (elem && !is_node) || multiselected) {
1722
- // update the selected elements' layer
1723
- $('#selLayerNames').removeAttr('disabled').val(currentLayerName);
1724
-
1725
- // Enable regular menu options
1726
- canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back');
1727
- }
1728
- else {
1729
- $('#selLayerNames').attr('disabled', 'disabled');
1730
- }
1731
- };
1732
-
1733
- $('#text').focus( function(){ textBeingEntered = true; } );
1734
- $('#text').blur( function(){ textBeingEntered = false; } );
1735
-
1736
- // bind the selected event to our function that handles updates to the UI
1737
- svgCanvas.bind("selected", selectedChanged);
1738
- svgCanvas.bind("transition", elementTransition);
1739
- svgCanvas.bind("changed", elementChanged);
1740
- svgCanvas.bind("saved", saveHandler);
1741
- svgCanvas.bind("exported", exportHandler);
1742
- svgCanvas.bind("zoomed", zoomChanged);
1743
- svgCanvas.bind("contextset", contextChanged);
1744
- svgCanvas.bind("extension_added", extAdded);
1745
- svgCanvas.textActions.setInputElem($("#text")[0]);
1746
-
1747
- var str = '<div class="palette_item" data-rgb="none"></div>'
1748
- $.each(palette, function(i,item){
1749
- str += '<div class="palette_item" style="background-color: ' + item + ';" data-rgb="' + item + '"></div>';
1750
- });
1751
- $('#palette').append(str);
1752
-
1753
- // Set up editor background functionality
1754
- // TODO add checkerboard as "pattern"
1755
- var color_blocks = ['#FFF','#888','#000']; // ,'url(data:image/gif;base64,R0lGODlhEAAQAIAAAP%2F%2F%2F9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG%2Bgq4jM3IFLJgpswNly%2FXkcBpIiVaInlLJr9FZWAQA7)'];
1756
- var str = '';
1757
- $.each(color_blocks, function() {
1758
- str += '<div class="color_block" style="background-color:' + this + ';"></div>';
1759
- });
1760
- $('#bg_blocks').append(str);
1761
- var blocks = $('#bg_blocks div');
1762
- var cur_bg = 'cur_background';
1763
- blocks.each(function() {
1764
- var blk = $(this);
1765
- blk.click(function() {
1766
- blocks.removeClass(cur_bg);
1767
- $(this).addClass(cur_bg);
1768
- });
1769
- });
1770
-
1771
- if($.pref('bkgd_color')) {
1772
- setBackground($.pref('bkgd_color'), $.pref('bkgd_url'));
1773
- } else if($.pref('bkgd_url')) {
1774
- // No color set, only URL
1775
- setBackground(defaultPrefs.bkgd_color, $.pref('bkgd_url'));
1776
- }
1777
-
1778
- if($.pref('img_save')) {
1779
- curPrefs.img_save = $.pref('img_save');
1780
- $('#image_save_opts input').val([curPrefs.img_save]);
1781
- }
1782
-
1783
- var changeRectRadius = function(ctl) {
1784
- svgCanvas.setRectRadius(ctl.value);
1785
- }
1786
-
1787
- var changeFontSize = function(ctl) {
1788
- svgCanvas.setFontSize(ctl.value);
1789
- }
1790
-
1791
- var changeStrokeWidth = function(ctl) {
1792
- var val = ctl.value;
1793
- if(val == 0 && selectedElement && ['line', 'polyline'].indexOf(selectedElement.nodeName) >= 0) {
1794
- val = ctl.value = 1;
1795
- }
1796
- svgCanvas.setStrokeWidth(val);
1797
- }
1798
-
1799
- var changeRotationAngle = function(ctl) {
1800
- svgCanvas.setRotationAngle(ctl.value);
1801
- $('#tool_reorient').toggleClass('disabled', ctl.value == 0);
1802
- }
1803
- var changeZoom = function(ctl) {
1804
- var zoomlevel = ctl.value / 100;
1805
- if(zoomlevel < .001) {
1806
- ctl.value = .1;
1807
- return;
1808
- }
1809
- var zoom = svgCanvas.getZoom();
1810
- var w_area = workarea;
1811
-
1812
- zoomChanged(window, {
1813
- width: 0,
1814
- height: 0,
1815
- // center pt of scroll position
1816
- x: (w_area[0].scrollLeft + w_area.width()/2)/zoom,
1817
- y: (w_area[0].scrollTop + w_area.height()/2)/zoom,
1818
- zoom: zoomlevel
1819
- }, true);
1820
- }
1821
-
1822
- var changeOpacity = function(ctl, val) {
1823
- if(val == null) val = ctl.value;
1824
- $('#group_opacity').val(val);
1825
- if(!ctl || !ctl.handle) {
1826
- $('#opac_slider').slider('option', 'value', val);
1827
- }
1828
- svgCanvas.setOpacity(val/100);
1829
- }
1830
-
1831
- var changeBlur = function(ctl, val, noUndo) {
1832
- if(val == null) val = ctl.value;
1833
- $('#blur').val(val);
1834
- var complete = false;
1835
- if(!ctl || !ctl.handle) {
1836
- $('#blur_slider').slider('option', 'value', val);
1837
- complete = true;
1838
- }
1839
- if(noUndo) {
1840
- svgCanvas.setBlurNoUndo(val);
1841
- } else {
1842
- svgCanvas.setBlur(val, complete);
1843
- }
1844
- }
1845
-
1846
- var operaRepaint = function() {
1847
- // Repaints canvas in Opera. Needed for stroke-dasharray change as well as fill change
1848
- if(!window.opera) return;
1849
- $('<p/>').hide().appendTo('body').remove();
1850
- }
1851
-
1852
- $('#stroke_style').change(function(){
1853
- svgCanvas.setStrokeAttr('stroke-dasharray', $(this).val());
1854
- operaRepaint();
1855
- });
1856
-
1857
- $('#stroke_linejoin').change(function(){
1858
- svgCanvas.setStrokeAttr('stroke-linejoin', $(this).val());
1859
- operaRepaint();
1860
- });
1861
-
1862
-
1863
- // Lose focus for select elements when changed (Allows keyboard shortcuts to work better)
1864
- $('select').change(function(){$(this).blur();});
1865
-
1866
- // fired when user wants to move elements to another layer
1867
- var promptMoveLayerOnce = false;
1868
- $('#selLayerNames').change(function(){
1869
- var destLayer = this.options[this.selectedIndex].value;
1870
- var confirm_str = uiStrings.notification.QmoveElemsToLayer.replace('%s',destLayer);
1871
- var moveToLayer = function(ok) {
1872
- if(!ok) return;
1873
- promptMoveLayerOnce = true;
1874
- svgCanvas.moveSelectedToLayer(destLayer);
1875
- svgCanvas.clearSelection();
1876
- populateLayers();
1877
- }
1878
- if (destLayer) {
1879
- if(promptMoveLayerOnce) {
1880
- moveToLayer(true);
1881
- } else {
1882
- $.confirm(confirm_str, moveToLayer);
1883
- }
1884
- }
1885
- });
1886
-
1887
- $('#font_family').change(function() {
1888
- svgCanvas.setFontFamily(this.value);
1889
- });
1890
-
1891
- $('#seg_type').change(function() {
1892
- svgCanvas.setSegType($(this).val());
1893
- });
1894
-
1895
- $('#text').keyup(function(){
1896
- svgCanvas.setTextContent(this.value);
1897
- });
1898
-
1899
- $('#image_url').change(function(){
1900
- setImageURL(this.value);
1901
- });
1902
-
1903
- $('#link_url').change(function() {
1904
- if(this.value.length) {
1905
- svgCanvas.setLinkURL(this.value);
1906
- } else {
1907
- svgCanvas.removeHyperlink();
1908
- }
1909
- });
1910
-
1911
- $('#g_title').change(function() {
1912
- svgCanvas.setGroupTitle(this.value);
1913
- });
1914
-
1915
- $('.attr_changer').change(function() {
1916
- var attr = this.getAttribute("data-attr");
1917
- var val = this.value;
1918
- var valid = svgedit.units.isValidUnit(attr, val, selectedElement);
1919
-
1920
- if(!valid) {
1921
- $.alert(uiStrings.notification.invalidAttrValGiven);
1922
- this.value = selectedElement.getAttribute(attr);
1923
- return false;
1924
- }
1925
-
1926
- if (attr !== "id") {
1927
- if (isNaN(val)) {
1928
- val = svgCanvas.convertToNum(attr, val);
1929
- } else if(curConfig.baseUnit !== 'px') {
1930
- // Convert unitless value to one with given unit
1931
-
1932
- var unitData = svgedit.units.getTypeMap();
1933
-
1934
- if(selectedElement[attr] || svgCanvas.getMode() === "pathedit" || attr === "x" || attr === "y") {
1935
- val *= unitData[curConfig.baseUnit];
1936
- }
1937
- }
1938
- }
1939
-
1940
- // if the user is changing the id, then de-select the element first
1941
- // change the ID, then re-select it with the new ID
1942
- if (attr === "id") {
1943
- var elem = selectedElement;
1944
- svgCanvas.clearSelection();
1945
- elem.id = val;
1946
- svgCanvas.addToSelection([elem],true);
1947
- }
1948
- else {
1949
- svgCanvas.changeSelectedAttribute(attr, val);
1950
- }
1951
- this.blur();
1952
- });
1953
-
1954
- // Prevent selection of elements when shift-clicking
1955
- $('#palette').mouseover(function() {
1956
- var inp = $('<input type="hidden">');
1957
- $(this).append(inp);
1958
- inp.focus().remove();
1959
- })
1960
-
1961
- $('.palette_item').mousedown(function(evt){
1962
- var right_click = evt.button === 2;
1963
- var isStroke = evt.shiftKey || right_click;
1964
- var picker = isStroke ? "stroke" : "fill";
1965
- var color = $(this).attr('data-rgb');
1966
- var paint = null;
1967
-
1968
- // Webkit-based browsers returned 'initial' here for no stroke
1969
- if (color === 'none' || color === 'transparent' || color === 'initial') {
1970
- color = 'none';
1971
- paint = new $.jGraduate.Paint();
1972
- }
1973
- else {
1974
- paint = new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)});
1975
- }
1976
-
1977
- paintBox[picker].setPaint(paint);
1978
-
1979
- if (isStroke) {
1980
- svgCanvas.setColor('stroke', color);
1981
- if (color != 'none' && svgCanvas.getStrokeOpacity() != 1) {
1982
- svgCanvas.setPaintOpacity('stroke', 1.0);
1983
- }
1984
- } else {
1985
- svgCanvas.setColor('fill', color);
1986
- if (color != 'none' && svgCanvas.getFillOpacity() != 1) {
1987
- svgCanvas.setPaintOpacity('fill', 1.0);
1988
- }
1989
- }
1990
- updateToolButtonState();
1991
- }).bind('contextmenu', function(e) {e.preventDefault()});
1992
-
1993
- $("#toggle_stroke_tools").on("click", function() {
1994
- $("#tools_bottom").toggleClass("expanded");
1995
- });
1996
-
1997
- // This is a common function used when a tool has been clicked (chosen)
1998
- // It does several common things:
1999
- // - removes the tool_button_current class from whatever tool currently has it
2000
- // - hides any flyouts
2001
- // - adds the tool_button_current class to the button passed in
2002
- var toolButtonClick = function(button, noHiding) {
2003
- if ($(button).hasClass('disabled')) return false;
2004
- if($(button).parent().hasClass('tools_flyout')) return true;
2005
- var fadeFlyouts = fadeFlyouts || 'normal';
2006
- if(!noHiding) {
2007
- $('.tools_flyout').fadeOut(fadeFlyouts);
2008
- }
2009
- $('#styleoverrides').text('');
2010
- workarea.css('cursor','auto');
2011
- $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button');
2012
- $(button).addClass('tool_button_current').removeClass('tool_button');
2013
- return true;
2014
- };
2015
-
2016
- (function() {
2017
- var last_x = null, last_y = null, w_area = workarea[0],
2018
- panning = false, keypan = false;
2019
-
2020
- $('#svgcanvas').bind('mousemove mouseup', function(evt) {
2021
- if(panning === false) return;
2022
-
2023
- w_area.scrollLeft -= (evt.clientX - last_x);
2024
- w_area.scrollTop -= (evt.clientY - last_y);
2025
-
2026
- last_x = evt.clientX;
2027
- last_y = evt.clientY;
2028
-
2029
- if(evt.type === 'mouseup') panning = false;
2030
- return false;
2031
- }).mousedown(function(evt) {
2032
- if(evt.button === 1 || keypan === true) {
2033
- panning = true;
2034
- last_x = evt.clientX;
2035
- last_y = evt.clientY;
2036
- return false;
2037
- }
2038
- });
2039
-
2040
- $(window).mouseup(function() {
2041
- panning = false;
2042
- });
2043
-
2044
- $(document).bind('keydown', 'space', function(evt) {
2045
- svgCanvas.spaceKey = keypan = true;
2046
- evt.preventDefault();
2047
- }).bind('keyup', 'space', function(evt) {
2048
- evt.preventDefault();
2049
- svgCanvas.spaceKey = keypan = false;
2050
- }).bind('keydown', 'shift', function(evt) {
2051
- if(svgCanvas.getMode() === 'zoom') {
2052
- workarea.css('cursor', zoomOutIcon);
2053
- }
2054
- }).bind('keyup', 'shift', function(evt) {
2055
- if(svgCanvas.getMode() === 'zoom') {
2056
- workarea.css('cursor', zoomInIcon);
2057
- }
2058
- })
2059
- }());
2060
-
2061
-
2062
- function setStrokeOpt(opt, changeElem) {
2063
- var id = opt.id;
2064
- var bits = id.split('_');
2065
- var pre = bits[0];
2066
- var val = bits[1];
2067
-
2068
- if(changeElem) {
2069
- svgCanvas.setStrokeAttr('stroke-' + pre, val);
2070
- }
2071
- operaRepaint();
2072
- setIcon('#cur_' + pre , id, 20);
2073
- $(opt).addClass('current').siblings().removeClass('current');
2074
- }
2075
-
2076
- (function() {
2077
- var button = $('#main_icon');
2078
- var overlay = $('#main_icon span');
2079
- var list = $('#main_menu');
2080
- var on_button = false;
2081
- var height = 0;
2082
- var js_hover = true;
2083
- var set_click = false;
2084
-
2085
- var hideMenu = function() {
2086
- list.fadeOut(200);
2087
- };
2088
-
2089
- $(window).mouseup(function(evt) {
2090
- if(!on_button) {
2091
- button.removeClass('buttondown');
2092
- // do not hide if it was the file input as that input needs to be visible
2093
- // for its change event to fire
2094
- if (evt.target.tagName != "INPUT") {
2095
- list.fadeOut(200);
2096
- } else if(!set_click) {
2097
- set_click = true;
2098
- $(evt.target).click(function() {
2099
- list.css('margin-left','-9999px').show();
2100
- });
2101
- }
2102
- }
2103
- on_button = false;
2104
- }).mousedown(function(evt) {
2105
- // $(".contextMenu").hide();
2106
- // console.log('cm', $(evt.target).closest('.contextMenu'));
2107
-
2108
- var islib = $(evt.target).closest('div.tools_flyout, .contextMenu').length;
2109
- if(!islib) $('.tools_flyout:visible,.contextMenu').fadeOut(250);
2110
- });
2111
-
2112
- overlay.bind('mousedown',function() {
2113
- if (!button.hasClass('buttondown')) {
2114
- button.addClass('buttondown').removeClass('buttonup')
2115
- // Margin must be reset in case it was changed before;
2116
- list.css('margin-left',0).show();
2117
- if(!height) {
2118
- height = list.height();
2119
- }
2120
- // Using custom animation as slideDown has annoying "bounce effect"
2121
- list.css('height',0).animate({
2122
- 'height': height
2123
- },200);
2124
- on_button = true;
2125
- return false;
2126
- } else {
2127
- button.removeClass('buttondown').addClass('buttonup');
2128
- list.fadeOut(200);
2129
- }
2130
- }).hover(function() {
2131
- on_button = true;
2132
- }).mouseout(function() {
2133
- on_button = false;
2134
- });
2135
-
2136
- var list_items = $('#main_menu li');
2137
-
2138
- // Check if JS method of hovering needs to be used (Webkit bug)
2139
- list_items.mouseover(function() {
2140
- js_hover = ($(this).css('background-color') == 'rgba(0, 0, 0, 0)');
2141
-
2142
- list_items.unbind('mouseover');
2143
- if(js_hover) {
2144
- list_items.mouseover(function() {
2145
- this.style.backgroundColor = '#FFC';
2146
- }).mouseout(function() {
2147
- this.style.backgroundColor = 'transparent';
2148
- return true;
2149
- });
2150
- }
2151
- });
2152
- }());
2153
- // Made public for UI customization.
2154
- // TODO: Group UI functions into a public svgEditor.ui interface.
2155
- Editor.addDropDown = function(elem, callback, dropUp) {
2156
- if ($(elem).length == 0) return; // Quit if called on non-existant element
2157
- var button = $(elem).find('button');
2158
-
2159
- var list = $(elem).find('ul').attr('id', $(elem)[0].id + '-list');
2160
-
2161
- if(!dropUp) {
2162
- // Move list to place where it can overflow container
2163
- $('#option_lists').append(list);
2164
- }
2165
-
2166
- var on_button = false;
2167
- if(dropUp) {
2168
- $(elem).addClass('dropup');
2169
- }
2170
-
2171
- list.find('li').bind('mouseup', callback);
2172
-
2173
- $(window).mouseup(function(evt) {
2174
- if(!on_button) {
2175
- button.removeClass('down');
2176
- list.hide();
2177
- }
2178
- on_button = false;
2179
- });
2180
-
2181
- button.bind('mousedown',function() {
2182
- if (!button.hasClass('down')) {
2183
- button.addClass('down');
2184
-
2185
- if(!dropUp) {
2186
- var pos = $(elem).position();
2187
- list.css({
2188
- top: pos.top + 24,
2189
- left: pos.left - 10
2190
- });
2191
- }
2192
- list.show();
2193
-
2194
- on_button = true;
2195
- } else {
2196
- button.removeClass('down');
2197
- list.hide();
2198
- }
2199
- }).hover(function() {
2200
- on_button = true;
2201
- }).mouseout(function() {
2202
- on_button = false;
2203
- });
2204
- }
2205
-
2206
- // TODO: Combine this with addDropDown or find other way to optimize
2207
- var addAltDropDown = function(elem, list, callback, opts) {
2208
- var button = $(elem);
2209
- var list = $(list);
2210
- var on_button = false;
2211
- var dropUp = opts.dropUp;
2212
- if(dropUp) {
2213
- $(elem).addClass('dropup');
2214
- }
2215
- list.find('li').bind('mouseup', function() {
2216
- if(opts.seticon) {
2217
- setIcon('#cur_' + button[0].id , $(this).children());
2218
- $(this).addClass('current').siblings().removeClass('current');
2219
- }
2220
- callback.apply(this, arguments);
2221
-
2222
- });
2223
-
2224
- $(window).mouseup(function(evt) {
2225
- if(!on_button) {
2226
- button.removeClass('down');
2227
- list.hide();
2228
- list.css({top:0, left:0});
2229
- }
2230
- on_button = false;
2231
- });
2232
-
2233
- var height = list.height();
2234
- $(elem).bind('mousedown',function() {
2235
- var off = $(elem).offset();
2236
- if(dropUp) {
2237
- off.top -= list.height();
2238
- off.left += 8;
2239
- } else {
2240
- off.top += $(elem).height();
2241
- }
2242
- $(list).offset(off);
2243
-
2244
- if (!button.hasClass('down')) {
2245
- button.addClass('down');
2246
- list.show();
2247
- on_button = true;
2248
- return false;
2249
- } else {
2250
- button.removeClass('down');
2251
- // CSS position must be reset for Webkit
2252
- list.hide();
2253
- list.css({top:0, left:0});
2254
- }
2255
- }).hover(function() {
2256
- on_button = true;
2257
- }).mouseout(function() {
2258
- on_button = false;
2259
- });
2260
-
2261
- if(opts.multiclick) {
2262
- list.mousedown(function() {
2263
- on_button = true;
2264
- });
2265
- }
2266
- }
2267
-
2268
- Editor.addDropDown('#font_family_dropdown', function() {
2269
- var fam = $(this).text();
2270
- $('#font_family').val($(this).text()).change();
2271
- });
2272
-
2273
- Editor.addDropDown('#opacity_dropdown', function() {
2274
- if($(this).find('div').length) return;
2275
- var perc = parseInt($(this).text().split('%')[0]);
2276
- changeOpacity(false, perc);
2277
- }, true);
2278
-
2279
- // For slider usage, see: http://jqueryui.com/demos/slider/
2280
- $("#opac_slider").slider({
2281
- start: function() {
2282
- $('#opacity_dropdown li:not(.special)').hide();
2283
- },
2284
- stop: function() {
2285
- $('#opacity_dropdown li').show();
2286
- $(window).mouseup();
2287
- },
2288
- slide: function(evt, ui){
2289
- changeOpacity(ui);
2290
- }
2291
- });
2292
-
2293
- Editor.addDropDown('#blur_dropdown', $.noop);
2294
-
2295
- var slideStart = false;
2296
-
2297
- $("#blur_slider").slider({
2298
- max: 10,
2299
- step: .1,
2300
- stop: function(evt, ui) {
2301
- slideStart = false;
2302
- changeBlur(ui);
2303
- $('#blur_dropdown li').show();
2304
- $(window).mouseup();
2305
- },
2306
- start: function() {
2307
- slideStart = true;
2308
- },
2309
- slide: function(evt, ui){
2310
- changeBlur(ui, null, slideStart);
2311
- }
2312
- });
2313
-
2314
-
2315
- Editor.addDropDown('#zoom_dropdown', function() {
2316
- var item = $(this);
2317
- var val = item.attr('data-val');
2318
- if(val) {
2319
- zoomChanged(window, val);
2320
- } else {
2321
- changeZoom({value:parseInt(item.text())});
2322
- }
2323
- }, true);
2324
-
2325
- addAltDropDown('#stroke_linecap', '#linecap_opts', function() {
2326
- setStrokeOpt(this, true);
2327
- }, {dropUp: true});
2328
-
2329
- addAltDropDown('#stroke_linejoin', '#linejoin_opts', function() {
2330
- setStrokeOpt(this, true);
2331
- }, {dropUp: true});
2332
-
2333
- addAltDropDown('#tool_position', '#position_opts', function() {
2334
- var letter = this.id.replace('tool_pos','').charAt(0);
2335
- svgCanvas.alignSelectedElements(letter, 'page');
2336
- }, {multiclick: true});
2337
-
2338
- /*
2339
-
2340
- When a flyout icon is selected
2341
- (if flyout) {
2342
- - Change the icon
2343
- - Make pressing the button run its stuff
2344
- }
2345
- - Run its stuff
2346
-
2347
- When its shortcut key is pressed
2348
- - If not current in list, do as above
2349
- , else:
2350
- - Just run its stuff
2351
-
2352
- */
2353
-
2354
- // Unfocus text input when workarea is mousedowned.
2355
- (function() {
2356
- var inp;
2357
-
2358
- var unfocus = function() {
2359
- $(inp).blur();
2360
- }
2361
-
2362
- $('#svg_editor').find('button, select, input:not(#text)').focus(function() {
2363
- inp = this;
2364
- ui_context = 'toolbars';
2365
- workarea.mousedown(unfocus);
2366
- }).blur(function() {
2367
- ui_context = 'canvas';
2368
- workarea.unbind('mousedown', unfocus);
2369
- // Go back to selecting text if in textedit mode
2370
- if(svgCanvas.getMode() == 'textedit') {
2371
- $('#text').focus();
2372
- }
2373
- });
2374
-
2375
- }());
2376
-
2377
- var clickSelect = function() {
2378
- if (toolButtonClick('#tool_select')) {
2379
- svgCanvas.setMode('select');
2380
- $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}');
2381
- }
2382
- };
2383
-
2384
- var clickFHPath = function() {
2385
- if (toolButtonClick('#tool_fhpath')) {
2386
- svgCanvas.setMode('fhpath');
2387
- }
2388
- };
2389
-
2390
- var clickLine = function() {
2391
- if (toolButtonClick('#tool_line')) {
2392
- svgCanvas.setMode('line');
2393
- }
2394
- };
2395
-
2396
- var clickSquare = function(){
2397
- if (toolButtonClick('#tool_square')) {
2398
- svgCanvas.setMode('square');
2399
- }
2400
- };
2401
-
2402
- var clickRect = function(){
2403
- if (toolButtonClick('#tool_rect')) {
2404
- svgCanvas.setMode('rect');
2405
- }
2406
- };
2407
-
2408
- var clickFHRect = function(){
2409
- if (toolButtonClick('#tool_fhrect')) {
2410
- svgCanvas.setMode('fhrect');
2411
- }
2412
- };
2413
-
2414
- var clickCircle = function(){
2415
- if (toolButtonClick('#tool_circle')) {
2416
- svgCanvas.setMode('circle');
2417
- }
2418
- };
2419
-
2420
- var clickEllipse = function(){
2421
- if (toolButtonClick('#tool_ellipse')) {
2422
- svgCanvas.setMode('ellipse');
2423
- }
2424
- };
2425
-
2426
- var clickFHEllipse = function(){
2427
- if (toolButtonClick('#tool_fhellipse')) {
2428
- svgCanvas.setMode('fhellipse');
2429
- }
2430
- };
2431
-
2432
- var clickImage = function(){
2433
- if (toolButtonClick('#tool_image')) {
2434
- svgCanvas.setMode('image');
2435
- }
2436
- };
2437
-
2438
- var clickZoom = function(){
2439
- if (toolButtonClick('#tool_zoom')) {
2440
- svgCanvas.setMode('zoom');
2441
- workarea.css('cursor', zoomInIcon);
2442
- }
2443
- };
2444
-
2445
- var dblclickZoom = function(){
2446
- if (toolButtonClick('#tool_zoom')) {
2447
- zoomImage();
2448
- setSelectMode();
2449
- }
2450
- };
2451
-
2452
- var clickText = function(){
2453
- if (toolButtonClick('#tool_text')) {
2454
- svgCanvas.setMode('text');
2455
- }
2456
- };
2457
-
2458
- var clickPath = function(){
2459
- if (toolButtonClick('#tool_path')) {
2460
- svgCanvas.setMode('path');
2461
- }
2462
- };
2463
-
2464
- // Delete is a contextual tool that only appears in the ribbon if
2465
- // an element has been selected
2466
- var deleteSelected = function() {
2467
- if (selectedElement != null || multiselected) {
2468
- svgCanvas.deleteSelectedElements();
2469
- }
2470
- };
2471
-
2472
- var cutSelected = function() {
2473
- if (selectedElement != null || multiselected) {
2474
- svgCanvas.cutSelectedElements();
2475
- }
2476
- };
2477
-
2478
- var copySelected = function() {
2479
- if (selectedElement != null || multiselected) {
2480
- svgCanvas.copySelectedElements();
2481
- }
2482
- };
2483
-
2484
- var pasteInCenter = function() {
2485
- var zoom = svgCanvas.getZoom();
2486
-
2487
- var x = (workarea[0].scrollLeft + workarea.width()/2)/zoom - svgCanvas.contentW;
2488
- var y = (workarea[0].scrollTop + workarea.height()/2)/zoom - svgCanvas.contentH;
2489
- svgCanvas.pasteElements('point', x, y);
2490
- }
2491
-
2492
- var moveToTopSelected = function() {
2493
- if (selectedElement != null) {
2494
- svgCanvas.moveToTopSelectedElement();
2495
- }
2496
- };
2497
-
2498
- var moveToBottomSelected = function() {
2499
- if (selectedElement != null) {
2500
- svgCanvas.moveToBottomSelectedElement();
2501
- }
2502
- };
2503
-
2504
- var moveUpDownSelected = function(dir) {
2505
- if (selectedElement != null) {
2506
- svgCanvas.moveUpDownSelected(dir);
2507
- }
2508
- };
2509
-
2510
- var convertToPath = function() {
2511
- if (selectedElement != null) {
2512
- svgCanvas.convertToPath();
2513
- }
2514
- }
2515
-
2516
- var reorientPath = function() {
2517
- if (selectedElement != null) {
2518
- path.reorient();
2519
- }
2520
- }
2521
-
2522
- var makeHyperlink = function() {
2523
- if (selectedElement != null || multiselected) {
2524
- $.prompt(uiStrings.notification.enterNewLinkURL, "http://", function(url) {
2525
- if(url) svgCanvas.makeHyperlink(url);
2526
- });
2527
- }
2528
- }
2529
-
2530
- var moveSelected = function(dx,dy) {
2531
- if (selectedElement != null || multiselected) {
2532
- if(curConfig.gridSnapping) {
2533
- // Use grid snap value regardless of zoom level
2534
- var multi = svgCanvas.getZoom() * curConfig.snappingStep;
2535
- dx *= multi;
2536
- dy *= multi;
2537
- }
2538
- svgCanvas.moveSelectedElements(dx,dy);
2539
- }
2540
- };
2541
-
2542
- var linkControlPoints = function() {
2543
- var linked = !$('#tool_node_link').hasClass('push_button_pressed');
2544
- if (linked)
2545
- $('#tool_node_link').addClass('push_button_pressed').removeClass('tool_button');
2546
- else
2547
- $('#tool_node_link').removeClass('push_button_pressed').addClass('tool_button');
2548
-
2549
- path.linkControlPoints(linked);
2550
- }
2551
-
2552
- var clonePathNode = function() {
2553
- if (path.getNodePoint()) {
2554
- path.clonePathNode();
2555
- }
2556
- };
2557
-
2558
- var deletePathNode = function() {
2559
- if (path.getNodePoint()) {
2560
- path.deletePathNode();
2561
- }
2562
- };
2563
-
2564
- var addSubPath = function() {
2565
- var button = $('#tool_add_subpath');
2566
- var sp = !button.hasClass('push_button_pressed');
2567
- if (sp) {
2568
- button.addClass('push_button_pressed').removeClass('tool_button');
2569
- } else {
2570
- button.removeClass('push_button_pressed').addClass('tool_button');
2571
- }
2572
-
2573
- path.addSubPath(sp);
2574
-
2575
- };
2576
-
2577
- var opencloseSubPath = function() {
2578
- path.opencloseSubPath();
2579
- }
2580
-
2581
- var selectNext = function() {
2582
- svgCanvas.cycleElement(1);
2583
- };
2584
-
2585
- var selectPrev = function() {
2586
- svgCanvas.cycleElement(0);
2587
- };
2588
-
2589
- var rotateSelected = function(cw,step) {
2590
- if (selectedElement == null || multiselected) return;
2591
- if(!cw) step *= -1;
2592
- var new_angle = $('#angle').val()*1 + step;
2593
- svgCanvas.setRotationAngle(new_angle);
2594
- updateContextPanel();
2595
- };
2596
-
2597
- var clickClear = function(){
2598
- var dims = curConfig.dimensions;
2599
- $.confirm(uiStrings.notification.QwantToClear, function(ok) {
2600
- if(!ok) return;
2601
- setSelectMode();
2602
- svgCanvas.clear();
2603
- svgCanvas.setResolution(dims[0], dims[1]);
2604
- updateCanvas(true);
2605
- zoomImage();
2606
- populateLayers();
2607
- updateContextPanel();
2608
- prepPaints();
2609
- svgCanvas.runExtensions('onNewDocument');
2610
- });
2611
- };
2612
-
2613
- var clickBold = function(){
2614
- svgCanvas.setBold( !svgCanvas.getBold() );
2615
- updateContextPanel();
2616
- return false;
2617
- };
2618
-
2619
- var clickItalic = function(){
2620
- svgCanvas.setItalic( !svgCanvas.getItalic() );
2621
- updateContextPanel();
2622
- return false;
2623
- };
2624
-
2625
- var clickSave = function(){
2626
- // In the future, more options can be provided here
2627
- var saveOpts = {
2628
- 'images': curPrefs.img_save,
2629
- 'round_digits': 6
2630
- }
2631
- svgCanvas.save(saveOpts);
2632
- };
2633
-
2634
- var clickExport = function() {
2635
- // Open placeholder window (prevents popup)
2636
- if(!customHandlers.pngsave) {
2637
- var str = uiStrings.notification.loadingImage;
2638
- exportWindow = window.open("data:text/html;charset=utf-8,<title>" + str + "<\/title><h1>" + str + "<\/h1>");
2639
- }
2640
-
2641
- if(window.canvg) {
2642
- svgCanvas.rasterExport();
2643
- } else {
2644
- $.getScript('/assets/canvg/rgbcolor.js', function() {
2645
- $.getScript('/assets/canvg/canvg.js', function() {
2646
- svgCanvas.rasterExport();
2647
- });
2648
- });
2649
- }
2650
- }
2651
-
2652
- // by default, svgCanvas.open() is a no-op.
2653
- // it is up to an extension mechanism (opera widget, etc)
2654
- // to call setCustomHandlers() which will make it do something
2655
- var clickOpen = function(){
2656
- svgCanvas.open();
2657
- };
2658
- var clickImport = function(){
2659
- };
2660
-
2661
- var clickUndo = function(){
2662
- if (undoMgr.getUndoStackSize() > 0) {
2663
- undoMgr.undo();
2664
- populateLayers();
2665
- }
2666
- };
2667
-
2668
- var clickRedo = function(){
2669
- if (undoMgr.getRedoStackSize() > 0) {
2670
- undoMgr.redo();
2671
- populateLayers();
2672
- }
2673
- };
2674
-
2675
- var clickGroup = function(){
2676
- // group
2677
- if (multiselected) {
2678
- svgCanvas.groupSelectedElements();
2679
- }
2680
- // ungroup
2681
- else if(selectedElement){
2682
- svgCanvas.ungroupSelectedElement();
2683
- }
2684
- };
2685
-
2686
- var clickClone = function(){
2687
- svgCanvas.cloneSelectedElements(20,20);
2688
- };
2689
-
2690
- var clickAlign = function() {
2691
- var letter = this.id.replace('tool_align','').charAt(0);
2692
- svgCanvas.alignSelectedElements(letter, $('#align_relative_to').val());
2693
- };
2694
-
2695
- var zoomImage = function(multiplier) {
2696
- var res = svgCanvas.getResolution();
2697
- multiplier = multiplier?res.zoom * multiplier:1;
2698
- // setResolution(res.w * multiplier, res.h * multiplier, true);
2699
- $('#zoom').val(multiplier * 100);
2700
- svgCanvas.setZoom(multiplier);
2701
- zoomDone();
2702
- updateCanvas(true);
2703
- };
2704
-
2705
- var zoomDone = function() {
2706
- // updateBgImage();
2707
- updateWireFrame();
2708
- //updateCanvas(); // necessary?
2709
- }
2710
-
2711
- var clickWireframe = function() {
2712
- var wf = !$('#tool_wireframe').hasClass('push_button_pressed');
2713
- if (wf)
2714
- $('#tool_wireframe').addClass('push_button_pressed').removeClass('tool_button');
2715
- else
2716
- $('#tool_wireframe').removeClass('push_button_pressed').addClass('tool_button');
2717
- workarea.toggleClass('wireframe');
2718
-
2719
- if(supportsNonSS) return;
2720
- var wf_rules = $('#wireframe_rules');
2721
- if(!wf_rules.length) {
2722
- wf_rules = $('<style id="wireframe_rules"><\/style>').appendTo('head');
2723
- } else {
2724
- wf_rules.empty();
2725
- }
2726
-
2727
- updateWireFrame();
2728
- }
2729
-
2730
- var updateWireFrame = function() {
2731
- // Test support
2732
- if(supportsNonSS) return;
2733
-
2734
- var rule = "#workarea.wireframe #svgcontent * { stroke-width: " + 1/svgCanvas.getZoom() + "px; }";
2735
- $('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : "");
2736
- }
2737
-
2738
- var showSourceEditor = function(e, forSaving){
2739
- if (editingsource) return;
2740
- editingsource = true;
2741
-
2742
- $('#save_output_btns').toggle(!!forSaving);
2743
- $('#tool_source_back').toggle(!forSaving);
2744
-
2745
- var str = orig_source = svgCanvas.getSvgString();
2746
- $('#svg_source_textarea').val(str);
2747
- $('#svg_source_editor').fadeIn();
2748
- properlySourceSizeTextArea();
2749
- $('#svg_source_textarea').focus();
2750
- };
2751
-
2752
- $('#svg_docprops_container, #svg_prefs_container').draggable({cancel:'button,fieldset', containment: 'window'});
2753
-
2754
- var showDocProperties = function(){
2755
- if (docprops) return;
2756
- docprops = true;
2757
-
2758
- // This selects the correct radio button by using the array notation
2759
- $('#image_save_opts input').val([curPrefs.img_save]);
2760
-
2761
- // update resolution option with actual resolution
2762
- var res = svgCanvas.getResolution();
2763
- if(curConfig.baseUnit !== "px") {
2764
- res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit;
2765
- res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit;
2766
- }
2767
-
2768
- $('#canvas_width').val(res.w);
2769
- $('#canvas_height').val(res.h);
2770
- $('#canvas_title').val(svgCanvas.getDocumentTitle());
2771
-
2772
- $('#svg_docprops').show();
2773
- };
2774
-
2775
-
2776
- var showPreferences = function(){
2777
- if (preferences) return;
2778
- preferences = true;
2779
- $('#main_menu').hide();
2780
-
2781
- // Update background color with current one
2782
- var blocks = $('#bg_blocks div');
2783
- var cur_bg = 'cur_background';
2784
- var canvas_bg = $.pref('bkgd_color');
2785
- var url = $.pref('bkgd_url');
2786
- // if(url) url = url[1];
2787
- blocks.each(function() {
2788
- var blk = $(this);
2789
- var is_bg = blk.css('background-color') == canvas_bg;
2790
- blk.toggleClass(cur_bg, is_bg);
2791
- if(is_bg) $('#canvas_bg_url').removeClass(cur_bg);
2792
- });
2793
- if(!canvas_bg) blocks.eq(0).addClass(cur_bg);
2794
- if(url) {
2795
- $('#canvas_bg_url').val(url);
2796
- }
2797
- $('grid_snapping_step').attr('value', curConfig.snappingStep);
2798
- if (curConfig.gridSnapping == true) {
2799
- $('#grid_snapping_on').attr('checked', 'checked');
2800
- } else {
2801
- $('#grid_snapping_on').removeAttr('checked');
2802
- }
2803
-
2804
- $('#svg_prefs').show();
2805
- };
2806
-
2807
- var properlySourceSizeTextArea = function(){
2808
- // TODO: remove magic numbers here and get values from CSS
2809
- var height = $('#svg_source_container').height() - 80;
2810
- $('#svg_source_textarea').css('height', height);
2811
- };
2812
-
2813
- var saveSourceEditor = function(){
2814
- if (!editingsource) return;
2815
-
2816
- var saveChanges = function() {
2817
- svgCanvas.clearSelection();
2818
- hideSourceEditor();
2819
- zoomImage();
2820
- populateLayers();
2821
- updateTitle();
2822
- prepPaints();
2823
- }
2824
-
2825
- if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) {
2826
- $.confirm(uiStrings.notification.QerrorsRevertToSource, function(ok) {
2827
- if(!ok) return false;
2828
- saveChanges();
2829
- });
2830
- } else {
2831
- saveChanges();
2832
- }
2833
- setSelectMode();
2834
- };
2835
-
2836
- var updateTitle = function(title) {
2837
- title = title || svgCanvas.getDocumentTitle();
2838
- var new_title = orig_title + (title?': ' + title:'');
2839
-
2840
- // Remove title update with current context info, isn't really necessary
2841
- // if(cur_context) {
2842
- // new_title = new_title + cur_context;
2843
- // }
2844
- $('title:first').text(new_title);
2845
- }
2846
-
2847
- var saveDocProperties = function(){
2848
- // set title
2849
- var new_title = $('#canvas_title').val();
2850
- updateTitle(new_title);
2851
- svgCanvas.setDocumentTitle(new_title);
2852
-
2853
- // update resolution
2854
- var width = $('#canvas_width'), w = width.val();
2855
- var height = $('#canvas_height'), h = height.val();
2856
-
2857
- if(w != "fit" && !svgedit.units.isValidUnit('width', w)) {
2858
- $.alert(uiStrings.notification.invalidAttrValGiven);
2859
- width.parent().addClass('error');
2860
- return false;
2861
- }
2862
-
2863
- width.parent().removeClass('error');
2864
-
2865
- if(h != "fit" && !svgedit.units.isValidUnit('height', h)) {
2866
- $.alert(uiStrings.notification.invalidAttrValGiven);
2867
- height.parent().addClass('error');
2868
- return false;
2869
- }
2870
-
2871
- height.parent().removeClass('error');
2872
-
2873
- if(!svgCanvas.setResolution(w, h)) {
2874
- $.alert(uiStrings.notification.noContentToFitTo);
2875
- return false;
2876
- }
2877
-
2878
- // set image save option
2879
- curPrefs.img_save = $('#image_save_opts :checked').val();
2880
- $.pref('img_save',curPrefs.img_save);
2881
- updateCanvas();
2882
- hideDocProperties();
2883
- };
2884
-
2885
- var savePreferences = function() {
2886
- // set background
2887
- var color = $('#bg_blocks div.cur_background').css('background-color') || '#FFF';
2888
- setBackground(color, $('#canvas_bg_url').val());
2889
-
2890
- // set language
2891
- var lang = $('#lang_select').val();
2892
- if(lang != curPrefs.lang) {
2893
- Editor.putLocale(lang);
2894
- }
2895
-
2896
- // set icon size
2897
- setIconSize($('#iconsize').val());
2898
-
2899
- // set grid setting
2900
- curConfig.gridSnapping = $('#grid_snapping_on')[0].checked;
2901
- curConfig.snappingStep = $('#grid_snapping_step').val();
2902
- curConfig.showRulers = $('#show_rulers')[0].checked;
2903
-
2904
- $('#rulers').toggle(curConfig.showRulers);
2905
- if(curConfig.showRulers) updateRulers();
2906
- curConfig.baseUnit = $('#base_unit').val();
2907
-
2908
- svgCanvas.setConfig(curConfig);
2909
-
2910
- updateCanvas();
2911
- hidePreferences();
2912
- }
2913
-
2914
- function setBackground(color, url) {
2915
- // if(color == curPrefs.bkgd_color && url == curPrefs.bkgd_url) return;
2916
- $.pref('bkgd_color', color);
2917
- $.pref('bkgd_url', url);
2918
-
2919
- // This should be done in svgcanvas.js for the borderRect fill
2920
- svgCanvas.setBackground(color, url);
2921
- }
2922
-
2923
- var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) {
2924
- var icon = (typeof icon_id === 'string') ? $.getSvgIcon(icon_id, true) : icon_id.clone();
2925
- if(!icon) {
2926
- console.log('NOTE: Icon image missing: ' + icon_id);
2927
- return;
2928
- }
2929
-
2930
- $(elem).empty().append(icon);
2931
- }
2932
-
2933
- var ua_prefix;
2934
- (ua_prefix = function() {
2935
- var regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/;
2936
- var someScript = document.getElementsByTagName('script')[0];
2937
- for(var prop in someScript.style) {
2938
- if(regex.test(prop)) {
2939
- // test is faster than match, so it's better to perform
2940
- // that on the lot and match only when necessary
2941
- return prop.match(regex)[0];
2942
- }
2943
- }
2944
-
2945
- // Nothing found so far?
2946
- if('WebkitOpacity' in someScript.style) return 'Webkit';
2947
- if('KhtmlOpacity' in someScript.style) return 'Khtml';
2948
-
2949
- return '';
2950
- }());
2951
-
2952
- var scaleElements = function(elems, scale) {
2953
- var prefix = '-' + ua_prefix.toLowerCase() + '-';
2954
-
2955
- var sides = ['top', 'left', 'bottom', 'right'];
2956
-
2957
- elems.each(function() {
2958
- // console.log('go', scale);
2959
-
2960
- // Handled in CSS
2961
- // this.style[ua_prefix + 'Transform'] = 'scale(' + scale + ')';
2962
-
2963
- var el = $(this);
2964
-
2965
- var w = el.outerWidth() * (scale - 1);
2966
- var h = el.outerHeight() * (scale - 1);
2967
- var margins = {};
2968
-
2969
- for(var i = 0; i < 4; i++) {
2970
- var s = sides[i];
2971
-
2972
- var cur = el.data('orig_margin-' + s);
2973
- if(cur == null) {
2974
- cur = parseInt(el.css('margin-' + s));
2975
- // Cache the original margin
2976
- el.data('orig_margin-' + s, cur);
2977
- }
2978
- var val = cur * scale;
2979
- if(s === 'right') {
2980
- val += w;
2981
- } else if(s === 'bottom') {
2982
- val += h;
2983
- }
2984
-
2985
- el.css('margin-' + s, val);
2986
- // el.css('outline', '1px solid red');
2987
- }
2988
- });
2989
- }
2990
-
2991
- var setIconSize = Editor.setIconSize = function(size, force) {
2992
- if(size == curPrefs.size && !force) return;
2993
- // return;
2994
- // var elems = $('.tool_button, .push_button, .tool_button_current, .disabled, .icon_label, #url_notice, #tool_open');
2995
- console.log('size', size);
2996
-
2997
- var sel_toscale = '#tools_top .toolset, #editor_panel > *, #history_panel > *,\
2998
- #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\
2999
- #g_panel > *, #tool_font_size > *, .tools_flyout';
3000
-
3001
- var elems = $(sel_toscale);
3002
-
3003
- var scale = 1;
3004
-
3005
- if(typeof size == 'number') {
3006
- scale = size;
3007
- } else {
3008
- var icon_sizes = { s:.75, m:1, l:1.25, xl:1.5 };
3009
- scale = icon_sizes[size];
3010
- }
3011
-
3012
- Editor.tool_scale = tool_scale = scale;
3013
-
3014
- setFlyoutPositions();
3015
- // $('.tools_flyout').each(function() {
3016
- // var pos = $(this).position();
3017
- // console.log($(this), pos.left+(34 * scale));
3018
- // $(this).css({'left': pos.left+(34 * scale), 'top': pos.top+(77 * scale)});
3019
- // console.log('l', $(this).css('left'));
3020
- // });
3021
-
3022
- // var scale = .75;//0.75;
3023
-
3024
- var hidden_ps = elems.parents(':hidden');
3025
- hidden_ps.css('visibility', 'hidden').show();
3026
- scaleElements(elems, scale);
3027
- hidden_ps.css('visibility', 'visible').hide();
3028
- // console.timeEnd('elems');
3029
- // return;
3030
-
3031
- $.pref('iconsize', size);
3032
- $('#iconsize').val(size);
3033
-
3034
-
3035
- // Change icon size
3036
- // $('.tool_button, .push_button, .tool_button_current, .disabled, .icon_label, #url_notice, #tool_open')
3037
- // .find('> svg, > img').each(function() {
3038
- // this.setAttribute('width',size_num);
3039
- // this.setAttribute('height',size_num);
3040
- // });
3041
- //
3042
- // $.resizeSvgIcons({
3043
- // '.flyout_arrow_horiz > svg, .flyout_arrow_horiz > img': size_num / 5,
3044
- // '#logo > svg, #logo > img': size_num * 1.3,
3045
- // '#tools_bottom .icon_label > *': (size_num === 16 ? 18 : size_num * .75)
3046
- // });
3047
- // if(size != 's') {
3048
- // $.resizeSvgIcons({'#layerbuttons svg, #layerbuttons img': size_num * .6});
3049
- // }
3050
-
3051
- // Note that all rules will be prefixed with '#svg_editor' when parsed
3052
- var cssResizeRules = {
3053
- // ".tool_button,\
3054
- // .push_button,\
3055
- // .tool_button_current,\
3056
- // .push_button_pressed,\
3057
- // .disabled,\
3058
- // .icon_label,\
3059
- // .tools_flyout .tool_button": {
3060
- // 'width': {s: '16px', l: '32px', xl: '48px'},
3061
- // 'height': {s: '16px', l: '32px', xl: '48px'},
3062
- // 'padding': {s: '1px', l: '2px', xl: '3px'}
3063
- // },
3064
- // ".tool_sep": {
3065
- // 'height': {s: '16px', l: '32px', xl: '48px'},
3066
- // 'margin': {s: '2px 2px', l: '2px 5px', xl: '2px 8px'}
3067
- // },
3068
- // "#main_icon": {
3069
- // 'width': {s: '31px', l: '53px', xl: '75px'},
3070
- // 'height': {s: '22px', l: '42px', xl: '64px'}
3071
- // },
3072
- "#tools_top": {
3073
- 'left': 50,
3074
- 'height': 72
3075
- },
3076
- "#tools_left": {
3077
- 'width': 31,
3078
- 'top': 74
3079
- },
3080
- "div#workarea": {
3081
- 'left': 38,
3082
- 'top': 74
3083
- }
3084
- // "#tools_bottom": {
3085
- // 'left': {s: '27px', l: '46px', xl: '65px'},
3086
- // 'height': {s: '58px', l: '98px', xl: '145px'}
3087
- // },
3088
- // "#color_tools": {
3089
- // 'border-spacing': {s: '0 1px'},
3090
- // 'margin-top': {s: '-1px'}
3091
- // },
3092
- // "#color_tools .icon_label": {
3093
- // 'width': {l:'43px', xl: '60px'}
3094
- // },
3095
- // ".color_tool": {
3096
- // 'height': {s: '20px'}
3097
- // },
3098
- // "#tool_opacity": {
3099
- // 'top': {s: '1px'},
3100
- // 'height': {s: 'auto', l:'auto', xl:'auto'}
3101
- // },
3102
- // "#tools_top input, #tools_bottom input": {
3103
- // 'margin-top': {s: '2px', l: '4px', xl: '5px'},
3104
- // 'height': {s: 'auto', l: 'auto', xl: 'auto'},
3105
- // 'border': {s: '1px solid #555', l: 'auto', xl: 'auto'},
3106
- // 'font-size': {s: '.9em', l: '1.2em', xl: '1.4em'}
3107
- // },
3108
- // "#zoom_panel": {
3109
- // 'margin-top': {s: '3px', l: '4px', xl: '5px'}
3110
- // },
3111
- // "#copyright, #tools_bottom .label": {
3112
- // 'font-size': {l: '1.5em', xl: '2em'},
3113
- // 'line-height': {s: '15px'}
3114
- // },
3115
- // "#tools_bottom_2": {
3116
- // 'width': {l: '295px', xl: '355px'},
3117
- // 'top': {s: '4px'}
3118
- // },
3119
- // "#tools_top > div, #tools_top": {
3120
- // 'line-height': {s: '17px', l: '34px', xl: '50px'}
3121
- // },
3122
- // ".dropdown button": {
3123
- // 'height': {s: '18px', l: '34px', xl: '40px'},
3124
- // 'line-height': {s: '18px', l: '34px', xl: '40px'},
3125
- // 'margin-top': {s: '3px'}
3126
- // },
3127
- // "#tools_top label, #tools_bottom label": {
3128
- // 'font-size': {s: '1em', l: '1.5em', xl: '2em'},
3129
- // 'height': {s: '25px', l: '42px', xl: '64px'}
3130
- // },
3131
- // "div.toolset": {
3132
- // 'height': {s: '25px', l: '42px', xl: '64px'}
3133
- // },
3134
- // "#tool_bold, #tool_italic": {
3135
- // 'font-size': {s: '1.5em', l: '3em', xl: '4.5em'}
3136
- // },
3137
- // "#sidepanels": {
3138
- // 'top': {s: '50px', l: '88px', xl: '125px'},
3139
- // 'bottom': {s: '51px', l: '68px', xl: '65px'}
3140
- // },
3141
- // '#layerbuttons': {
3142
- // 'width': {l: '130px', xl: '175px'},
3143
- // 'height': {l: '24px', xl: '30px'}
3144
- // },
3145
- // '#layerlist': {
3146
- // 'width': {l: '128px', xl: '150px'}
3147
- // },
3148
- // '.layer_button': {
3149
- // 'width': {l: '19px', xl: '28px'},
3150
- // 'height': {l: '19px', xl: '28px'}
3151
- // },
3152
- // "input.spin-button": {
3153
- // 'background-image': {l: "url('images/spinbtn_updn_big.png')", xl: "url('images/spinbtn_updn_big.png')"},
3154
- // 'background-position': {l: '100% -5px', xl: '100% -2px'},
3155
- // 'padding-right': {l: '24px', xl: '24px' }
3156
- // },
3157
- // "input.spin-button.up": {
3158
- // 'background-position': {l: '100% -45px', xl: '100% -42px'}
3159
- // },
3160
- // "input.spin-button.down": {
3161
- // 'background-position': {l: '100% -85px', xl: '100% -82px'}
3162
- // },
3163
- // "#position_opts": {
3164
- // 'width': {all: (size_num*4) +'px'}
3165
- // }
3166
- };
3167
-
3168
- var rule_elem = $('#tool_size_rules');
3169
- if(!rule_elem.length) {
3170
- rule_elem = $('<style id="tool_size_rules"><\/style>').appendTo('head');
3171
- } else {
3172
- rule_elem.empty();
3173
- }
3174
-
3175
- if(size != 'm') {
3176
- var style_str = '';
3177
- $.each(cssResizeRules, function(selector, rules) {
3178
- selector = '#svg_editor ' + selector.replace(/,/g,', #svg_editor');
3179
- style_str += selector + '{';
3180
- $.each(rules, function(prop, values) {
3181
- if(typeof values === 'number') {
3182
- var val = (values * scale) + 'px';
3183
- } else if(values[size] || values.all) {
3184
- var val = (values[size] || values.all);
3185
- }
3186
- style_str += (prop + ':' + val + ';');
3187
- });
3188
- style_str += '}';
3189
- });
3190
- //this.style[ua_prefix + 'Transform'] = 'scale(' + scale + ')';
3191
- var prefix = '-' + ua_prefix.toLowerCase() + '-';
3192
- style_str += (sel_toscale + '{' + prefix + 'transform: scale(' + scale + ');}'
3193
- + ' #svg_editor div.toolset .toolset {' + prefix + 'transform: scale(1); margin: 1px !important;}' // Hack for markers
3194
- + ' #svg_editor .ui-slider {' + prefix + 'transform: scale(' + (1/scale) + ');}' // Hack for sliders
3195
- );
3196
- rule_elem.text(style_str);
3197
- }
3198
-
3199
- setFlyoutPositions();
3200
- }
3201
-
3202
- var cancelOverlays = function() {
3203
- $('#dialog_box').hide();
3204
- if (!editingsource && !docprops && !preferences) {
3205
- if(cur_context) {
3206
- svgCanvas.leaveContext();
3207
- }
3208
- return;
3209
- };
3210
-
3211
- if (editingsource) {
3212
- if (orig_source !== $('#svg_source_textarea').val()) {
3213
- $.confirm(uiStrings.notification.QignoreSourceChanges, function(ok) {
3214
- if(ok) hideSourceEditor();
3215
- });
3216
- } else {
3217
- hideSourceEditor();
3218
- }
3219
- }
3220
- else if (docprops) {
3221
- hideDocProperties();
3222
- } else if (preferences) {
3223
- hidePreferences();
3224
- }
3225
- resetScrollPos();
3226
- };
3227
-
3228
- var hideSourceEditor = function(){
3229
- $('#svg_source_editor').hide();
3230
- editingsource = false;
3231
- $('#svg_source_textarea').blur();
3232
- };
3233
-
3234
- var hideDocProperties = function(){
3235
- $('#svg_docprops').hide();
3236
- $('#canvas_width,#canvas_height').removeAttr('disabled');
3237
- $('#resolution')[0].selectedIndex = 0;
3238
- $('#image_save_opts input').val([curPrefs.img_save]);
3239
- docprops = false;
3240
- };
3241
-
3242
- var hidePreferences = function(){
3243
- $('#svg_prefs').hide();
3244
- preferences = false;
3245
- };
3246
-
3247
- var win_wh = {width:$(window).width(), height:$(window).height()};
3248
-
3249
- var resetScrollPos = $.noop, curScrollPos;
3250
-
3251
- // Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9)
3252
- if(svgedit.browser.isIE()) {
3253
- (function() {
3254
- resetScrollPos = function() {
3255
- if(workarea[0].scrollLeft === 0
3256
- && workarea[0].scrollTop === 0) {
3257
- workarea[0].scrollLeft = curScrollPos.left;
3258
- workarea[0].scrollTop = curScrollPos.top;
3259
- }
3260
- }
3261
-
3262
- curScrollPos = {
3263
- left: workarea[0].scrollLeft,
3264
- top: workarea[0].scrollTop
3265
- };
3266
-
3267
- $(window).resize(resetScrollPos);
3268
- svgEditor.ready(function() {
3269
- // TODO: Find better way to detect when to do this to minimize
3270
- // flickering effect
3271
- setTimeout(function() {
3272
- resetScrollPos();
3273
- }, 500);
3274
- });
3275
-
3276
- workarea.scroll(function() {
3277
- curScrollPos = {
3278
- left: workarea[0].scrollLeft,
3279
- top: workarea[0].scrollTop
3280
- };
3281
- });
3282
- }());
3283
- }
3284
-
3285
- $(window).resize(function(evt) {
3286
- if (editingsource) {
3287
- properlySourceSizeTextArea();
3288
- }
3289
-
3290
- $.each(win_wh, function(type, val) {
3291
- var curval = $(window)[type]();
3292
- workarea[0]['scroll' + (type==='width'?'Left':'Top')] -= (curval - val)/2;
3293
- win_wh[type] = curval;
3294
- });
3295
- });
3296
-
3297
- (function() {
3298
- workarea.scroll(function() {
3299
- // TODO: jQuery's scrollLeft/Top() wouldn't require a null check
3300
- if ($('#ruler_x').length != 0) {
3301
- $('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft;
3302
- }
3303
- if ($('#ruler_y').length != 0) {
3304
- $('#ruler_y')[0].scrollTop = workarea[0].scrollTop;
3305
- }
3306
- });
3307
-
3308
- }());
3309
-
3310
- $('#url_notice').click(function() {
3311
- $.alert(this.title);
3312
- });
3313
-
3314
- $('#change_image_url').click(promptImgURL);
3315
-
3316
- function promptImgURL() {
3317
- var curhref = svgCanvas.getHref(selectedElement);
3318
- curhref = curhref.indexOf("data:") === 0?"":curhref;
3319
- $.prompt(uiStrings.notification.enterNewImgURL, curhref, function(url) {
3320
- if(url) setImageURL(url);
3321
- });
3322
- }
3323
-
3324
- // added these event handlers for all the push buttons so they
3325
- // behave more like buttons being pressed-in and not images
3326
- (function() {
3327
- var toolnames = ['clear','open','save','source','delete','delete_multi','paste','clone','clone_multi','move_top','move_bottom'];
3328
- var all_tools = '';
3329
- var cur_class = 'tool_button_current';
3330
-
3331
- $.each(toolnames, function(i,item) {
3332
- all_tools += '#tool_' + item + (i==toolnames.length-1?',':'');
3333
- });
3334
-
3335
- $(all_tools).mousedown(function() {
3336
- $(this).addClass(cur_class);
3337
- }).bind('mousedown mouseout', function() {
3338
- $(this).removeClass(cur_class);
3339
- });
3340
-
3341
- $('#tool_undo, #tool_redo').mousedown(function(){
3342
- if (!$(this).hasClass('disabled')) $(this).addClass(cur_class);
3343
- }).bind('mousedown mouseout',function(){
3344
- $(this).removeClass(cur_class);}
3345
- );
3346
- }());
3347
-
3348
- // switch modifier key in tooltips if mac
3349
- // NOTE: This code is not used yet until I can figure out how to successfully bind ctrl/meta
3350
- // in Opera and Chrome
3351
- if (isMac && !window.opera) {
3352
- var shortcutButtons = ["tool_clear", "tool_save", "tool_source", "tool_undo", "tool_redo", "tool_clone"];
3353
- var i = shortcutButtons.length;
3354
- while (i--) {
3355
- var button = document.getElementById(shortcutButtons[i]);
3356
- if (button != null) {
3357
- var title = button.title;
3358
- var index = title.indexOf("Ctrl+");
3359
- button.title = [title.substr(0, index), "Cmd+", title.substr(index + 5)].join('');
3360
- }
3361
- }
3362
- }
3363
-
3364
- // TODO: go back to the color boxes having white background-color and then setting
3365
- // background-image to none.png (otherwise partially transparent gradients look weird)
3366
- var colorPicker = function(elem) {
3367
- var picker = elem.attr('id') == 'stroke_color' ? 'stroke' : 'fill';
3368
- // var opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity'));
3369
- var paint = paintBox[picker].paint;
3370
- var title = (picker == 'stroke' ? 'Pick a Stroke Paint and Opacity' : 'Pick a Fill Paint and Opacity');
3371
- var was_none = false;
3372
- var pos = elem.offset();
3373
- $("#color_picker")
3374
- .draggable({cancel:'.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker', containment: 'window'})
3375
- .css(curConfig.colorPickerCSS || {'left': pos.left-140, 'bottom': 40})
3376
- .jGraduate(
3377
- {
3378
- paint: paint,
3379
- window: { pickerTitle: title },
3380
- images: { clientPath: curConfig.jGraduatePath },
3381
- newstop: 'inverse'
3382
- },
3383
- function(p) {
3384
- paint = new $.jGraduate.Paint(p);
3385
- paintBox[picker].setPaint(paint);
3386
- svgCanvas.setPaint(picker, paint);
3387
-
3388
- $('#color_picker').hide();
3389
- },
3390
- function(p) {
3391
- $('#color_picker').hide();
3392
- });
3393
- };
3394
-
3395
- var updateToolButtonState = function() {
3396
- var bNoFill = (svgCanvas.getColor('fill') == 'none');
3397
- var bNoStroke = (svgCanvas.getColor('stroke') == 'none');
3398
- var buttonsNeedingStroke = [ '#tool_fhpath', '#tool_line' ];
3399
- var buttonsNeedingFillAndStroke = [ '#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path'];
3400
- if (bNoStroke) {
3401
- for (var index in buttonsNeedingStroke) {
3402
- var button = buttonsNeedingStroke[index];
3403
- if ($(button).hasClass('tool_button_current')) {
3404
- clickSelect();
3405
- }
3406
- $(button).addClass('disabled');
3407
- }
3408
- }
3409
- else {
3410
- for (var index in buttonsNeedingStroke) {
3411
- var button = buttonsNeedingStroke[index];
3412
- $(button).removeClass('disabled');
3413
- }
3414
- }
3415
-
3416
- if (bNoStroke && bNoFill) {
3417
- for (var index in buttonsNeedingFillAndStroke) {
3418
- var button = buttonsNeedingFillAndStroke[index];
3419
- if ($(button).hasClass('tool_button_current')) {
3420
- clickSelect();
3421
- }
3422
- $(button).addClass('disabled');
3423
- }
3424
- }
3425
- else {
3426
- for (var index in buttonsNeedingFillAndStroke) {
3427
- var button = buttonsNeedingFillAndStroke[index];
3428
- $(button).removeClass('disabled');
3429
- }
3430
- }
3431
-
3432
- svgCanvas.runExtensions("toolButtonStateUpdate", {
3433
- nofill: bNoFill,
3434
- nostroke: bNoStroke
3435
- });
3436
-
3437
- // Disable flyouts if all inside are disabled
3438
- $('.tools_flyout').each(function() {
3439
- var shower = $('#' + this.id + '_show');
3440
- var has_enabled = false;
3441
- $(this).children().each(function() {
3442
- if(!$(this).hasClass('disabled')) {
3443
- has_enabled = true;
3444
- }
3445
- });
3446
- shower.toggleClass('disabled', !has_enabled);
3447
- });
3448
-
3449
- operaRepaint();
3450
- };
3451
-
3452
-
3453
-
3454
- var PaintBox = function(container, type) {
3455
- var cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke'];
3456
-
3457
- // set up gradients to be used for the buttons
3458
- var svgdocbox = new DOMParser().parseFromString(
3459
- '<svg xmlns="http://www.w3.org/2000/svg"><rect width="16.5" height="16.5"\
3460
- fill="#' + cur.color + '" opacity="' + cur.opacity + '"/>\
3461
- <defs><linearGradient id="gradbox_"/></defs></svg>', 'text/xml');
3462
- var docElem = svgdocbox.documentElement;
3463
-
3464
- docElem = $(container)[0].appendChild(document.importNode(docElem, true));
3465
-
3466
- docElem.setAttribute('width',16.5);
3467
-
3468
- this.rect = docElem.firstChild;
3469
- this.defs = docElem.getElementsByTagName('defs')[0];
3470
- this.grad = this.defs.firstChild;
3471
- this.paint = new $.jGraduate.Paint({solidColor: cur.color});
3472
- this.type = type;
3473
-
3474
- this.setPaint = function(paint, apply) {
3475
- this.paint = paint;
3476
-
3477
- var fillAttr = "none";
3478
- var ptype = paint.type;
3479
- var opac = paint.alpha / 100;
3480
-
3481
- switch ( ptype ) {
3482
- case 'solidColor':
3483
- fillAttr = (paint[ptype] != 'none') ? "#" + paint[ptype] : paint[ptype];
3484
- break;
3485
- case 'linearGradient':
3486
- case 'radialGradient':
3487
- this.defs.removeChild(this.grad);
3488
- this.grad = this.defs.appendChild(paint[ptype]);
3489
- var id = this.grad.id = 'gradbox_' + this.type;
3490
- fillAttr = "url(#" + id + ')';
3491
- }
3492
-
3493
- this.rect.setAttribute('fill', fillAttr);
3494
- this.rect.setAttribute('opacity', opac);
3495
-
3496
- if(apply) {
3497
- svgCanvas.setColor(this.type, paintColor, true);
3498
- svgCanvas.setPaintOpacity(this.type, paintOpacity, true);
3499
- }
3500
- }
3501
-
3502
- this.update = function(apply) {
3503
- if(!selectedElement) return;
3504
- var type = this.type;
3505
-
3506
- switch ( selectedElement.tagName ) {
3507
- case 'use':
3508
- case 'image':
3509
- case 'foreignObject':
3510
- // These elements don't have fill or stroke, so don't change
3511
- // the current value
3512
- return;
3513
- case 'g':
3514
- case 'a':
3515
- var gPaint = null;
3516
-
3517
- var childs = selectedElement.getElementsByTagName('*');
3518
- for(var i = 0, len = childs.length; i < len; i++) {
3519
- var elem = childs[i];
3520
- var p = elem.getAttribute(type);
3521
- if(i === 0) {
3522
- gPaint = p;
3523
- } else if(gPaint !== p) {
3524
- gPaint = null;
3525
- break;
3526
- }
3527
- }
3528
- if(gPaint === null) {
3529
- // No common color, don't update anything
3530
- var paintColor = null;
3531
- return;
3532
- }
3533
- var paintColor = gPaint;
3534
-
3535
- var paintOpacity = 1;
3536
- break;
3537
- default:
3538
- var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity"));
3539
- if (isNaN(paintOpacity)) {
3540
- paintOpacity = 1.0;
3541
- }
3542
-
3543
- var defColor = type === "fill" ? "black" : "none";
3544
- var paintColor = selectedElement.getAttribute(type) || defColor;
3545
- }
3546
-
3547
- if(apply) {
3548
- svgCanvas.setColor(type, paintColor, true);
3549
- svgCanvas.setPaintOpacity(type, paintOpacity, true);
3550
- }
3551
-
3552
- paintOpacity *= 100;
3553
-
3554
- var paint = getPaint(paintColor, paintOpacity, type);
3555
- // update the rect inside #fill_color/#stroke_color
3556
- this.setPaint(paint);
3557
- }
3558
-
3559
- this.prep = function() {
3560
- var ptype = this.paint.type;
3561
-
3562
- switch ( ptype ) {
3563
- case 'linearGradient':
3564
- case 'radialGradient':
3565
- var paint = new $.jGraduate.Paint({copy: this.paint});
3566
- svgCanvas.setPaint(type, paint);
3567
- }
3568
- }
3569
- };
3570
-
3571
- paintBox.fill = new PaintBox('#fill_color', 'fill');
3572
- paintBox.stroke = new PaintBox('#stroke_color', 'stroke');
3573
-
3574
- $('#stroke_width').val(curConfig.initStroke.width);
3575
- $('#group_opacity').val(curConfig.initOpacity * 100);
3576
-
3577
- // Use this SVG elem to test vectorEffect support
3578
- var test_el = paintBox.fill.rect.cloneNode(false);
3579
- test_el.setAttribute('style','vector-effect:non-scaling-stroke');
3580
- var supportsNonSS = (test_el.style.vectorEffect === 'non-scaling-stroke');
3581
- test_el.removeAttribute('style');
3582
- var svgdocbox = paintBox.fill.rect.ownerDocument;
3583
- // Use this to test support for blur element. Seems to work to test support in Webkit
3584
- var blur_test = svgdocbox.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur');
3585
- if(typeof blur_test.stdDeviationX === "undefined") {
3586
- $('#tool_blur').hide();
3587
- }
3588
- $(blur_test).remove();
3589
-
3590
- // Test for zoom icon support
3591
- (function() {
3592
- var pre = '-' + ua_prefix.toLowerCase() + '-zoom-';
3593
- var zoom = pre + 'in';
3594
- workarea.css('cursor', zoom);
3595
- if(workarea.css('cursor') === zoom) {
3596
- zoomInIcon = zoom;
3597
- zoomOutIcon = pre + 'out';
3598
- }
3599
- workarea.css('cursor', 'auto');
3600
- }());
3601
-
3602
-
3603
-
3604
- // Test for embedImage support (use timeout to not interfere with page load)
3605
- setTimeout(function() {
3606
- svgCanvas.embedImage('/assets/images/logo.png', function(datauri) {
3607
- if(!datauri) {
3608
- // Disable option
3609
- $('#image_save_opts [value=embed]').attr('disabled','disabled');
3610
- $('#image_save_opts input').val(['ref']);
3611
- curPrefs.img_save = 'ref';
3612
- $('#image_opt_embed').css('color','#666').attr('title',uiStrings.notification.featNotSupported);
3613
- }
3614
- });
3615
- },1000);
3616
-
3617
- $('#fill_color, #tool_fill .icon_label').click(function(){
3618
- colorPicker($('#fill_color'));
3619
- updateToolButtonState();
3620
- });
3621
-
3622
- $('#stroke_color, #tool_stroke .icon_label').click(function(){
3623
- colorPicker($('#stroke_color'));
3624
- updateToolButtonState();
3625
- });
3626
-
3627
- $('#group_opacityLabel').click(function() {
3628
- $('#opacity_dropdown button').mousedown();
3629
- $(window).mouseup();
3630
- });
3631
-
3632
- $('#zoomLabel').click(function() {
3633
- $('#zoom_dropdown button').mousedown();
3634
- $(window).mouseup();
3635
- });
3636
-
3637
- $('#tool_move_top').mousedown(function(evt){
3638
- $('#tools_stacking').show();
3639
- evt.preventDefault();
3640
- });
3641
-
3642
- $('.layer_button').mousedown(function() {
3643
- $(this).addClass('layer_buttonpressed');
3644
- }).mouseout(function() {
3645
- $(this).removeClass('layer_buttonpressed');
3646
- }).mouseup(function() {
3647
- $(this).removeClass('layer_buttonpressed');
3648
- });
3649
-
3650
- $('.push_button').mousedown(function() {
3651
- if (!$(this).hasClass('disabled')) {
3652
- $(this).addClass('push_button_pressed').removeClass('push_button');
3653
- }
3654
- }).mouseout(function() {
3655
- $(this).removeClass('push_button_pressed').addClass('push_button');
3656
- }).mouseup(function() {
3657
- $(this).removeClass('push_button_pressed').addClass('push_button');
3658
- });
3659
-
3660
- $('#layer_new').click(function() {
3661
- var i = svgCanvas.getCurrentDrawing().getNumLayers();
3662
- do {
3663
- var uniqName = uiStrings.layers.layer + " " + ++i;
3664
- } while(svgCanvas.getCurrentDrawing().hasLayer(uniqName));
3665
-
3666
- $.prompt(uiStrings.notification.enterUniqueLayerName,uniqName, function(newName) {
3667
- if (!newName) return;
3668
- if (svgCanvas.getCurrentDrawing().hasLayer(newName)) {
3669
- $.alert(uiStrings.notification.dupeLayerName);
3670
- return;
3671
- }
3672
- svgCanvas.createLayer(newName);
3673
- updateContextPanel();
3674
- populateLayers();
3675
- });
3676
- });
3677
-
3678
- function deleteLayer() {
3679
- if (svgCanvas.deleteCurrentLayer()) {
3680
- updateContextPanel();
3681
- populateLayers();
3682
- // This matches what SvgCanvas does
3683
- // TODO: make this behavior less brittle (svg-editor should get which
3684
- // layer is selected from the canvas and then select that one in the UI)
3685
- $('#layerlist tr.layer').removeClass("layersel");
3686
- $('#layerlist tr.layer:first').addClass("layersel");
3687
- }
3688
- }
3689
-
3690
- function cloneLayer() {
3691
- var name = svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy';
3692
-
3693
- $.prompt(uiStrings.notification.enterUniqueLayerName, name, function(newName) {
3694
- if (!newName) return;
3695
- if (svgCanvas.getCurrentDrawing().hasLayer(newName)) {
3696
- $.alert(uiStrings.notification.dupeLayerName);
3697
- return;
3698
- }
3699
- svgCanvas.cloneLayer(newName);
3700
- updateContextPanel();
3701
- populateLayers();
3702
- });
3703
- }
3704
-
3705
- function mergeLayer() {
3706
- if($('#layerlist tr.layersel').index() == svgCanvas.getCurrentDrawing().getNumLayers()-1) return;
3707
- svgCanvas.mergeLayer();
3708
- updateContextPanel();
3709
- populateLayers();
3710
- }
3711
-
3712
- function moveLayer(pos) {
3713
- var curIndex = $('#layerlist tr.layersel').index();
3714
- var total = svgCanvas.getCurrentDrawing().getNumLayers();
3715
- if(curIndex > 0 || curIndex < total-1) {
3716
- curIndex += pos;
3717
- svgCanvas.setCurrentLayerPosition(total-curIndex-1);
3718
- populateLayers();
3719
- }
3720
- }
3721
-
3722
- $('#layer_delete').click(deleteLayer);
3723
-
3724
- $('#layer_up').click(function() {
3725
- moveLayer(-1);
3726
- });
3727
-
3728
- $('#layer_down').click(function() {
3729
- moveLayer(1);
3730
- });
3731
-
3732
- $('#layer_rename').click(function() {
3733
- var curIndex = $('#layerlist tr.layersel').prevAll().length;
3734
- var oldName = $('#layerlist tr.layersel td.layername').text();
3735
- $.prompt(uiStrings.notification.enterNewLayerName,"", function(newName) {
3736
- if (!newName) return;
3737
- if (oldName == newName || svgCanvas.getCurrentDrawing().hasLayer(newName)) {
3738
- $.alert(uiStrings.notification.layerHasThatName);
3739
- return;
3740
- }
3741
-
3742
- svgCanvas.renameCurrentLayer(newName);
3743
- populateLayers();
3744
- });
3745
- });
3746
-
3747
- var SIDEPANEL_MAXWIDTH = 300;
3748
- var SIDEPANEL_OPENWIDTH = 150;
3749
- var sidedrag = -1, sidedragging = false, allowmove = false;
3750
-
3751
- var resizePanel = function(evt) {
3752
- if (!allowmove) return;
3753
- if (sidedrag == -1) return;
3754
- sidedragging = true;
3755
- var deltax = sidedrag - evt.pageX;
3756
-
3757
- var sidepanels = $('#sidepanels');
3758
- var sidewidth = parseInt(sidepanels.css('width'));
3759
- if (sidewidth+deltax > SIDEPANEL_MAXWIDTH) {
3760
- deltax = SIDEPANEL_MAXWIDTH - sidewidth;
3761
- sidewidth = SIDEPANEL_MAXWIDTH;
3762
- }
3763
- else if (sidewidth+deltax < 2) {
3764
- deltax = 2 - sidewidth;
3765
- sidewidth = 2;
3766
- }
3767
-
3768
- if (deltax == 0) return;
3769
- sidedrag -= deltax;
3770
-
3771
- var layerpanel = $('#layerpanel');
3772
- workarea.css('right', parseInt(workarea.css('right'))+deltax);
3773
- sidepanels.css('width', parseInt(sidepanels.css('width'))+deltax);
3774
- layerpanel.css('width', parseInt(layerpanel.css('width'))+deltax);
3775
- var ruler_x = $('#ruler_x');
3776
- ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax);
3777
- }
3778
-
3779
- $('#sidepanel_handle')
3780
- .mousedown(function(evt) {
3781
- sidedrag = evt.pageX;
3782
- $(window).mousemove(resizePanel);
3783
- allowmove = false;
3784
- // Silly hack for Chrome, which always runs mousemove right after mousedown
3785
- setTimeout(function() {
3786
- allowmove = true;
3787
- }, 20);
3788
- })
3789
- .mouseup(function(evt) {
3790
- if (!sidedragging) toggleSidePanel();
3791
- sidedrag = -1;
3792
- sidedragging = false;
3793
- });
3794
-
3795
- $(window).mouseup(function() {
3796
- sidedrag = -1;
3797
- sidedragging = false;
3798
- $('#svg_editor').unbind('mousemove', resizePanel);
3799
- });
3800
-
3801
- // if width is non-zero, then fully close it, otherwise fully open it
3802
- // the optional close argument forces the side panel closed
3803
- var toggleSidePanel = function(close){
3804
- var w = parseInt($('#sidepanels').css('width'));
3805
- var deltax = (w > 2 || close ? 2 : SIDEPANEL_OPENWIDTH) - w;
3806
- var sidepanels = $('#sidepanels');
3807
- var layerpanel = $('#layerpanel');
3808
- var ruler_x = $('#ruler_x');
3809
- workarea.css('right', parseInt(workarea.css('right')) + deltax);
3810
- sidepanels.css('width', parseInt(sidepanels.css('width')) + deltax);
3811
- layerpanel.css('width', parseInt(layerpanel.css('width')) + deltax);
3812
- ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax);
3813
- };
3814
-
3815
- // this function highlights the layer passed in (by fading out the other layers)
3816
- // if no layer is passed in, this function restores the other layers
3817
- var toggleHighlightLayer = function(layerNameToHighlight) {
3818
- var curNames = new Array(svgCanvas.getCurrentDrawing().getNumLayers());
3819
- for (var i = 0; i < curNames.length; ++i) { curNames[i] = svgCanvas.getCurrentDrawing().getLayerName(i); }
3820
-
3821
- if (layerNameToHighlight) {
3822
- for (var i = 0; i < curNames.length; ++i) {
3823
- if (curNames[i] != layerNameToHighlight) {
3824
- svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 0.5);
3825
- }
3826
- }
3827
- }
3828
- else {
3829
- for (var i = 0; i < curNames.length; ++i) {
3830
- svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 1.0);
3831
- }
3832
- }
3833
- };
3834
-
3835
- var populateLayers = function(){
3836
- var layerlist = $('#layerlist tbody');
3837
- var selLayerNames = $('#selLayerNames');
3838
- layerlist.empty();
3839
- selLayerNames.empty();
3840
- var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName();
3841
- var layer = svgCanvas.getCurrentDrawing().getNumLayers();
3842
- var icon = $.getSvgIcon('eye');
3843
- // we get the layers in the reverse z-order (the layer rendered on top is listed first)
3844
- while (layer--) {
3845
- var name = svgCanvas.getCurrentDrawing().getLayerName(layer);
3846
- // contenteditable=\"true\"
3847
- var appendstr = "<tr class=\"layer";
3848
- if (name == currentLayerName) {
3849
- appendstr += " layersel"
3850
- }
3851
- appendstr += "\">";
3852
-
3853
- if (svgCanvas.getCurrentDrawing().getLayerVisibility(name)) {
3854
- appendstr += "<td class=\"layervis\"/><td class=\"layername\" >" + name + "</td></tr>";
3855
- }
3856
- else {
3857
- appendstr += "<td class=\"layervis layerinvis\"/><td class=\"layername\" >" + name + "</td></tr>";
3858
- }
3859
- layerlist.append(appendstr);
3860
- selLayerNames.append("<option value=\"" + name + "\">" + name + "</option>");
3861
- }
3862
- if(icon !== undefined) {
3863
- var copy = icon.clone();
3864
- $('td.layervis',layerlist).append(icon.clone());
3865
- $.resizeSvgIcons({'td.layervis .svg_icon':14});
3866
- }
3867
- // handle selection of layer
3868
- $('#layerlist td.layername')
3869
- .mouseup(function(evt){
3870
- $('#layerlist tr.layer').removeClass("layersel");
3871
- var row = $(this.parentNode);
3872
- row.addClass("layersel");
3873
- svgCanvas.setCurrentLayer(this.textContent);
3874
- evt.preventDefault();
3875
- })
3876
- .mouseover(function(evt){
3877
- $(this).css({"font-style": "italic", "color":"blue"});
3878
- toggleHighlightLayer(this.textContent);
3879
- })
3880
- .mouseout(function(evt){
3881
- $(this).css({"font-style": "normal", "color":"black"});
3882
- toggleHighlightLayer();
3883
- });
3884
- $('#layerlist td.layervis').click(function(evt){
3885
- var row = $(this.parentNode).prevAll().length;
3886
- var name = $('#layerlist tr.layer:eq(' + row + ') td.layername').text();
3887
- var vis = $(this).hasClass('layerinvis');
3888
- svgCanvas.setLayerVisibility(name, vis);
3889
- if (vis) {
3890
- $(this).removeClass('layerinvis');
3891
- }
3892
- else {
3893
- $(this).addClass('layerinvis');
3894
- }
3895
- });
3896
-
3897
- // if there were too few rows, let's add a few to make it not so lonely
3898
- var num = 5 - $('#layerlist tr.layer').size();
3899
- while (num-- > 0) {
3900
- // FIXME: there must a better way to do this
3901
- layerlist.append("<tr><td style=\"color:white\">_</td><td/></tr>");
3902
- }
3903
- };
3904
- populateLayers();
3905
-
3906
- // function changeResolution(x,y) {
3907
- // var zoom = svgCanvas.getResolution().zoom;
3908
- // setResolution(x * zoom, y * zoom);
3909
- // }
3910
-
3911
- var centerCanvas = function() {
3912
- // this centers the canvas vertically in the workarea (horizontal handled in CSS)
3913
- workarea.css('line-height', workarea.height() + 'px');
3914
- };
3915
-
3916
- $(window).bind('load resize', centerCanvas);
3917
-
3918
- function stepFontSize(elem, step) {
3919
- var orig_val = elem.value-0;
3920
- var sug_val = orig_val + step;
3921
- var increasing = sug_val >= orig_val;
3922
- if(step === 0) return orig_val;
3923
-
3924
- if(orig_val >= 24) {
3925
- if(increasing) {
3926
- return Math.round(orig_val * 1.1);
3927
- } else {
3928
- return Math.round(orig_val / 1.1);
3929
- }
3930
- } else if(orig_val <= 1) {
3931
- if(increasing) {
3932
- return orig_val * 2;
3933
- } else {
3934
- return orig_val / 2;
3935
- }
3936
- } else {
3937
- return sug_val;
3938
- }
3939
- }
3940
-
3941
- function stepZoom(elem, step) {
3942
- var orig_val = elem.value-0;
3943
- if(orig_val === 0) return 100;
3944
- var sug_val = orig_val + step;
3945
- if(step === 0) return orig_val;
3946
-
3947
- if(orig_val >= 100) {
3948
- return sug_val;
3949
- } else {
3950
- if(sug_val >= orig_val) {
3951
- return orig_val * 2;
3952
- } else {
3953
- return orig_val / 2;
3954
- }
3955
- }
3956
- }
3957
-
3958
- // function setResolution(w, h, center) {
3959
- // updateCanvas();
3960
- // // w-=0; h-=0;
3961
- // // $('#svgcanvas').css( { 'width': w, 'height': h } );
3962
- // // $('#canvas_width').val(w);
3963
- // // $('#canvas_height').val(h);
3964
- // //
3965
- // // if(center) {
3966
- // // var w_area = workarea;
3967
- // // var scroll_y = h/2 - w_area.height()/2;
3968
- // // var scroll_x = w/2 - w_area.width()/2;
3969
- // // w_area[0].scrollTop = scroll_y;
3970
- // // w_area[0].scrollLeft = scroll_x;
3971
- // // }
3972
- // }
3973
-
3974
- $('#resolution').change(function(){
3975
- var wh = $('#canvas_width,#canvas_height');
3976
- if(!this.selectedIndex) {
3977
- if($('#canvas_width').val() == 'fit') {
3978
- wh.removeAttr("disabled").val(100);
3979
- }
3980
- } else if(this.value == 'content') {
3981
- wh.val('fit').attr("disabled","disabled");
3982
- } else {
3983
- var dims = this.value.split('x');
3984
- $('#canvas_width').val(dims[0]);
3985
- $('#canvas_height').val(dims[1]);
3986
- wh.removeAttr("disabled");
3987
- }
3988
- });
3989
-
3990
- //Prevent browser from erroneously repopulating fields
3991
- $('input,select').attr("autocomplete","off");
3992
-
3993
- // Associate all button actions as well as non-button keyboard shortcuts
3994
- var Actions = function() {
3995
- // sel:'selector', fn:function, evt:'event', key:[key, preventDefault, NoDisableInInput]
3996
- var tool_buttons = [
3997
- {sel:'#tool_select', fn: clickSelect, evt: 'click', key: ['V', true]},
3998
- {sel:'#tool_fhpath', fn: clickFHPath, evt: 'click', key: ['Q', true]},
3999
- {sel:'#tool_line', fn: clickLine, evt: 'click', key: ['L', true]},
4000
- {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: ['R', true], parent: '#tools_rect', icon: 'rect'},
4001
- {sel:'#tool_square', fn: clickSquare, evt: 'mouseup', parent: '#tools_rect', icon: 'square'},
4002
- {sel:'#tool_fhrect', fn: clickFHRect, evt: 'mouseup', parent: '#tools_rect', icon: 'fh_rect'},
4003
- {sel:'#tool_ellipse', fn: clickEllipse, evt: 'mouseup', key: ['E', true], parent: '#tools_ellipse', icon: 'ellipse'},
4004
- {sel:'#tool_circle', fn: clickCircle, evt: 'mouseup', parent: '#tools_ellipse', icon: 'circle'},
4005
- {sel:'#tool_fhellipse', fn: clickFHEllipse, evt: 'mouseup', parent: '#tools_ellipse', icon: 'fh_ellipse'},
4006
- {sel:'#tool_path', fn: clickPath, evt: 'click', key: ['P', true]},
4007
- {sel:'#tool_text', fn: clickText, evt: 'click', key: ['T', true]},
4008
- {sel:'#tool_image', fn: clickImage, evt: 'mouseup'},
4009
- {sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: ['Z', true]},
4010
- {sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: ['N', true]},
4011
- {sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: ['S', true]},
4012
- {sel:'#tool_export', fn: clickExport, evt: 'mouseup'},
4013
- {sel:'#tool_open', fn: clickOpen, evt: 'mouseup', key: ['O', true]},
4014
- {sel:'#tool_import', fn: clickImport, evt: 'mouseup'},
4015
- {sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: ['U', true]},
4016
- {sel:'#tool_wireframe', fn: clickWireframe, evt: 'click', key: ['F', true]},
4017
- {sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true},
4018
- {sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'},
4019
- {sel:'#tool_docprops_save', fn: saveDocProperties, evt: 'click'},
4020
- {sel:'#tool_docprops', fn: showDocProperties, evt: 'mouseup'},
4021
- {sel:'#tool_prefs_save', fn: savePreferences, evt: 'click'},
4022
- {sel:'#tool_prefs_option', fn: function() {showPreferences();return false}, evt: 'mouseup'},
4023
- {sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]},
4024
- {sel:'#tool_reorient', fn: reorientPath, evt: 'click'},
4025
- {sel:'#tool_node_link', fn: linkControlPoints, evt: 'click'},
4026
- {sel:'#tool_node_clone', fn: clonePathNode, evt: 'click'},
4027
- {sel:'#tool_node_delete', fn: deletePathNode, evt: 'click'},
4028
- {sel:'#tool_openclose_path', fn: opencloseSubPath, evt: 'click'},
4029
- {sel:'#tool_add_subpath', fn: addSubPath, evt: 'click'},
4030
- {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: 'ctrl+shift+]'},
4031
- {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: 'ctrl+shift+['},
4032
- {sel:'#tool_topath', fn: convertToPath, evt: 'click'},
4033
- {sel:'#tool_make_link,#tool_make_link_multi', fn: makeHyperlink, evt: 'click'},
4034
- {sel:'#tool_undo', fn: clickUndo, evt: 'click', key: ['Z', true]},
4035
- {sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['Y', true]},
4036
- {sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: ['D', true]},
4037
- {sel:'#tool_group', fn: clickGroup, evt: 'click', key: ['G', true]},
4038
- {sel:'#tool_ungroup', fn: clickGroup, evt: 'click'},
4039
- {sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'},
4040
- {sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'},
4041
- // these two lines are required to make Opera work properly with the flyout mechanism
4042
- // {sel:'#tools_rect_show', fn: clickRect, evt: 'click'},
4043
- // {sel:'#tools_ellipse_show', fn: clickEllipse, evt: 'click'},
4044
- {sel:'#tool_bold', fn: clickBold, evt: 'mousedown'},
4045
- {sel:'#tool_italic', fn: clickItalic, evt: 'mousedown'},
4046
- {sel:'#sidepanel_handle', fn: toggleSidePanel, key: ['X']},
4047
- {sel:'#copy_save_done', fn: cancelOverlays, evt: 'click'},
4048
-
4049
- // Shortcuts not associated with buttons
4050
-
4051
- {key: 'ctrl+left', fn: function(){rotateSelected(0,1)}},
4052
- {key: 'ctrl+right', fn: function(){rotateSelected(1,1)}},
4053
- {key: 'ctrl+shift+left', fn: function(){rotateSelected(0,5)}},
4054
- {key: 'ctrl+shift+right', fn: function(){rotateSelected(1,5)}},
4055
- {key: 'shift+O', fn: selectPrev},
4056
- {key: 'shift+P', fn: selectNext},
4057
- {key: [modKey+'up', true], fn: function(){zoomImage(2);}},
4058
- {key: [modKey+'down', true], fn: function(){zoomImage(.5);}},
4059
- {key: [modKey+']', true], fn: function(){moveUpDownSelected('Up');}},
4060
- {key: [modKey+'[', true], fn: function(){moveUpDownSelected('Down');}},
4061
- {key: ['up', true], fn: function(){moveSelected(0,-1);}},
4062
- {key: ['down', true], fn: function(){moveSelected(0,1);}},
4063
- {key: ['left', true], fn: function(){moveSelected(-1,0);}},
4064
- {key: ['right', true], fn: function(){moveSelected(1,0);}},
4065
- {key: 'shift+up', fn: function(){moveSelected(0,-10)}},
4066
- {key: 'shift+down', fn: function(){moveSelected(0,10)}},
4067
- {key: 'shift+left', fn: function(){moveSelected(-10,0)}},
4068
- {key: 'shift+right', fn: function(){moveSelected(10,0)}},
4069
- {key: ['alt+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-1)}},
4070
- {key: ['alt+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,1)}},
4071
- {key: ['alt+left', true], fn: function(){svgCanvas.cloneSelectedElements(-1,0)}},
4072
- {key: ['alt+right', true], fn: function(){svgCanvas.cloneSelectedElements(1,0)}},
4073
- {key: ['alt+shift+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-10)}},
4074
- {key: ['alt+shift+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,10)}},
4075
- {key: ['alt+shift+left', true], fn: function(){svgCanvas.cloneSelectedElements(-10,0)}},
4076
- {key: ['alt+shift+right', true], fn: function(){svgCanvas.cloneSelectedElements(10,0)}},
4077
- {key: 'A', fn: function(){svgCanvas.selectAllInCurrentLayer();}},
4078
-
4079
- // Standard shortcuts
4080
- {key: modKey+'z', fn: clickUndo},
4081
- {key: modKey + 'shift+z', fn: clickRedo},
4082
- {key: modKey + 'y', fn: clickRedo},
4083
-
4084
- {key: modKey+'x', fn: cutSelected},
4085
- {key: modKey+'c', fn: copySelected},
4086
- {key: modKey+'v', fn: pasteInCenter}
4087
-
4088
-
4089
- ];
4090
-
4091
- // Tooltips not directly associated with a single function
4092
- var key_assocs = {
4093
- '4/Shift+4': '#tools_rect_show',
4094
- '5/Shift+5': '#tools_ellipse_show'
4095
- };
4096
-
4097
- return {
4098
- setAll: function() {
4099
- var flyouts = {};
4100
-
4101
- $.each(tool_buttons, function(i, opts) {
4102
- // Bind function to button
4103
- if(opts.sel) {
4104
- var btn = $(opts.sel);
4105
- if (btn.length == 0) return true; // Skip if markup does not exist
4106
- if(opts.evt) {
4107
- if (svgedit.browser.isTouch() && opts.evt === "click") opts.evt = "mousedown"
4108
- btn[opts.evt](opts.fn);
4109
- }
4110
-
4111
- // Add to parent flyout menu, if able to be displayed
4112
- if(opts.parent && $(opts.parent + '_show').length != 0) {
4113
- var f_h = $(opts.parent);
4114
- if(!f_h.length) {
4115
- f_h = makeFlyoutHolder(opts.parent.substr(1));
4116
- }
4117
-
4118
- f_h.append(btn);
4119
-
4120
- if(!$.isArray(flyouts[opts.parent])) {
4121
- flyouts[opts.parent] = [];
4122
- }
4123
- flyouts[opts.parent].push(opts);
4124
- }
4125
- }
4126
-
4127
-
4128
- // Bind function to shortcut key
4129
- if(opts.key) {
4130
- // Set shortcut based on options
4131
- var keyval, shortcut = '', disInInp = true, fn = opts.fn, pd = false;
4132
- if($.isArray(opts.key)) {
4133
- keyval = opts.key[0];
4134
- if(opts.key.length > 1) pd = opts.key[1];
4135
- if(opts.key.length > 2) disInInp = opts.key[2];
4136
- } else {
4137
- keyval = opts.key;
4138
- }
4139
- keyval += '';
4140
-
4141
- $.each(keyval.split('/'), function(i, key) {
4142
- $(document).bind('keydown', key, function(e) {
4143
- fn();
4144
- if(pd) {
4145
- e.preventDefault();
4146
- }
4147
- // Prevent default on ALL keys?
4148
- return false;
4149
- });
4150
- });
4151
-
4152
- // Put shortcut in title
4153
- if(opts.sel && !opts.hidekey && btn.attr('title')) {
4154
- var new_title = btn.attr('title').split('[')[0] + ' (' + keyval + ')';
4155
- key_assocs[keyval] = opts.sel;
4156
- // Disregard for menu items
4157
- if(!btn.parents('#main_menu').length) {
4158
- btn.attr('title', new_title);
4159
- }
4160
- }
4161
- }
4162
- });
4163
-
4164
- // Setup flyouts
4165
- setupFlyouts(flyouts);
4166
-
4167
-
4168
- // Misc additional actions
4169
-
4170
- // Make "return" keypress trigger the change event
4171
- $('.attr_changer, #image_url').bind('keydown', 'return',
4172
- function(evt) {$(this).change();evt.preventDefault();}
4173
- );
4174
-
4175
- $(window).bind('keydown', 'tab', function(e) {
4176
- if(ui_context === 'canvas') {
4177
- e.preventDefault();
4178
- selectNext();
4179
- }
4180
- }).bind('keydown', 'shift+tab', function(e) {
4181
- if(ui_context === 'canvas') {
4182
- e.preventDefault();
4183
- selectPrev();
4184
- }
4185
- });
4186
-
4187
- $('#tool_zoom').dblclick(dblclickZoom);
4188
- },
4189
- setTitles: function() {
4190
- $.each(key_assocs, function(keyval, sel) {
4191
- var menu = ($(sel).parents('#main_menu').length);
4192
-
4193
- $(sel).each(function() {
4194
- if(menu) {
4195
- var t = $(this).text().split(' [')[0];
4196
- } else {
4197
- var t = this.title.split(' [')[0];
4198
- }
4199
- var key_str = '';
4200
- // Shift+Up
4201
- $.each(keyval.split('/'), function(i, key) {
4202
- var mod_bits = key.split('+'), mod = '';
4203
- if(mod_bits.length > 1) {
4204
- mod = mod_bits[0] + '+';
4205
- key = mod_bits[1];
4206
- }
4207
- key_str += (i?'/':'') + mod + (uiStrings['key_'+key] || key);
4208
- });
4209
- if(menu) {
4210
- this.lastChild.textContent = t +' ['+key_str+']';
4211
- } else {
4212
- this.title = t +' ['+key_str+']';
4213
- }
4214
- });
4215
- });
4216
- },
4217
- getButtonData: function(sel) {
4218
- var b;
4219
- $.each(tool_buttons, function(i, btn) {
4220
- if(btn.sel === sel) b = btn;
4221
- });
4222
- return b;
4223
- }
4224
- };
4225
- }();
4226
-
4227
- Actions.setAll();
4228
-
4229
- // Select given tool
4230
- Editor.ready(function() {
4231
- var tool,
4232
- itool = curConfig.initTool,
4233
- container = $("#tools_left, #svg_editor .tools_flyout"),
4234
- pre_tool = container.find("#tool_" + itool),
4235
- reg_tool = container.find("#" + itool);
4236
- if(pre_tool.length) {
4237
- tool = pre_tool;
4238
- } else if(reg_tool.length){
4239
- tool = reg_tool;
4240
- } else {
4241
- tool = $("#tool_select");
4242
- }
4243
- tool.click().mouseup();
4244
-
4245
- if(curConfig.wireframe) {
4246
- $('#tool_wireframe').click();
4247
- }
4248
-
4249
- if(curConfig.showlayers) {
4250
- toggleSidePanel();
4251
- }
4252
-
4253
- $('#rulers').toggle(!!curConfig.showRulers);
4254
-
4255
- if (curConfig.showRulers) {
4256
- $('#show_rulers')[0].checked = true;
4257
- }
4258
-
4259
- if(curConfig.gridSnapping) {
4260
- $('#grid_snapping_on')[0].checked = true;
4261
- }
4262
-
4263
- if(curConfig.baseUnit) {
4264
- $('#base_unit').val(curConfig.baseUnit);
4265
- }
4266
-
4267
- if(curConfig.snappingStep) {
4268
- $('#grid_snapping_step').val(curConfig.snappingStep);
4269
- }
4270
- });
4271
-
4272
- $('#rect_rx').SpinButton({ min: 0, max: 1000, step: 1, callback: changeRectRadius });
4273
- $('#stroke_width').SpinButton({ min: 0, max: 99, step: 1, smallStep: 0.1, callback: changeStrokeWidth });
4274
- $('#angle').SpinButton({ min: -180, max: 180, step: 5, callback: changeRotationAngle });
4275
- $('#font_size').SpinButton({ step: 1, min: 0.001, stepfunc: stepFontSize, callback: changeFontSize });
4276
- $('#group_opacity').SpinButton({ step: 5, min: 0, max: 100, callback: changeOpacity });
4277
- $('#blur').SpinButton({ step: .1, min: 0, max: 10, callback: changeBlur });
4278
- $('#zoom').SpinButton({ min: 0.001, max: 10000, step: 50, stepfunc: stepZoom, callback: changeZoom })
4279
- // Set default zoom
4280
- .val(svgCanvas.getZoom() * 100);
4281
-
4282
- $("#workarea").contextMenu({
4283
- menu: 'cmenu_canvas',
4284
- inSpeed: 0
4285
- },
4286
- function(action, el, pos) {
4287
- switch ( action ) {
4288
- case 'delete':
4289
- deleteSelected();
4290
- break;
4291
- case 'cut':
4292
- cutSelected();
4293
- break;
4294
- case 'copy':
4295
- copySelected();
4296
- break;
4297
- case 'paste':
4298
- svgCanvas.pasteElements();
4299
- break;
4300
- case 'paste_in_place':
4301
- svgCanvas.pasteElements('in_place');
4302
- break;
4303
- case 'group':
4304
- svgCanvas.groupSelectedElements();
4305
- break;
4306
- case 'ungroup':
4307
- svgCanvas.ungroupSelectedElement();
4308
- break;
4309
- case 'move_front':
4310
- moveToTopSelected();
4311
- break;
4312
- case 'move_up':
4313
- moveUpDownSelected('Up');
4314
- break;
4315
- case 'move_down':
4316
- moveUpDownSelected('Down');
4317
- break;
4318
- case 'move_back':
4319
- moveToBottomSelected();
4320
- break;
4321
- default:
4322
- if(svgedit.contextmenu && svgedit.contextmenu.hasCustomHandler(action)){
4323
- svgedit.contextmenu.getCustomHandler(action).call();
4324
- }
4325
- break;
4326
- }
4327
-
4328
- if(svgCanvas.clipBoard.length) {
4329
- canv_menu.enableContextMenuItems('#paste,#paste_in_place');
4330
- }
4331
- });
4332
-
4333
- var lmenu_func = function(action, el, pos) {
4334
- switch ( action ) {
4335
- case 'dupe':
4336
- cloneLayer();
4337
- break;
4338
- case 'delete':
4339
- deleteLayer();
4340
- break;
4341
- case 'merge_down':
4342
- mergeLayer();
4343
- break;
4344
- case 'merge_all':
4345
- svgCanvas.mergeAllLayers();
4346
- updateContextPanel();
4347
- populateLayers();
4348
- break;
4349
- }
4350
- }
4351
-
4352
- $("#layerlist").contextMenu({
4353
- menu: 'cmenu_layers',
4354
- inSpeed: 0
4355
- },
4356
- lmenu_func
4357
- );
4358
-
4359
- $("#layer_moreopts").contextMenu({
4360
- menu: 'cmenu_layers',
4361
- inSpeed: 0,
4362
- allowLeft: true
4363
- },
4364
- lmenu_func
4365
- );
4366
-
4367
- $('.contextMenu li').mousedown(function(ev) {
4368
- ev.preventDefault();
4369
- })
4370
-
4371
- $('#cmenu_canvas li').disableContextMenu();
4372
- canv_menu.enableContextMenuItems('#delete,#cut,#copy');
4373
-
4374
- window.onbeforeunload = function() {
4375
-
4376
- if ('localStorage' in window) {
4377
- var name = 'svgedit-' + Editor.curConfig.canvasName;
4378
- window.localStorage.setItem(name, svgCanvas.getSvgString());
4379
- Editor.show_save_warning = false;
4380
- }
4381
-
4382
- // Suppress warning if page is empty
4383
- if(undoMgr.getUndoStackSize() === 0) {
4384
- Editor.show_save_warning = false;
4385
- }
4386
-
4387
- // show_save_warning is set to "false" when the page is saved.
4388
- if(!curConfig.no_save_warning && Editor.show_save_warning) {
4389
- // Browser already asks question about closing the page
4390
- return uiStrings.notification.unsavedChanges;
4391
- }
4392
- };
4393
-
4394
- Editor.openPrep = function(func) {
4395
- $('#main_menu').hide();
4396
- if(undoMgr.getUndoStackSize() === 0) {
4397
- func(true);
4398
- } else {
4399
- $.confirm(uiStrings.notification.QwantToOpen, func);
4400
- }
4401
- }
4402
-
4403
- // use HTML5 File API: http://www.w3.org/TR/FileAPI/
4404
- // if browser has HTML5 File API support, then we will show the open menu item
4405
- // and provide a file input to click. When that change event fires, it will
4406
- // get the text contents of the file and send it to the canvas
4407
- if (window.FileReader) {
4408
- var import_image = function(e) {
4409
- e.stopPropagation();
4410
- e.preventDefault();
4411
- $("#workarea").removeAttr("style");
4412
- $('#main_menu').hide();
4413
- var file = null;
4414
- if (e.type == "drop") file = e.dataTransfer.files[0]
4415
- else file = this.files[0];
4416
- if (file) {
4417
- if(file.type.indexOf("image") != -1) {
4418
- //detected an image
4419
- //svg handling
4420
- if(file.type.indexOf("svg") != -1) {
4421
- var reader = new FileReader();
4422
- reader.onloadend = function(e) {
4423
- svgCanvas.importSvgString(e.target.result, true);
4424
- svgCanvas.ungroupSelectedElement()
4425
- svgCanvas.ungroupSelectedElement()
4426
- svgCanvas.groupSelectedElements()
4427
- svgCanvas.alignSelectedElements("m", "page")
4428
- svgCanvas.alignSelectedElements("c", "page")
4429
- };
4430
- reader.readAsText(file);
4431
- }
4432
-
4433
- //bitmap handling
4434
- else {
4435
- var reader = new FileReader();
4436
- reader.onloadend = function(e) {
4437
- // let's insert the new image until we know its dimensions
4438
- insertNewImage = function(img_width, img_height){
4439
- var newImage = svgCanvas.addSvgElementFromJson({
4440
- "element": "image",
4441
- "attr": {
4442
- "x": 0,
4443
- "y": 0,
4444
- "width": img_width,
4445
- "height": img_height,
4446
- "id": svgCanvas.getNextId(),
4447
- "style": "pointer-events:inherit"
4448
- }
4449
- });
4450
- svgCanvas.setHref(newImage, e.target.result);
4451
- svgCanvas.selectOnly([newImage])
4452
- svgCanvas.alignSelectedElements("m", "page")
4453
- svgCanvas.alignSelectedElements("c", "page")
4454
- updateContextPanel();
4455
- }
4456
- // create dummy img so we know the default dimensions
4457
- var img_width = 100;
4458
- var img_height = 100;
4459
- var img = new Image();
4460
- img.src = e.target.result;
4461
- img.style.opacity = 0;
4462
- img.onload = function() {
4463
- img_width = img.offsetWidth
4464
- img_height = img.offsetHeight
4465
- insertNewImage(img_width, img_height);
4466
- }
4467
- };
4468
- reader.readAsDataURL(file)
4469
- }
4470
- }
4471
- }
4472
- }
4473
-
4474
- function onDragEnter(e) {
4475
- e.stopPropagation();
4476
- e.preventDefault();
4477
- // and indicator should be displayed here, such as "drop files here"
4478
- }
4479
-
4480
- function onDragOver(e) {
4481
- e.stopPropagation();
4482
- e.preventDefault();
4483
- }
4484
-
4485
- function onDragLeave(e) {
4486
- e.stopPropagation();
4487
- e.preventDefault();
4488
- // hypothetical indicator should be removed here
4489
- }
4490
-
4491
- workarea[0].addEventListener('dragenter', onDragEnter, false);
4492
- workarea[0].addEventListener('dragover', onDragOver, false);
4493
- workarea[0].addEventListener('dragleave', onDragLeave, false);
4494
- workarea[0].addEventListener('drop', import_image, false);
4495
-
4496
- var open = $('<input type="file">').change(function() {
4497
- var f = this;
4498
- Editor.openPrep(function(ok) {
4499
- if(!ok) return;
4500
- svgCanvas.clear();
4501
- if(f.files.length==1) {
4502
- var reader = new FileReader();
4503
- reader.onloadend = function(e) {
4504
- loadSvgString(e.target.result);
4505
- updateCanvas();
4506
- };
4507
- reader.readAsText(f.files[0]);
4508
- }
4509
- });
4510
- });
4511
- $("#tool_open").show().prepend(open);
4512
-
4513
- var img_import = $('<input type="file">').change(import_image);
4514
- $("#tool_import").show().prepend(img_import);
4515
- }
4516
-
4517
- var updateCanvas = Editor.updateCanvas = function(center, new_ctr) {
4518
-
4519
- var w = workarea.width(), h = workarea.height();
4520
- var w_orig = w, h_orig = h;
4521
- var zoom = svgCanvas.getZoom();
4522
- var w_area = workarea;
4523
- var cnvs = $("#svgcanvas");
4524
-
4525
- var old_ctr = {
4526
- x: w_area[0].scrollLeft + w_orig/2,
4527
- y: w_area[0].scrollTop + h_orig/2
4528
- };
4529
-
4530
- var multi = curConfig.canvas_expansion;
4531
- w = Math.max(w_orig, svgCanvas.contentW * zoom * multi);
4532
- h = Math.max(h_orig, svgCanvas.contentH * zoom * multi);
4533
-
4534
- if(w == w_orig && h == h_orig) {
4535
- workarea.css('overflow','hidden');
4536
- } else {
4537
- workarea.css('overflow','scroll');
4538
- }
4539
-
4540
- var old_can_y = cnvs.height()/2;
4541
- var old_can_x = cnvs.width()/2;
4542
- cnvs.width(w).height(h);
4543
- var new_can_y = h/2;
4544
- var new_can_x = w/2;
4545
- var offset = svgCanvas.updateCanvas(w, h);
4546
-
4547
- var ratio = new_can_x / old_can_x;
4548
-
4549
- var scroll_x = w/2 - w_orig/2;
4550
- var scroll_y = h/2 - h_orig/2;
4551
-
4552
- if(!new_ctr) {
4553
-
4554
- var old_dist_x = old_ctr.x - old_can_x;
4555
- var new_x = new_can_x + old_dist_x * ratio;
4556
-
4557
- var old_dist_y = old_ctr.y - old_can_y;
4558
- var new_y = new_can_y + old_dist_y * ratio;
4559
-
4560
- new_ctr = {
4561
- x: new_x,
4562
- y: new_y
4563
- };
4564
-
4565
- } else {
4566
- new_ctr.x += offset.x,
4567
- new_ctr.y += offset.y;
4568
- }
4569
-
4570
- if(center) {
4571
- // Go to top-left for larger documents
4572
- if(svgCanvas.contentW > w_area.width()) {
4573
- // Top-left
4574
- workarea[0].scrollLeft = offset.x - 10;
4575
- workarea[0].scrollTop = offset.y - 10;
4576
- } else {
4577
- // Center
4578
- w_area[0].scrollLeft = scroll_x;
4579
- w_area[0].scrollTop = scroll_y;
4580
- }
4581
- } else {
4582
- w_area[0].scrollLeft = new_ctr.x - w_orig/2;
4583
- w_area[0].scrollTop = new_ctr.y - h_orig/2;
4584
- }
4585
- if(curConfig.showRulers) {
4586
- updateRulers(cnvs, zoom);
4587
- workarea.scroll();
4588
- }
4589
- }
4590
-
4591
- // Make [1,2,5] array
4592
- var r_intervals = [];
4593
- for(var i = .1; i < 1E5; i *= 10) {
4594
- r_intervals.push(1 * i);
4595
- r_intervals.push(2 * i);
4596
- r_intervals.push(5 * i);
4597
- }
4598
-
4599
- function updateRulers(scanvas, zoom) {
4600
- if(!zoom) zoom = svgCanvas.getZoom();
4601
- if(!scanvas) scanvas = $("#svgcanvas");
4602
-
4603
- var limit = 30000;
4604
-
4605
- var c_elem = svgCanvas.getContentElem();
4606
-
4607
- var units = svgedit.units.getTypeMap();
4608
- var unit = units[curConfig.baseUnit]; // 1 = 1px
4609
-
4610
- for(var d = 0; d < 2; d++) {
4611
- var is_x = (d === 0);
4612
- var dim = is_x ? 'x' : 'y';
4613
- var lentype = is_x?'width':'height';
4614
- var content_d = c_elem.getAttribute(dim)-0;
4615
-
4616
- var $hcanv_orig = $('#ruler_' + dim + ' canvas:first');
4617
-
4618
- // Bit of a hack to fully clear the canvas in Safari & IE9
4619
- $hcanv = $hcanv_orig.clone();
4620
- $hcanv_orig.replaceWith($hcanv);
4621
-
4622
- var hcanv = $hcanv[0];
4623
-
4624
- // Set the canvas size to the width of the container
4625
- var ruler_len = scanvas[lentype]();
4626
- var total_len = ruler_len;
4627
- hcanv.parentNode.style[lentype] = total_len + 'px';
4628
-
4629
-
4630
- var canv_count = 1;
4631
- var ctx_num = 0;
4632
- var ctx_arr;
4633
- var ctx = hcanv.getContext("2d");
4634
-
4635
- ctx.fillStyle = "rgb(200,0,0)";
4636
- ctx.fillRect(0,0,hcanv.width,hcanv.height);
4637
-
4638
- // Remove any existing canvasses
4639
- $hcanv.siblings().remove();
4640
-
4641
- // Create multiple canvases when necessary (due to browser limits)
4642
- if(ruler_len >= limit) {
4643
- var num = parseInt(ruler_len / limit) + 1;
4644
- ctx_arr = Array(num);
4645
- ctx_arr[0] = ctx;
4646
- for(var i = 1; i < num; i++) {
4647
- hcanv[lentype] = limit;
4648
- var copy = hcanv.cloneNode(true);
4649
- hcanv.parentNode.appendChild(copy);
4650
- ctx_arr[i] = copy.getContext('2d');
4651
- }
4652
-
4653
- copy[lentype] = ruler_len % limit;
4654
-
4655
- // set copy width to last
4656
- ruler_len = limit;
4657
- }
4658
-
4659
- hcanv[lentype] = ruler_len;
4660
-
4661
- var u_multi = unit * zoom;
4662
-
4663
- // Calculate the main number interval
4664
- var raw_m = 50 / u_multi;
4665
- var multi = 1;
4666
- for(var i = 0; i < r_intervals.length; i++) {
4667
- var num = r_intervals[i];
4668
- multi = num;
4669
- if(raw_m <= num) {
4670
- break;
4671
- }
4672
- }
4673
-
4674
- var big_int = multi * u_multi;
4675
-
4676
- ctx.font = "9px sans-serif";
4677
-
4678
- var ruler_d = ((content_d / u_multi) % multi) * u_multi;
4679
- var label_pos = ruler_d - big_int;
4680
- for (; ruler_d < total_len; ruler_d += big_int) {
4681
- label_pos += big_int;
4682
- var real_d = ruler_d - content_d;
4683
-
4684
- var cur_d = Math.round(ruler_d) + .5;
4685
- if(is_x) {
4686
- ctx.moveTo(cur_d, 15);
4687
- ctx.lineTo(cur_d, 0);
4688
- } else {
4689
- ctx.moveTo(15, cur_d);
4690
- ctx.lineTo(0, cur_d);
4691
- }
4692
-
4693
- var num = (label_pos - content_d) / u_multi;
4694
- var label;
4695
- if(multi >= 1) {
4696
- label = Math.round(num);
4697
- } else {
4698
- var decs = (multi+'').split('.')[1].length;
4699
- label = num.toFixed(decs)-0;
4700
- }
4701
-
4702
- // Do anything special for negative numbers?
4703
- // var is_neg = label < 0;
4704
- // real_d2 = Math.abs(real_d2);
4705
-
4706
- // Change 1000s to Ks
4707
- if(label !== 0 && label !== 1000 && label % 1000 === 0) {
4708
- label = (label / 1000) + 'K';
4709
- }
4710
-
4711
- if(is_x) {
4712
- ctx.fillText(label, ruler_d+2, 8);
4713
- } else {
4714
- var str = (label+'').split('');
4715
- for(var i = 0; i < str.length; i++) {
4716
- ctx.fillText(str[i], 1, (ruler_d+9) + i*9);
4717
- }
4718
- }
4719
-
4720
- var part = big_int / 10;
4721
- for(var i = 1; i < 10; i++) {
4722
- var sub_d = Math.round(ruler_d + part * i) + .5;
4723
- if(ctx_arr && sub_d > ruler_len) {
4724
- ctx_num++;
4725
- ctx.stroke();
4726
- if(ctx_num >= ctx_arr.length) {
4727
- i = 10;
4728
- ruler_d = total_len;
4729
- continue;
4730
- }
4731
- ctx = ctx_arr[ctx_num];
4732
- ruler_d -= limit;
4733
- sub_d = Math.round(ruler_d + part * i) + .5;
4734
- }
4735
-
4736
- var line_num = (i % 2)?12:10;
4737
- if(is_x) {
4738
- ctx.moveTo(sub_d, 15);
4739
- ctx.lineTo(sub_d, line_num);
4740
- } else {
4741
- ctx.moveTo(15, sub_d);
4742
- ctx.lineTo(line_num ,sub_d);
4743
- }
4744
- }
4745
- }
4746
-
4747
- // console.log('ctx', ctx);
4748
- ctx.strokeStyle = "#000";
4749
- ctx.stroke();
4750
- }
4751
- }
4752
-
4753
- // $(function() {
4754
- updateCanvas(true);
4755
- // });
4756
-
4757
- // var revnums = "svg-editor.js ($Rev: 2277 $) ";
4758
- // revnums += svgCanvas.getVersion();
4759
- // $('#copyright')[0].setAttribute("title", revnums);
4760
-
4761
- // Callback handler for embedapi.js
4762
- try{
4763
- var json_encode = function(obj){
4764
- //simple partial JSON encoder implementation
4765
- if(window.JSON && JSON.stringify) return JSON.stringify(obj);
4766
- var enc = arguments.callee; //for purposes of recursion
4767
- if(typeof obj == "boolean" || typeof obj == "number"){
4768
- return obj+'' //should work...
4769
- }else if(typeof obj == "string"){
4770
- //a large portion of this is stolen from Douglas Crockford's json2.js
4771
- return '"'+
4772
- obj.replace(
4773
- /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g
4774
- , function (a) {
4775
- return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
4776
- })
4777
- +'"'; //note that this isn't quite as purtyful as the usualness
4778
- }else if(obj.length){ //simple hackish test for arrayish-ness
4779
- for(var i = 0; i < obj.length; i++){
4780
- obj[i] = enc(obj[i]); //encode every sub-thingy on top
4781
- }
4782
- return "["+obj.join(",")+"]";
4783
- }else{
4784
- var pairs = []; //pairs will be stored here
4785
- for(var k in obj){ //loop through thingys
4786
- pairs.push(enc(k)+":"+enc(obj[k])); //key: value
4787
- }
4788
- return "{"+pairs.join(",")+"}" //wrap in the braces
4789
- }
4790
- }
4791
- window.addEventListener("message", function(e){
4792
- var cbid = parseInt(e.data.substr(0, e.data.indexOf(";")));
4793
- try{
4794
- e.source.postMessage("SVGe"+cbid+";"+json_encode(eval(e.data)), "*");
4795
- }catch(err){
4796
- e.source.postMessage("SVGe"+cbid+";error:"+err.message, "*");
4797
- }
4798
- }, false)
4799
- }catch(err){
4800
- window.embed_error = err;
4801
- }
4802
-
4803
-
4804
-
4805
- // For Compatibility with older extensions
4806
- $(function() {
4807
- window.svgCanvas = svgCanvas;
4808
- svgCanvas.ready = svgEditor.ready;
4809
- });
4810
-
4811
-
4812
- Editor.setLang = function(lang, allStrings) {
4813
- $.pref('lang', lang);
4814
- $('#lang_select').val(lang);
4815
- if(allStrings) {
4816
-
4817
- var notif = allStrings.notification;
4818
-
4819
-
4820
-
4821
- // $.extend will only replace the given strings
4822
- var oldLayerName = $('#layerlist tr.layersel td.layername').text();
4823
- var rename_layer = (oldLayerName == uiStrings.common.layer + ' 1');
4824
-
4825
- $.extend(uiStrings, allStrings);
4826
- svgCanvas.setUiStrings(allStrings);
4827
- Actions.setTitles();
4828
-
4829
- if(rename_layer) {
4830
- svgCanvas.renameCurrentLayer(uiStrings.common.layer + ' 1');
4831
- populateLayers();
4832
- }
4833
-
4834
- svgCanvas.runExtensions("langChanged", lang);
4835
-
4836
- // Update flyout tooltips
4837
- setFlyoutTitles();
4838
-
4839
- // Copy title for certain tool elements
4840
- var elems = {
4841
- '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block',
4842
- '#fill_color': '#tool_fill label, #tool_fill .color_block',
4843
- '#linejoin_miter': '#cur_linejoin',
4844
- '#linecap_butt': '#cur_linecap'
4845
- }
4846
-
4847
- $.each(elems, function(source, dest) {
4848
- $(dest).attr('title', $(source)[0].title);
4849
- });
4850
-
4851
- // Copy alignment titles
4852
- $('#multiselected_panel div[id^=tool_align]').each(function() {
4853
- $('#tool_pos' + this.id.substr(10))[0].title = this.title;
4854
- });
4855
-
4856
- }
4857
- };
4858
- };
4859
-
4860
- var callbacks = [];
4861
-
4862
- function loadSvgString(str, callback) {
4863
- var success = svgCanvas.setSvgString(str) !== false;
4864
- callback = callback || $.noop;
4865
- if(success) {
4866
- callback(true);
4867
- } else {
4868
- $.alert(uiStrings.notification.errorLoadingSVG, function() {
4869
- callback(false);
4870
- });
4871
- }
4872
- }
4873
-
4874
- Editor.ready = function(cb) {
4875
- if(!is_ready) {
4876
- callbacks.push(cb);
4877
- } else {
4878
- cb();
4879
- }
4880
- };
4881
-
4882
- Editor.runCallbacks = function() {
4883
- $.each(callbacks, function() {
4884
- this();
4885
- });
4886
- is_ready = true;
4887
- };
4888
-
4889
- Editor.loadFromString = function(str) {
4890
- Editor.ready(function() {
4891
- loadSvgString(str);
4892
- });
4893
- };
4894
-
4895
- Editor.disableUI = function(featList) {
4896
- // $(function() {
4897
- // $('#tool_wireframe, #tool_image, #main_button, #tool_source, #sidepanels').remove();
4898
- // $('#tools_top').css('left', 5);
4899
- // });
4900
- };
4901
-
4902
- Editor.loadFromURL = function(url, opts) {
4903
- if(!opts) opts = {};
4904
-
4905
- var cache = opts.cache;
4906
- var cb = opts.callback;
4907
-
4908
- Editor.ready(function() {
4909
- $.ajax({
4910
- 'url': url,
4911
- 'dataType': 'text',
4912
- cache: !!cache,
4913
- success: function(str) {
4914
- loadSvgString(str, cb);
4915
- },
4916
- error: function(xhr, stat, err) {
4917
- if(xhr.status != 404 && xhr.responseText) {
4918
- loadSvgString(xhr.responseText, cb);
4919
- } else {
4920
- $.alert(uiStrings.notification.URLloadFail + ": \n"+err+'', cb);
4921
- }
4922
- }
4923
- });
4924
- });
4925
- };
4926
-
4927
- Editor.loadFromDataURI = function(str) {
4928
- Editor.ready(function() {
4929
- var pre = 'data:image/svg+xml;base64,';
4930
- var src = str.substring(pre.length);
4931
- loadSvgString(svgedit.utilities.decode64(src));
4932
- });
4933
- };
4934
-
4935
- Editor.addExtension = function() {
4936
- var args = arguments;
4937
-
4938
- // Note that we don't want this on Editor.ready since some extensions
4939
- // may want to run before then (like server_opensave).
4940
- $(function() {
4941
- if(svgCanvas) svgCanvas.addExtension.apply(this, args);
4942
- });
4943
- };
4944
-
4945
- return Editor;
4946
- }(jQuery);
4947
-
4948
- // Run init once DOM is loaded
4949
- $(svgEditor.init);
4950
-
4951
- })();
4952
-
4953
- // ?iconsize=s&bkgd_color=555
4954
-
4955
- // svgEditor.setConfig({
4956
- // // imgPath: 'foo',
4957
- // dimensions: [800, 600],
4958
- // canvas_expansion: 5,
4959
- // initStroke: {
4960
- // color: '0000FF',
4961
- // width: 3.5,
4962
- // opacity: .5
4963
- // },
4964
- // initFill: {
4965
- // color: '550000',
4966
- // opacity: .75
4967
- // },
4968
- // extensions: ['ext-helloworld.js']
4969
- // })