xref: /plugin/diagrams/script.js (revision 709a5f27d51480bdc4b769fd12b8d1a930110828)
1jQuery( function() {
2
3    const serviceUrl = 'https://embed.diagrams.net/?embed=1&proto=json&spin=1';
4    const doctypeXML = '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
5
6    // check if name/id of new diagram is valid
7    function validId(id) {
8        return id.length > 0 && /^[\w][\w\.\-]*$/.test( id )
9    }
10
11    // return URL to fetch existing diagram from DW
12    function getLocalDiagramUrl(ns, id) {
13        return DOKU_BASE + 'lib/exe/ajax.php?call=mediaupload&ow=true&ns=' + ns + '&qqfile=' + id + '&sectok=' + JSINFO['sectok'];
14    }
15
16    // split full id into ns and id parts
17    function splitFullId(fullId) {
18        let id = fullId;
19        let ns = '';
20        const idParts = id.split(':');
21        if (idParts.length > 1) {
22            ns = idParts[0];
23            id = idParts.slice(1).join(':');
24        }
25         return {ns: ns, id: id};
26    }
27
28    /**
29     * Launch diagram editor's iframe
30     */
31    const launchEditor = function(fullId) {
32        if (!jQuery('#drawio-frame')[0]) {
33            jQuery('body').append('<iframe id="drawio-frame" style="border: 0;position: fixed; top: 0; left: 0; right:0; bottom: 0; width:100%; height:100%; z-index: 9999;"></iframe>');
34            jQuery(window).on('message', {fullId: fullId}, handleServiceMessages);
35            jQuery('#drawio-frame').attr('src', serviceUrl);
36        }
37    };
38
39    /**
40     * Handle messages from diagramming service
41     *
42     * @param e
43     */
44    const handleServiceMessages = function( e ) {
45        // get diagram info passed to the function
46        const fullId = e.data.fullId;
47        const {ns, id} = splitFullId(fullId);
48
49        const msg = JSON.parse( e.originalEvent.data );
50        const drawio = jQuery( '#drawio-frame' )[0].contentWindow;
51        if( msg.event === 'init' ) {
52            // try loading existing diagram file
53            jQuery.get(DOKU_BASE + 'lib/exe/fetch.php?media=' + fullId, function (data) {
54                drawio.postMessage(JSON.stringify({action: 'load', xml: data}), '*');
55            }, 'text')
56            .fail(function () { // catch 404, file does not exist yet locally
57                drawio.postMessage(JSON.stringify({action: 'load', xml: ''}), '*');
58            });
59        } else if ( msg.event === 'save' ) {
60            drawio.postMessage(
61                JSON.stringify( {action: 'export', format: 'xmlsvg', spin: 'Speichern' } ),
62                '*'
63            );
64        } else if ( msg.event === 'export' ) {
65            if ( msg.format !== 'svg' ) {
66                alert( 'Nicht unterstützt!' );
67            } else {
68                const datastr = doctypeXML + '\n' +
69                    decodeURIComponent( atob( msg.data.split( ',' )[1] ).split( '' ).map( function( c ) {
70                        return '%' + ( '00' + c.charCodeAt( 0 ).toString( 16 ) ).slice( -2 );
71                    } ).join( '' ) );
72                jQuery.post( getLocalDiagramUrl(ns, id), datastr )
73                    .done( function() {
74                        jQuery( window ).off( 'message', handleServiceMessages );
75                        jQuery( '#drawio-frame' ).remove();
76                        // media manager window should reflect selection in ns tree
77                        const url = new URL(location.href);
78                        url.searchParams.set('ns', ns);
79                        setTimeout( function() {
80                            location.assign(url);
81                        }, 200 );
82                    } ).fail( function() {
83                    alert( 'Fehler beim Speichern' );
84                } );
85            }
86        } else if( msg.event === 'exit' ) {
87            jQuery( window ).off( 'message', handleServiceMessages );
88            jQuery( '#drawio-frame' ).remove();
89        }
90    };
91
92    // add diagram edit button to all SVGs included in wiki pages
93    if( JSINFO['iseditor'] ) {
94        jQuery( 'img, object' ).filter( '.media, .medialeft, .mediacenter, .mediaright' ).add( 'iframe.svgpureinsert' ).each( function() {
95            const current = jQuery( this );
96            const src = this.nodeName === 'OBJECT' ? current.attr( 'data' ) : current.attr( 'src' );
97            const extension = src.split( '.' ).pop().toLowerCase();
98            if( extension === 'svg' ) {
99                const editlink = '<br><button class="drawio-btn btn btn-default btn-xs" style="clear:both" data-id="' + src.split('media=')[1].split('&')[0] + '">Editieren</button>';
100                if( current.parent()[0].nodeName === 'A' ) {
101                    current.parent().after( editlink );
102                } else {
103                    current.after( editlink );
104                }
105            }
106        } );
107    }
108
109    // attach diagram editing function to the button rendered on pages
110    jQuery( 'button.drawio-btn' ).on( 'click', function () {
111        const fullId = jQuery( this ).data( 'id' );
112        launchEditor(fullId);
113    });
114
115    // create a new diagram, triggered by click on page tools item
116    jQuery( 'a#drawio-newfile-create' ).on( 'click', function( e ) {
117        e.preventDefault();
118        const ns = NS;
119        let id = prompt( 'Name des neuen Diagramms' );
120        if( !validId(id) ) {
121            alert( 'Dateiname ist leer oder enthält ungültige Zeichen' );
122            return;
123        }
124        id += '.svg';
125        const datastr = doctypeXML +
126            '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1px" height="1px" version="1.1" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36&quot; version=&quot;7.9.5&quot; editor=&quot;www.draw.io&quot;&gt;&lt;diagram id=&quot;8c846276-93cf-00fc-3101-d1fabb6ae99a&quot; name=&quot;Seite-1&quot;&gt;dZHBEoIgEIafhrtCNXY2q0snD51JEJjQdRBH6+nTwIyxuLB8/7+7sCCSVsPJ0EZegHGNcMQGRA4I43iDd+M2kYcjSbJ3QBjFvGkBuXpyDyNPO8V4GxgtgLaqCWEBdc0LGzBqDPShrQQddm2o4CuQF1Sv6VUxK/0rttHCz1wJOXeOI6/caHEXBrra90OYlO/l5IrOtby/lZRB/4VIhkhqAKyLqiHleprtPDaXd/yjfu5teG1/JIzBUns8BB9Ishc=&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g transform="translate(0.5,0.5)"/></svg>';
127        jQuery.post( getLocalDiagramUrl(ns, id), datastr )
128            .done( function( response ) {
129                if( response.error ) {
130                    alert( 'Fehler beim Speichern: ' + response.error );
131                } else {
132                    alert( 'Diagramm ' + response.id + ' angelegt' );
133                }
134            } ).fail( function() {
135                alert( 'Fehler beim Speichern' );
136            } );
137    } );
138
139    /**
140     * Launch the editor and create a new diagram
141     *
142     * @param event
143     */
144    function createDiagram(event) {
145        event.preventDefault();
146
147        let href;
148        // FIXME does this really work?
149        // get namespace selected in ns tree
150        $selectedNSLink = jQuery('.idx_dir.selected');
151        if ($selectedNSLink && $selectedNSLink.length > 0) {
152            href = $selectedNSLink.attr('href');
153        } else {
154            // FIXME url rewriting?
155            href = location.href;
156        }
157        const ns = extractNs(href);
158        const id = jQuery('#drawio__create-filename').val();
159
160        if (!validId(id)) {
161            alert('name is empty or contains invalid characters!');
162            return;
163        }
164
165        const fullIdArray = [ns, id];
166        launchEditor(fullIdArray.join(':') + '.svg');
167    }
168
169    // extract ns param from URL
170    function extractNs(url) {
171        urlParam = function(name) {
172            var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(url);
173            return results[1] || '';
174        };
175        return decodeURIComponent(urlParam('ns'));
176    }
177
178    // returns a diagram creation form as jQuery object
179    function newDiagramForm() {
180        currentNs = extractNs(location.href);
181        $drawioCreateForm = jQuery(
182            '<form>' +
183            '<p>Create draw.io diagram in current namespace <strong><span id="drawio__current-ns">' +
184            currentNs +
185            '</strong></span></p>' +
186            '<input type="text" name="drawio-create-filename" id="drawio__create-filename" />' +
187            '<button id="drawio__create">Create</button>' +
188            '</form>'
189        );
190
191        jQuery( $drawioCreateForm ).on( 'submit', createDiagram );
192
193        return $drawioCreateForm;
194    }
195
196    /**
197     * Full-page media manager
198     */
199    const $mm_page = jQuery('#mediamanager__page');
200    if (!$mm_page.length) return;
201
202    const $mm_tree = jQuery("#media__tree");
203    $mm_tree.prepend(newDiagramForm());
204
205    // update diagram NS when clicking in media tree
206    $mm_tree.find('a.idx_dir').each(function (e) {
207        const $this = jQuery( this );
208        $this.on('click', function (e) {
209            e.preventDefault();
210
211            const $nsSpan = jQuery('#drawio__current-ns');
212            $nsSpan.text(extractNs(e.target));
213        });
214    });
215
216    // TODO pop-up media manager
217} );
218