| /* globals jQuery */ | 
| /** | 
|  * ext-arrows.js | 
|  * | 
|  * @license MIT | 
|  * | 
|  * @copyright 2010 Alexis Deveria | 
|  * | 
|  */ | 
| export default { | 
|   name: 'arrows', | 
|   async init (S) { | 
|     const strings = await S.importLocale(); | 
|     const svgEditor = this; | 
|     const svgCanvas = svgEditor.canvas; | 
|     const $ = jQuery; | 
|     const // {svgcontent} = S, | 
|       addElem = svgCanvas.addSVGElementFromJson, | 
|       {nonce} = S, | 
|       prefix = 'se_arrow_'; | 
|   | 
|     let selElems, arrowprefix, randomizeIds = S.randomize_ids; | 
|   | 
|     function setArrowNonce (window, n) { | 
|       randomizeIds = true; | 
|       arrowprefix = prefix + n + '_'; | 
|       pathdata.fw.id = arrowprefix + 'fw'; | 
|       pathdata.bk.id = arrowprefix + 'bk'; | 
|     } | 
|   | 
|     function unsetArrowNonce (window) { | 
|       randomizeIds = false; | 
|       arrowprefix = prefix; | 
|       pathdata.fw.id = arrowprefix + 'fw'; | 
|       pathdata.bk.id = arrowprefix + 'bk'; | 
|     } | 
|   | 
|     svgCanvas.bind('setnonce', setArrowNonce); | 
|     svgCanvas.bind('unsetnonce', unsetArrowNonce); | 
|   | 
|     if (randomizeIds) { | 
|       arrowprefix = prefix + nonce + '_'; | 
|     } else { | 
|       arrowprefix = prefix; | 
|     } | 
|   | 
|     const pathdata = { | 
|       fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw'}, | 
|       bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'} | 
|     }; | 
|   | 
|     function getLinked (elem, attr) { | 
|       const str = elem.getAttribute(attr); | 
|       if (!str) { return null; } | 
|       const m = str.match(/\(#(.*)\)/); | 
|       if (!m || m.length !== 2) { | 
|         return null; | 
|       } | 
|       return svgCanvas.getElem(m[1]); | 
|     } | 
|   | 
|     function showPanel (on) { | 
|       $('#arrow_panel').toggle(on); | 
|       if (on) { | 
|         const el = selElems[0]; | 
|         const end = el.getAttribute('marker-end'); | 
|         const start = el.getAttribute('marker-start'); | 
|         const mid = el.getAttribute('marker-mid'); | 
|         let val; | 
|         if (end && start) { | 
|           val = 'both'; | 
|         } else if (end) { | 
|           val = 'end'; | 
|         } else if (start) { | 
|           val = 'start'; | 
|         } else if (mid) { | 
|           val = 'mid'; | 
|           if (mid.includes('bk')) { | 
|             val = 'mid_bk'; | 
|           } | 
|         } | 
|   | 
|         if (!start && !mid && !end) { | 
|           val = 'none'; | 
|         } | 
|   | 
|         $('#arrow_list').val(val); | 
|       } | 
|     } | 
|   | 
|     function resetMarker () { | 
|       const el = selElems[0]; | 
|       el.removeAttribute('marker-start'); | 
|       el.removeAttribute('marker-mid'); | 
|       el.removeAttribute('marker-end'); | 
|     } | 
|   | 
|     function addMarker (dir, type, id) { | 
|       // TODO: Make marker (or use?) per arrow type, since refX can be different | 
|       id = id || arrowprefix + dir; | 
|   | 
|       const data = pathdata[dir]; | 
|   | 
|       if (type === 'mid') { | 
|         data.refx = 5; | 
|       } | 
|   | 
|       let marker = svgCanvas.getElem(id); | 
|       if (!marker) { | 
|         marker = addElem({ | 
|           element: 'marker', | 
|           attr: { | 
|             viewBox: '0 0 10 10', | 
|             id, | 
|             refY: 5, | 
|             markerUnits: 'strokeWidth', | 
|             markerWidth: 5, | 
|             markerHeight: 5, | 
|             orient: 'auto', | 
|             style: 'pointer-events:none' // Currently needed for Opera | 
|           } | 
|         }); | 
|         const arrow = addElem({ | 
|           element: 'path', | 
|           attr: { | 
|             d: data.d, | 
|             fill: '#000000' | 
|           } | 
|         }); | 
|         marker.append(arrow); | 
|         svgCanvas.findDefs().append(marker); | 
|       } | 
|   | 
|       marker.setAttribute('refX', data.refx); | 
|   | 
|       return marker; | 
|     } | 
|   | 
|     function setArrow () { | 
|       resetMarker(); | 
|   | 
|       let type = this.value; | 
|       if (type === 'none') { | 
|         return; | 
|       } | 
|   | 
|       // Set marker on element | 
|       let dir = 'fw'; | 
|       if (type === 'mid_bk') { | 
|         type = 'mid'; | 
|         dir = 'bk'; | 
|       } else if (type === 'both') { | 
|         addMarker('bk', type); | 
|         svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')'); | 
|         type = 'end'; | 
|         dir = 'fw'; | 
|       } else if (type === 'start') { | 
|         dir = 'bk'; | 
|       } | 
|   | 
|       addMarker(dir, type); | 
|       svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')'); | 
|       svgCanvas.call('changed', selElems); | 
|     } | 
|   | 
|     function colorChanged (elem) { | 
|       const color = elem.getAttribute('stroke'); | 
|       const mtypes = ['start', 'mid', 'end']; | 
|       const defs = svgCanvas.findDefs(); | 
|   | 
|       $.each(mtypes, function (i, type) { | 
|         const marker = getLinked(elem, 'marker-' + type); | 
|         if (!marker) { return; } | 
|   | 
|         const curColor = $(marker).children().attr('fill'); | 
|         const curD = $(marker).children().attr('d'); | 
|         if (curColor === color) { return; } | 
|   | 
|         const allMarkers = $(defs).find('marker'); | 
|         let newMarker = null; | 
|         // Different color, check if already made | 
|         allMarkers.each(function () { | 
|           const attrs = $(this).children().attr(['fill', 'd']); | 
|           if (attrs.fill === color && attrs.d === curD) { | 
|             // Found another marker with this color and this path | 
|             newMarker = this; | 
|           } | 
|         }); | 
|   | 
|         if (!newMarker) { | 
|           // Create a new marker with this color | 
|           const lastId = marker.id; | 
|           const dir = lastId.includes('_fw') ? 'fw' : 'bk'; | 
|   | 
|           newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length); | 
|   | 
|           $(newMarker).children().attr('fill', color); | 
|         } | 
|   | 
|         $(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')'); | 
|   | 
|         // Check if last marker can be removed | 
|         let remove = true; | 
|         $(S.svgcontent).find('line, polyline, path, polygon').each(function () { | 
|           const elem = this; | 
|           $.each(mtypes, function (j, mtype) { | 
|             if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') { | 
|               remove = false; | 
|               return remove; | 
|             } | 
|           }); | 
|           if (!remove) { return false; } | 
|         }); | 
|   | 
|         // Not found, so can safely remove | 
|         if (remove) { | 
|           $(marker).remove(); | 
|         } | 
|       }); | 
|     } | 
|   | 
|     const contextTools = [ | 
|       { | 
|         type: 'select', | 
|         panel: 'arrow_panel', | 
|         id: 'arrow_list', | 
|         defval: 'none', | 
|         events: { | 
|           change: setArrow | 
|         } | 
|       } | 
|     ]; | 
|   | 
|     return { | 
|       name: strings.name, | 
|       context_tools: strings.contextTools.map((contextTool, i) => { | 
|         return Object.assign(contextTools[i], contextTool); | 
|       }), | 
|       callback () { | 
|         $('#arrow_panel').hide(); | 
|         // Set ID so it can be translated in locale file | 
|         $('#arrow_list option')[0].id = 'connector_no_arrow'; | 
|       }, | 
|       async addLangData ({lang, importLocale}) { | 
|         const strings = await importLocale(); | 
|         return { | 
|           data: strings.langList | 
|         }; | 
|       }, | 
|       selectedChanged (opts) { | 
|         // Use this to update the current selected elements | 
|         selElems = opts.elems; | 
|   | 
|         const markerElems = ['line', 'path', 'polyline', 'polygon']; | 
|         let i = selElems.length; | 
|         while (i--) { | 
|           const elem = selElems[i]; | 
|           if (elem && markerElems.includes(elem.tagName)) { | 
|             if (opts.selectedElement && !opts.multiselected) { | 
|               showPanel(true); | 
|             } else { | 
|               showPanel(false); | 
|             } | 
|           } else { | 
|             showPanel(false); | 
|           } | 
|         } | 
|       }, | 
|       elementChanged (opts) { | 
|         const elem = opts.elems[0]; | 
|         if (elem && ( | 
|           elem.getAttribute('marker-start') || | 
|           elem.getAttribute('marker-mid') || | 
|           elem.getAttribute('marker-end') | 
|         )) { | 
|           // const start = elem.getAttribute('marker-start'); | 
|           // const mid = elem.getAttribute('marker-mid'); | 
|           // const end = elem.getAttribute('marker-end'); | 
|           // Has marker, so see if it should match color | 
|           colorChanged(elem); | 
|         } | 
|       } | 
|     }; | 
|   } | 
| }; |