1let refnotes_admin = (function () {
2    let modified = false;
3
4
5    class NameMap extends Map {
6        constructor(sentinel) {
7            super();
8
9            this.sentinel = sentinel;
10        }
11
12        get(key) {
13            return key == '' ? this.sentinel : super.get(key);
14        }
15
16        has(key) {
17            return key == '' ? true : super.has(key);
18        }
19    }
20
21
22    class NamedObjectMap extends Map {
23        set(value) {
24            super.set(value.getName(), value);
25        }
26    }
27
28
29    function List(id) {
30        let list = jQuery(id);
31
32        function appendOption(value) {
33            jQuery('<option>')
34                .html(value)
35                .val(value)
36                .prop('sorting', value.replace(/:/g, '-').replace(/(-\w+)$/, '-$1'))
37                .appendTo(list);
38        }
39
40        function sortOptions() {
41            list.append(list.children().get().sort(function (a, b) {
42                return a.sorting > b.sorting ? 1 : -1;
43            }));
44        }
45
46        this.getSelectedValue = function () {
47            return list.val();
48        }
49
50        this.insertValue = function (value) {
51            appendOption(value);
52            sortOptions();
53
54            return list.children('[value="' + value + '"]').attr('selected', 'selected').val();
55        }
56
57        this.reload = function (values) {
58            list.empty();
59
60            for (let value of values.keys()) {
61                if (value != '') {
62                    appendOption(value);
63                }
64            }
65
66            sortOptions();
67
68            return list.children(':first').attr('selected', 'selected').val();
69        }
70
71        this.removeValue = function (value) {
72            let option = list.children('[value="' + value + '"]');
73
74            if (option.length == 1) {
75                list.prop('selectedIndex', option.index() + (option.is(':last-child') ? -1 : 1));
76                option.remove();
77            }
78
79            return list.val();
80        }
81
82        this.renameValue = function (oldValue, newValue) {
83            if (list.children('[value="' + oldValue + '"]').remove().length == 1) {
84                this.insertValue(newValue);
85            }
86
87            return list.val();
88        }
89    }
90
91
92    let locale = (function () {
93        let lang = new Map();
94
95        function initialize() {
96            jQuery.each(jQuery('#refnotes-lang').html().split(/:eos:/), function (key, value) {
97                let match = value.match(/^\s*(\w+) : (.+)/);
98                if (match != null) {
99                    lang.set(match[1], match[2]);
100                }
101            });
102        }
103
104        function getString(key) {
105            let string = lang.has(key) ? lang.get(key) : '';
106
107            if ((string.length > 0) && (arguments.length > 1)) {
108                for (let i = 1; i < arguments.length; i++) {
109                    string = string.replace(new RegExp('\\{' + i + '\\}'), arguments[i]);
110                }
111            }
112
113            return string;
114        }
115
116        return {
117            initialize,
118            getString
119        }
120    })();
121
122
123    let server = (function () {
124        let timer = null;
125        let transaction = null;
126
127        function sendRequest(request, data, success) {
128            if (transaction == null) {
129                transaction = request;
130
131                jQuery.ajax({
132                    cache   : false,
133                    data    : data,
134                    global  : false,
135                    success : success,
136                    type    : 'POST',
137                    timeout : 10000,
138                    url     : DOKU_BASE + 'lib/exe/ajax.php',
139                    beforeSend() {
140                        setStatus('info', transaction);
141                    },
142                    error(xhr, status, message) {
143                        setErrorStatus((status == 'parseerror') ? 'invalid_data' : transaction + '_failed', message);
144                    },
145                    dataFilter(data) {
146                        let cookie = '{B27067E9-3DDA-4E31-9768-E66F23D18F4A}';
147                        let match = data.match(new RegExp(cookie + '(.+?)' + cookie));
148
149                        if ((match == null) || (match.length != 2)) {
150                            throw 'Malformed response';
151                        }
152
153                        return match[1];
154                    },
155                    complete() {
156                        transaction = null;
157                    }
158                });
159            }
160            else {
161                setErrorStatus(request + '_failed', 'Server is busy');
162            }
163        }
164
165        function loadSettings() {
166            sendRequest('loading', {
167                call   : 'refnotes-admin',
168                action : 'load-settings'
169            }, function (data) {
170                setSuccessStatus('loaded', 3000);
171                reloadSettings(data);
172            });
173        }
174
175        function saveSettings(settings) {
176            sendRequest('saving', {
177                call     : 'refnotes-admin',
178                action   : 'save-settings',
179                settings : JSON.stringify(settings)
180            }, function (data) {
181                if (data == 'saved') {
182                    modified = false;
183
184                    setSuccessStatus('saved', 10000);
185                }
186                else {
187                    setErrorStatus('saving_failed', 'Server FS access error');
188                }
189            });
190        }
191
192        function setStatus(status, message) {
193            window.clearTimeout(timer);
194
195            if (message.match(/^\w+$/) != null) {
196                message = locale.getString(message);
197            }
198
199            jQuery('#server-status')
200                .removeClass()
201                .addClass(status)
202                .text(message);
203        }
204
205        function setErrorStatus(messageId, details) {
206            setStatus('error', locale.getString(messageId, details));
207        }
208
209        function setSuccessStatus(messageId, timeout) {
210            setStatus('success', messageId);
211
212            timer = window.setTimeout(function () {
213                setStatus('cleared', 'status');
214            }, timeout);
215        }
216
217        return {
218            loadSettings,
219            saveSettings
220        }
221    })();
222
223
224    let general = (function () {
225        let fields   = new NamedObjectMap();
226        let defaults = new Map([
227            ['replace-footnotes'     , false],
228            ['reference-db-enable'   , false],
229            ['reference-db-namespace', ':refnotes:']
230        ]);
231
232        function Field(settingName) {
233            this.element = jQuery('#field-' + settingName);
234
235            this.element.change(this, function (event) {
236                event.data.updateDefault();
237                modified = true;
238            });
239
240            this.getName = function () {
241                return settingName;
242            }
243
244            this.updateDefault = function () {
245                this.element.parents('td').toggleClass('default', this.getValue() == defaults.get(settingName));
246            }
247
248            this.enable = function (enable) {
249                this.element.prop('disabled', !enable);
250            }
251        }
252
253        function CheckField(settingName) {
254            this.baseClass = Field;
255            this.baseClass(settingName);
256
257            this.setValue = function (value) {
258                this.element.attr('checked', value);
259                this.updateDefault();
260            }
261
262            this.getValue = function () {
263                return this.element.is(':checked');
264            }
265
266            this.setValue(defaults.get(settingName));
267            this.enable(false);
268        }
269
270        function TextField(settingName) {
271            this.baseClass = Field;
272            this.baseClass(settingName);
273
274            this.setValue = function (value) {
275                this.element.val(value);
276                this.updateDefault();
277            }
278
279            this.getValue = function () {
280                return this.element.val();
281            }
282
283            this.setValue(defaults.get(settingName));
284            this.enable(false);
285        }
286
287        function initialize() {
288            fields.set(new CheckField('replace-footnotes'));
289            fields.set(new CheckField('reference-db-enable'));
290            fields.set(new TextField('reference-db-namespace'));
291
292            jQuery('#field-reference-db-namespace').css('width', '19em');
293        }
294
295        function reload(settings) {
296            for (let name in settings) {
297                if (fields.has(name)) {
298                    fields.get(name).setValue(settings[name]);
299                }
300            }
301
302            for (let field of fields.values()) {
303                field.enable(true);
304            }
305        }
306
307        function getSettings() {
308            let settings = {};
309
310            for (let [name, field] of fields) {
311                settings[name] = field.getValue();
312            }
313
314            return settings;
315        }
316
317        return {
318            initialize,
319            reload,
320            getSettings
321        }
322    })();
323
324
325    let namespaces = (function () {
326        let list       = null;
327        let fields     = new NamedObjectMap();
328        let namespaces = new NameMap(new DefaultNamespace());
329        let current    = namespaces.get('');
330        let defaults   = new Map([
331            ['refnote-id'           , 'numeric'],
332            ['reference-base'       , 'super'],
333            ['reference-font-weight', 'normal'],
334            ['reference-font-style' , 'normal'],
335            ['reference-format'     , 'right-parent'],
336            ['reference-group'      , 'group-none'],
337            ['reference-render'     , 'basic'],
338            ['multi-ref-id'         , 'ref-counter'],
339            ['note-preview'         , 'popup'],
340            ['notes-separator'      , '100%'],
341            ['note-text-align'      , 'justify'],
342            ['note-font-size'       , 'reduced'],
343            ['note-render'          , 'basic'],
344            ['note-id-base'         , 'super'],
345            ['note-id-font-weight'  , 'normal'],
346            ['note-id-font-style'   , 'normal'],
347            ['note-id-format'       , 'right-parent'],
348            ['back-ref-caret'       , 'none'],
349            ['back-ref-base'        , 'super'],
350            ['back-ref-font-weight' , 'bold'],
351            ['back-ref-font-style'  , 'normal'],
352            ['back-ref-format'      , 'note-id'],
353            ['back-ref-separator'   , 'comma'],
354            ['scoping'              , 'reset']
355        ]);
356
357        function DefaultNamespace() {
358            this.isReadOnly = function () {
359                return true;
360            }
361
362            this.setName = function (newName) {
363            }
364
365            this.getName = function () {
366                return '';
367            }
368
369            this.setStyle = function (name, value) {
370            }
371
372            this.getStyle = function (name) {
373                return defaults.get(name);
374            }
375
376            this.getStyleInheritance = function (name) {
377                return 'default';
378            }
379
380            this.getSettings = function () {
381                return {};
382            }
383        }
384
385        function Namespace(name, data) {
386            let styles = data ? new Map(Object.entries(data)) : new Map();
387
388            function getParent() {
389                let parent = name.replace(/\w*:$/, '');
390
391                while (!namespaces.has(parent)) {
392                    parent = parent.replace(/\w*:$/, '');
393                }
394
395                return namespaces.get(parent);
396            }
397
398            this.isReadOnly = function () {
399                return false;
400            }
401
402            this.setName = function (newName) {
403                name = newName;
404            }
405
406            this.getName = function () {
407                return name;
408            }
409
410            this.setStyle = function (name, value) {
411                if (value == 'inherit') {
412                    styles.delete(name);
413                }
414                else {
415                    styles.set(name, value);
416                }
417            }
418
419            this.getStyle = function (name) {
420                let result;
421
422                if (styles.has(name)) {
423                    result = styles.get(name);
424                }
425                else {
426                    result = getParent().getStyle(name);
427                }
428
429                return result;
430            }
431
432            this.getStyleInheritance = function (name) {
433                let result = '';
434
435                if (!styles.has(name)) {
436                    result = getParent().getStyleInheritance(name) || 'inherited';
437                }
438
439                return result;
440            }
441
442            this.getSettings = function () {
443                let settings = {};
444
445                for (let [name, style] of styles) {
446                    settings[name] = style;
447                }
448
449                return settings;
450            }
451        }
452
453        function Field(styleName) {
454            this.element = jQuery('#field-' + styleName);
455
456            this.getName = function () {
457                return styleName;
458            }
459
460            this.updateInheretance = function () {
461                this.element.parents('td')
462                    .removeClass('default inherited')
463                    .addClass(current.getStyleInheritance(styleName));
464            }
465        }
466
467        function SelectField(styleName) {
468            this.baseClass = Field;
469            this.baseClass(styleName);
470
471            let combo = this.element;
472
473            combo.change(this, function (event) {
474                event.data.onChange();
475            });
476
477            function setSelection(value) {
478                combo.val(value);
479            }
480
481            this.onChange = function () {
482                let value = combo.val();
483
484                current.setStyle(styleName, value);
485
486                this.updateInheretance();
487
488                if ((value == 'inherit') || current.isReadOnly()) {
489                    setSelection(current.getStyle(styleName));
490                }
491
492                modified = true;
493            }
494
495            this.update = function () {
496                this.updateInheretance();
497                setSelection(current.getStyle(styleName));
498                combo.prop('disabled', current.isReadOnly());
499            }
500        }
501
502        function TextField(styleName, validate) {
503            this.baseClass = Field;
504            this.baseClass(styleName);
505
506            let edit   = this.element;
507            let button = jQuery('#field-' + styleName + '-inherit');
508
509            edit.change(this, function (event) {
510                event.data.setValue(validate(edit.val()));
511            });
512
513            button.click(this, function (event) {
514                event.data.setValue('inherit');
515            });
516
517            this.setValue = function (value) {
518                current.setStyle(styleName, value);
519
520                this.updateInheretance();
521
522                if ((edit.val() != value) || (value == 'inherit') || current.isReadOnly()) {
523                    edit.val(current.getStyle(styleName));
524                }
525
526                modified = true;
527            }
528
529            this.update = function () {
530                this.updateInheretance();
531
532                edit.val(current.getStyle(styleName));
533                edit.prop('disabled', current.isReadOnly());
534                button.prop('disabled', current.isReadOnly());
535            }
536        }
537
538        function initialize() {
539            list = new List('#select-namespaces');
540
541            fields.set(new SelectField('refnote-id'));
542            fields.set(new SelectField('reference-base'));
543            fields.set(new SelectField('reference-font-weight'));
544            fields.set(new SelectField('reference-font-style'));
545            fields.set(new SelectField('reference-format'));
546            fields.set(new SelectField('reference-group'));
547            fields.set(new SelectField('reference-render'));
548            fields.set(new SelectField('multi-ref-id'));
549            fields.set(new SelectField('note-preview'));
550            fields.set(new TextField('notes-separator', function (value) {
551                return (value.match(/(?:\d+\.?|\d*\.\d+)(?:%|em|px)|none/) != null) ? value : 'none';
552            }));
553            fields.set(new SelectField('note-text-align'));
554            fields.set(new SelectField('note-font-size'));
555            fields.set(new SelectField('note-render'));
556            fields.set(new SelectField('note-id-base'));
557            fields.set(new SelectField('note-id-font-weight'));
558            fields.set(new SelectField('note-id-font-style'));
559            fields.set(new SelectField('note-id-format'));
560            fields.set(new SelectField('back-ref-caret'));
561            fields.set(new SelectField('back-ref-base'));
562            fields.set(new SelectField('back-ref-font-weight'));
563            fields.set(new SelectField('back-ref-font-style'));
564            fields.set(new SelectField('back-ref-format'));
565            fields.set(new SelectField('back-ref-separator'));
566            fields.set(new SelectField('scoping'));
567
568            jQuery('#select-namespaces').change(onNamespaceChange);
569            jQuery('#name-namespaces').prop('disabled', true);
570            jQuery('#add-namespaces').click(onAddNamespace).prop('disabled', true);
571            jQuery('#rename-namespaces').click(onRenameNamespace).prop('disabled', true);
572            jQuery('#delete-namespaces').click(onDeleteNamespace).prop('disabled', true);
573
574            updateFields();
575        }
576
577        function onNamespaceChange(event) {
578            setCurrent(list.getSelectedValue());
579        }
580
581        function onAddNamespace(event) {
582            try {
583                let name = validateName(jQuery('#name-namespaces').val(), 'ns', namespaces);
584
585                namespaces.set(name, new Namespace(name));
586
587                setCurrent(list.insertValue(name));
588
589                modified = true;
590            }
591            catch (error) {
592                alert(error);
593            }
594        }
595
596        function onRenameNamespace(event) {
597            try {
598                let newName = validateName(jQuery('#name-namespaces').val(), 'ns', namespaces);
599                let oldName = current.getName();
600
601                current.setName(newName);
602
603                namespaces.delete(oldName);
604                namespaces.set(newName, current);
605
606                setCurrent(list.renameValue(oldName, newName));
607
608                modified = true;
609            }
610            catch (error) {
611                alert(error);
612            }
613        }
614
615        function onDeleteNamespace(event) {
616            if (confirm(locale.getString('delete_ns', current.getName()))) {
617                namespaces.delete(current.getName());
618
619                setCurrent(list.removeValue(current.getName()));
620
621                modified = true;
622            }
623        }
624
625        function reload(settings) {
626            namespaces.clear();
627
628            for (let name in settings) {
629                if (name.match(/^:$|^:.+?:$/) != null) {
630                    namespaces.set(name, new Namespace(name, settings[name]));
631                }
632            }
633
634            jQuery('#name-namespaces').prop('disabled', false);
635            jQuery('#add-namespaces').prop('disabled', false);
636
637            setCurrent(list.reload(namespaces));
638        }
639
640        function setCurrent(name) {
641            current = namespaces.get(name);
642
643            updateFields();
644        }
645
646        function updateFields() {
647            jQuery('#name-namespaces').val(current.getName());
648            jQuery('#rename-namespaces').prop('disabled', current.isReadOnly());
649            jQuery('#delete-namespaces').prop('disabled', current.isReadOnly());
650
651            for (let field of fields.values()) {
652                field.update();
653            }
654        }
655
656        function getSettings() {
657            let settings = {};
658
659            for (let [name, namespace] of namespaces) {
660                settings[name] = namespace.getSettings();
661            }
662
663            return settings;
664        }
665
666        return {
667            initialize,
668            reload,
669            getSettings
670        }
671    })();
672
673
674    let notes = (function () {
675        let list     = null;
676        let fields   = new NamedObjectMap();
677        let notes    = new NameMap(new EmptyNote());
678        let current  = notes.get('');
679        let defaults = new Map([
680            ['inline'                   , false],
681            ['use-reference-base'       , true],
682            ['use-reference-font-weight', true],
683            ['use-reference-font-style' , true],
684            ['use-reference-format'     , true]
685        ]);
686        let inlineAttributes = [
687            'use-reference-base',
688            'use-reference-font-weight',
689            'use-reference-font-style',
690            'use-reference-format'
691        ];
692
693        function isInlineAttribute(name) {
694            return inlineAttributes.indexOf(name) != -1;
695        }
696
697        function EmptyNote() {
698            this.isReadOnly = function () {
699                return true;
700            }
701
702            this.setName = function (newName) {
703            }
704
705            this.getName = function () {
706                return '';
707            }
708
709            this.setText = function (text) {
710            }
711
712            this.getText = function () {
713                return '';
714            }
715
716            this.setAttribute = function (name, value) {
717            }
718
719            this.getAttribute = function (name) {
720                return defaults.get(name);
721            }
722
723            this.getSettings = function () {
724                return {};
725            }
726        }
727
728        function Note(name, data) {
729            let attributes = data ? new Map(Object.entries(data)) : new Map();
730
731            this.isReadOnly = function () {
732                return false;
733            }
734
735            this.setName = function (newName) {
736                name = newName;
737            }
738
739            this.getName = function () {
740                return name;
741            }
742
743            this.setText = function (text) {
744                attributes.set('text', text);
745            }
746
747            this.getText = function () {
748                return attributes.get('text');
749            }
750
751            this.setAttribute = function (name, value) {
752                attributes.set(name, value);
753            }
754
755            this.getAttribute = function (name) {
756                if (!attributes.has(name) || (isInlineAttribute(name) && !this.getAttribute('inline'))) {
757                    return defaults.get(name);
758                }
759                else {
760                    return attributes.get(name);
761                }
762            }
763
764            this.getSettings = function () {
765                let settings = {};
766
767                if (!this.getAttribute('inline')) {
768                    for (let i in inlineAttributes) {
769                        if (attributes.has(inlineAttributes[i])) {
770                            attributes.delete(inlineAttributes[i]);
771                        }
772                    }
773                }
774
775                for (let [name, attribute] of attributes) {
776                    settings[name] = attribute;
777                }
778
779                return settings;
780            }
781        }
782
783        function Field(attributeName) {
784            this.element = jQuery('#field-' + attributeName);
785
786            this.element.change(this, function (event) {
787                current.setAttribute(attributeName, event.data.getValue());
788                modified = true;
789            });
790
791            this.getName = function () {
792                return attributeName;
793            }
794
795            this.enable = function (enable) {
796                this.element.prop('disabled', !enable);
797            }
798        }
799
800        function CheckField(attributeName) {
801            this.baseClass = Field;
802            this.baseClass(attributeName);
803
804            this.setValue = function (value) {
805                this.element.attr('checked', value);
806            }
807
808            this.getValue = function () {
809                return this.element.is(':checked');
810            }
811
812            this.update = function () {
813                this.setValue(current.getAttribute(attributeName));
814                this.enable(!current.isReadOnly() && (!isInlineAttribute(attributeName) || current.getAttribute('inline')));
815            }
816        }
817
818        function InlineField() {
819            this.baseClass = CheckField;
820            this.baseClass('inline');
821
822            this.element.change(this, function (event) {
823                for (let i in inlineAttributes) {
824                    fields.get(inlineAttributes[i]).update();
825                }
826            });
827        }
828
829        function initialize() {
830            list = new List('#select-notes');
831
832            fields.set(new InlineField());
833            fields.set(new CheckField('use-reference-base'));
834            fields.set(new CheckField('use-reference-font-weight'));
835            fields.set(new CheckField('use-reference-font-style'));
836            fields.set(new CheckField('use-reference-format'));
837
838            jQuery('#select-notes').change(onNoteChange);
839            jQuery('#name-notes').prop('disabled', true);
840            jQuery('#add-notes').click(onAddNote).prop('disabled', true);
841            jQuery('#rename-notes').click(onRenameNote).prop('disabled', true);
842            jQuery('#delete-notes').click(onDeleteNote).prop('disabled', true);
843            jQuery('#field-note-text').change(onTextChange);
844
845            updateFields();
846        }
847
848        function onNoteChange(event) {
849            setCurrent(list.getSelectedValue());
850        }
851
852        function onAddNote(event) {
853            try {
854                let name = validateName(jQuery('#name-notes').val(), 'note', notes);
855
856                notes.set(name, new Note(name));
857
858                setCurrent(list.insertValue(name));
859
860                modified = true;
861            }
862            catch (error) {
863                alert(error);
864            }
865        }
866
867        function onRenameNote(event) {
868            try {
869                let newName = validateName(jQuery('#name-notes').val(), 'note', notes);
870                let oldName = current.getName();
871
872                current.setName(newName);
873
874                notes.delete(oldName);
875                notes.set(newName, current);
876
877                setCurrent(list.renameValue(oldName, newName));
878
879                modified = true;
880            }
881            catch (error) {
882                alert(error);
883            }
884        }
885
886        function onDeleteNote(event) {
887            if (confirm(locale.getString('delete_note', current.getName()))) {
888                notes.delete(current.getName());
889
890                setCurrent(list.removeValue(current.getName()));
891
892                modified = true;
893            }
894        }
895
896        function onTextChange(event) {
897            current.setText(event.target.value);
898
899            modified = true;
900        }
901
902        function reload(settings) {
903            notes.clear();
904
905            for (let name in settings) {
906                if (name.match(/^:.+?\w$/) != null) {
907                    notes.set(name, new Note(name, settings[name]));
908                }
909            }
910
911            jQuery('#name-notes').prop('disabled', false);
912            jQuery('#add-notes').prop('disabled', false);
913
914            setCurrent(list.reload(notes));
915        }
916
917        function setCurrent(name) {
918            current = notes.get(name);
919
920            updateFields();
921        }
922
923        function updateFields() {
924            jQuery('#name-notes').val(current.getName());
925            jQuery('#rename-notes').prop('disabled', current.isReadOnly());
926            jQuery('#delete-notes').prop('disabled', current.isReadOnly());
927            jQuery('#field-note-text').val(current.getText()).prop('disabled', current.isReadOnly());
928
929            for (let field of fields.values()) {
930                field.update();
931            }
932        }
933
934        function getSettings() {
935            let settings = {};
936
937            for (let [name, note] of notes) {
938                settings[name] = note.getSettings();
939            }
940
941            return settings;
942        }
943
944        return {
945            initialize,
946            reload,
947            getSettings
948        }
949    })();
950
951
952    function initialize() {
953        locale.initialize();
954        general.initialize();
955        namespaces.initialize();
956        notes.initialize();
957
958        jQuery('#save-config').click(function () {
959            saveSettings();
960        });
961
962        window.onbeforeunload = onBeforeUnload;
963
964        jQuery('#server-status').show();
965
966        server.loadSettings();
967    }
968
969    function reloadSettings(settings) {
970        general.reload(settings.general);
971        namespaces.reload(settings.namespaces);
972        notes.reload(settings.notes);
973    }
974
975    function saveSettings() {
976        let settings = {};
977
978        settings.general    = general.getSettings();
979        settings.namespaces = namespaces.getSettings();
980        settings.notes      = notes.getSettings();
981
982        server.saveSettings(settings);
983
984        scroll(0, 0);
985    }
986
987    function onBeforeUnload(event) {
988        if (modified) {
989            let message = locale.getString('unsaved');
990
991            (event || window.event).returnValue = message;
992
993            return message;
994        }
995    }
996
997    function validateName(name, type, existing) {
998        let names = name.split(':');
999
1000        name = (type == 'ns') ? ':' : '';
1001
1002        for (let i = 0; i < names.length; i++) {
1003            if (names[i] != '') {
1004                /* ECMA regexp doesn't support POSIX character classes, so [a-zA-Z] is used instead of [[:alpha:]] */
1005                if (names[i].match(/^[a-zA-Z]\w*$/) == null) {
1006                    name = '';
1007                    break;
1008                }
1009
1010                name += (type == 'ns') ? names[i] + ':' : ':' + names[i];
1011            }
1012        }
1013
1014        if (name == '') {
1015            throw locale.getString('invalid_' + type + '_name');
1016        }
1017
1018        if (existing.has(name)) {
1019            throw locale.getString(type + '_name_exists', name);
1020        }
1021
1022        return name;
1023    }
1024
1025    return {
1026        initialize
1027    }
1028})();
1029
1030
1031jQuery(function () {
1032    if (jQuery('#refnotes-config').length != 0) {
1033        refnotes_admin.initialize();
1034    }
1035});
1036