diff --git a/editor/svg-editor.js b/editor/svg-editor.js index 25b8c414..b03458b2 100644 --- a/editor/svg-editor.js +++ b/editor/svg-editor.js @@ -1,5 +1,5 @@ -/*globals globalStorage, widget, svgEditor, svgedit, canvg */ -/*jslint vars: true, eqeq: true, todo: true */ +/*globals globalStorage, widget, svgEditor, svgedit, canvg, DOMParser, FileReader, jQuery, $ */ +/*jslint vars: true, eqeq: true, todo: true, forin: true, continue: true, regexp: true */ /* * svg-editor.js * @@ -17,12 +17,12 @@ // 2) browser.js // 3) svgcanvas.js -(function() { +(function() {'use strict'; if (window.svgEditor) { return; } - window.svgEditor = function($) { + window.svgEditor = (function($) { var svgCanvas, Editor = {}, isReady = false, @@ -115,6 +115,18 @@ }, customHandlers = {}; + function loadSvgString(str, callback) { + var success = svgCanvas.setSvgString(str) !== false; + callback = callback || $.noop; + if (success) { + callback(true); + } else { + $.alert(uiStrings.notification.errorLoadingSVG, function() { + callback(false); + }); + } + } + Editor.curConfig = curConfig; Editor.tool_scale = 1; @@ -169,7 +181,7 @@ Editor.setConfig = function(opts) { $.each(opts, function(key, val) { // Only allow prefs defined in defaultPrefs - if (key in defaultPrefs) { + if (defaultPrefs[key]) { $.pref(key, val); } }); @@ -652,8 +664,16 @@ var preferences = false; var cur_context = ''; var origTitle = $('title:first').text(); + // Make [1,2,5] array + var r_intervals = []; + var i; + for (i = 0.1; i < 1E5; i *= 10) { + r_intervals.push(i); + r_intervals.push(2 * i); + r_intervals.push(5 * i); + } - // this function highlights the layer passed in (by fading out the other layers) + // This function highlights the layer passed in (by fading out the other layers) // if no layer is passed in, this function restores the other layers var toggleHighlightLayer = function(layerNameToHighlight) { var i, curNames = new Array(svgCanvas.getCurrentDrawing().getNumLayers()); @@ -831,704 +851,379 @@ }}); }; - // called when we've selected a different element - var selectedChanged = function(window, elems) { - var mode = svgCanvas.getMode(); - if (mode === 'select') { - setSelectMode(); - } - var is_node = (mode == "pathedit"); - // if elems[1] is present, then we have more than one element - selectedElement = (elems.length === 1 || elems[1] == null ? elems[0] : null); - multiselected = (elems.length >= 2 && elems[1] != null); - if (selectedElement != null) { - // unless we're already in always set the mode of the editor to select because - // upon creation of a text element the editor is switched into - // select mode and this event fires - we need our UI to be in sync - - if (!is_node) { - updateToolbar(); - } - } // if (elem != null) - - // Deal with pathedit mode - togglePathEditMode(is_node, elems); - updateContextPanel(); - svgCanvas.runExtensions('selectedChanged', { - elems: elems, - selectedElement: selectedElement, - multiselected: multiselected - }); - }; - - // Call when part of element is in process of changing, generally - // on mousemove actions like rotate, move, etc. - var elementTransition = function(window, elems) { - var mode = svgCanvas.getMode(); - var elem = elems[0]; - - if (!elem) { + var operaRepaint = function() { + // Repaints canvas in Opera. Needed for stroke-dasharray change as well as fill change + if (!window.opera) { return; } - - multiselected = (elems.length >= 2 && elems[1] != null); - // Only updating fields for single elements for now - if (!multiselected) { - switch (mode) { - case 'rotate': - var ang = svgCanvas.getRotationAngle(elem); - $('#angle').val(ang); - $('#tool_reorient').toggleClass('disabled', ang === 0); - break; - - // TODO: Update values that change on move/resize, etc -// case "select": -// case "resize": -// break; - } - } - svgCanvas.runExtensions('elementTransition', { - elems: elems - }); + $('
').hide().appendTo('body').remove(); }; - // called when any element has changed - var elementChanged = function(window, elems) { - var i, - mode = svgCanvas.getMode(); - if (mode === 'select') { - setSelectMode(); + function setStrokeOpt(opt, changeElem) { + var id = opt.id; + var bits = id.split('_'); + var pre = bits[0]; + var val = bits[1]; + + if (changeElem) { + svgCanvas.setStrokeAttr('stroke-' + pre, val); } + operaRepaint(); + setIcon('#cur_' + pre , id, 20); + $(opt).addClass('current').siblings().removeClass('current'); + } - for (i = 0; i < elems.length; ++i) { - var elem = elems[i]; - - // if the element changed was the svg, then it could be a resolution change - if (elem && elem.tagName === 'svg') { - populateLayers(); - updateCanvas(); - } - // Update selectedElement if element is no longer part of the image. - // This occurs for the text elements in Firefox - else if (elem && selectedElement && selectedElement.parentNode == null) { -// || elem && elem.tagName == "path" && !multiselected) { // This was added in r1430, but not sure why - selectedElement = elem; - } + // This is a common function used when a tool has been clicked (chosen) + // It does several common things: + // - removes the tool_button_current class from whatever tool currently has it + // - hides any flyouts + // - adds the tool_button_current class to the button passed in + var toolButtonClick = function(button, noHiding) { + if ($(button).hasClass('disabled')) {return false;} + if ($(button).parent().hasClass('tools_flyout')) {return true;} + var fadeFlyouts = 'normal'; + if (!noHiding) { + $('.tools_flyout').fadeOut(fadeFlyouts); } - - Editor.showSaveWarning = true; - - // we update the contextual panel with potentially new - // positional/sizing information (we DON'T want to update the - // toolbar here as that creates an infinite loop) - // also this updates the history buttons - - // we tell it to skip focusing the text control if the - // text element was previously in focus - updateContextPanel(); - - // In the event a gradient was flipped: - if (selectedElement && mode === 'select') { - paintBox.fill.update(); - paintBox.stroke.update(); - } - - svgCanvas.runExtensions('elementChanged', { - elems: elems - }); + $('#styleoverrides').text(''); + workarea.css('cursor', 'auto'); + $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); + $(button).addClass('tool_button_current').removeClass('tool_button'); + return true; }; - var zoomChanged = svgCanvas.zoomChanged = function(window, bbox, autoCenter) { - var scrbar = 15, - res = svgCanvas.getResolution(), - w_area = workarea, - canvas_pos = $('#svgcanvas').position(); - var z_info = svgCanvas.setBBoxZoom(bbox, w_area.width()-scrbar, w_area.height()-scrbar); - if (!z_info) {return;} - var zoomlevel = z_info.zoom, - bb = z_info.bbox; - - if (zoomlevel < 0.001) { - changeZoom({value: 0.1}); - return; + var clickSelect = function() { + if (toolButtonClick('#tool_select')) { + svgCanvas.setMode('select'); + $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}'); } + }; - $('#zoom').val((zoomlevel*100).toFixed(1)); + var setImageURL = Editor.setImageURL = function(url) { + if (!url) { + url = defaultImageURL; + } + svgCanvas.setImageURL(url); + $('#image_url').val(url); - if (autoCenter) { - updateCanvas(); + if (url.indexOf('data:') === 0) { + // data URI found + $('#image_url').hide(); + $('#change_image_url').show(); } else { - updateCanvas(false, {x: bb.x * zoomlevel + (bb.width * zoomlevel)/2, y: bb.y * zoomlevel + (bb.height * zoomlevel)/2}); - } - - if (svgCanvas.getMode() == 'zoom' && bb.width) { - // Go to select if a zoom box was drawn - setSelectMode(); - } - - zoomDone(); - }; - - $('#cur_context_panel').delegate('a', 'click', function() { - var link = $(this); - if (link.attr('data-root')) { - svgCanvas.leaveContext(); - } else { - svgCanvas.setContext(link.text()); - } - svgCanvas.clearSelection(); - return false; - }); - - var contextChanged = function(win, context) { - var link_str = ''; - if (context) { - var str = ''; - link_str = '' + svgCanvas.getCurrentDrawing().getCurrentLayerName() + ''; - - $(context).parentsUntil('#svgcontent > g').andSelf().each(function() { - if (this.id) { - str += ' > ' + this.id; - if (this !== context) { - link_str += ' > ' + this.id + ''; - } else { - link_str += ' > ' + this.id; - } - } + // regular URL + svgCanvas.embedImage(url, function(dataURI) { + // Couldn't embed, so show warning + $('#url_notice').toggle(!dataURI); + defaultImageURL = url; }); - - cur_context = str; - } else { - cur_context = null; + $('#image_url').show(); + $('#change_image_url').hide(); } - $('#cur_context_panel').toggle(!!context).html(link_str); - - updateTitle(); }; - // Makes sure the current selected paint is available to work with - var prepPaints = function() { - paintBox.fill.prep(); - paintBox.stroke.prep(); - }; + function setBackground(color, url) { + // if (color == curPrefs.bkgd_color && url == curPrefs.bkgd_url) return; + $.pref('bkgd_color', color); + $.pref('bkgd_url', url); - var flyout_funcs = {}; + // This should be done in svgcanvas.js for the borderRect fill + svgCanvas.setBackground(color, url); + } - var setupFlyouts = function(holders) { - $.each(holders, function(hold_sel, btn_opts) { - var buttons = $(hold_sel).children(); - var show_sel = hold_sel + '_show'; - var shower = $(show_sel); - var def = false; - buttons.addClass('tool_button') - .unbind('click mousedown mouseup') // may not be necessary - .each(function(i) { - // Get this buttons options - var opts = btn_opts[i]; - - // Remember the function that goes with this ID - flyout_funcs[opts.sel] = opts.fn; - - if (opts.isDefault) {def = i;} - - // Clicking the icon in flyout should set this set's icon - var func = function(event) { - var options = opts; - //find the currently selected tool if comes from keystroke - if (event.type === 'keydown') { - var flyoutIsSelected = $(options.parent + '_show').hasClass('tool_button_current'); - var currentOperation = $(options.parent + '_show').attr('data-curopt'); - $.each(holders[opts.parent], function(i, tool) { - if (tool.sel == currentOperation) { - if (!event.shiftKey || !flyoutIsSelected) { - options = tool; - } else { - options = holders[opts.parent][i+1] || holders[opts.parent][0]; - } - } - }); - } - if ($(this).hasClass('disabled')) {return false;} - if (toolButtonClick(show_sel)) { - options.fn(); - } - var icon; - if (options.icon) { - icon = $.getSvgIcon(options.icon, true); - } else { - icon = $(options.sel).children().eq(0).clone(); - } - - icon[0].setAttribute('width', shower.width()); - icon[0].setAttribute('height', shower.height()); - shower.children(':not(.flyout_arrow_horiz)').remove(); - shower.append(icon).attr('data-curopt', options.sel); // This sets the current mode - }; - - $(this).mouseup(func); - - if (opts.key) { - $(document).bind('keydown', opts.key[0] + ' shift+' + opts.key[0], func); - } - }); - - if (def) { - shower.attr('data-curopt', btn_opts[def].sel); - } else if (!shower.attr('data-curopt')) { - // Set first as default - shower.attr('data-curopt', btn_opts[0].sel); - } - - var timer; - var pos = $(show_sel).position(); - - // Clicking the "show" icon should set the current mode - shower.mousedown(function(evt) { - if (shower.hasClass('disabled')) { - return false; - } - var holder = $(hold_sel); - var l = pos.left + 34; - var w = holder.width() * -1; - var time = holder.data('shown_popop') ? 200 : 0; - timer = setTimeout(function() { - // Show corresponding menu - if (!shower.data('isLibrary')) { - holder.css('left', w).show().animate({ - left: l - }, 150); - } else { - holder.css('left', l).show(); - } - holder.data('shown_popop', true); - },time); - evt.preventDefault(); - }).mouseup(function(evt) { - clearTimeout(timer); - var opt = $(this).attr('data-curopt'); - // Is library and popped up, so do nothing - if (shower.data('isLibrary') && $(show_sel.replace('_show', '')).is(':visible')) { - toolButtonClick(show_sel, true); - return; - } - if (toolButtonClick(show_sel) && (opt in flyout_funcs)) { - flyout_funcs[opt](); - } - }); - // $('#tools_rect').mouseleave(function(){$('#tools_rect').fadeOut();}); + function promptImgURL() { + var curhref = svgCanvas.getHref(selectedElement); + curhref = curhref.indexOf('data:') === 0 ? '' : curhref; + $.prompt(uiStrings.notification.enterNewImgURL, curhref, function(url) { + if (url) {setImageURL(url);} }); - setFlyoutTitles(); - setFlyoutPositions(); + } + + var setInputWidth = function(elem) { + var w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300); + $(elem).width(w); }; - var makeFlyoutHolder = function(id, child) { - var div = $('