root/branches/release-28/mt-static/mt.js @ 1285

Revision 1285, 94.4 kB (checked in by auno, 23 months ago)

Fixed not to show drop down menu on pop up window. BugzID:66576

  • Property svn:mime-type set to text/javascript
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
3# This program is distributed under the terms of the
4# GNU General Public License, version 2.
5#
6# $Id$
7*/
8
9var pager;
10var CMSScriptURI;
11var ScriptURI;
12var ScriptBaseURI;
13var StaticURI;
14var HelpBaseURI;
15var Lexicon = {};
16var itemset_options = {};
17
18if ((!(navigator.appVersion.indexOf('MSIE') != -1) &&
19      (parseInt(navigator.appVersion)==4))) {
20    document.write("<style type=\"text/css\">");
21    document.write("body { margin-top: -8px; margin-left: -8px; }"); 
22    document.write("</style>");
23}
24
25var origWidth, origHeight;
26if ((navigator.appName == 'Netscape') &&
27    (parseInt(navigator.appVersion) == 4)) {
28    origWidth = innerWidth;
29    origHeight = innerHeight;
30    window.onresize = restore;
31}
32
33function restore () {
34    if (innerWidth != origWidth || innerHeight != origHeight)
35        location.reload();
36}
37
38function doRebuild (blogID, otherParams) {
39    window.open(CMSScriptURI + '?__mode=rebuild_confirm&blog_id=' + blogID + '&' + otherParams, 'rebuild', 'width=400,height=400,resizable=yes');
40}
41
42function openManual (section, page) {
43    var url;
44    if (page)
45        url = HelpBaseURI + 'help/' + section + '/' + page + '/';
46    else if (section)
47        url = HelpBaseURI + 'help/' + section + '/';
48    else
49        url = HelpBaseURI + 'help/';
50    window.open(url, 'mt_help', 
51'scrollbars=yes,status=yes,resizable=yes,toolbar=yes,location=yes,menubar=yes');
52    return false;
53}
54
55function countMarked (f, nameRestrict) {
56    var count = 0;
57    var e = f.id;
58    if (!e) return 0;
59    if (e.type && e.type == 'hidden') return 1;
60    if (e.value && e.checked)
61        count++;
62    else
63    if (nameRestrict) {
64        for (i=0; i<e.length; i++)
65            if (e[i].checked && (e[i].name == nameRestrict))
66                count++;
67    } else {
68        for (i=0; i<e.length; i++)
69            if (e[i].checked)
70                count++;
71    }
72   return count;
73}
74
75//For make-js script
76//trans('delete');
77//trans('remove');
78//trans('enable');
79//trans('disable');
80function doRemoveItems (f, singular, plural, nameRestrict, args, params) {
81    if (params && (typeof(params) == 'string')) {
82        params = { 'mode': params };
83    } else if (!params) {
84        params = {}
85    }
86    var verb = params['verb'] || trans('delete');
87    var mode = params['mode'] || 'delete';
88    var object_type;
89    if (params['type']) {
90        object_type = params['type'];
91    } else {
92        for (var i = 0; i < f.childNodes.length; i++) {
93            if (f.childNodes[i].name == '_type') {
94                object_type = f.childNodes[i].value;
95                break;
96            }
97        }
98    }
99    var count = countMarked(f, nameRestrict);
100    if (!count) {
101        alert(params['none_prompt'] || trans('You did not select any [_1] to [_2].', plural, verb));
102        return false;
103    }
104    var singularMessage = params['singular_prompt'] || trans('Are you sure you want to [_2] this [_1]?');
105    var pluralMessage = params['plural_prompt'] || trans('Are you sure you want to [_3] the [_1] selected [_2]?');
106    if (object_type == 'role') {
107        singularMessage = trans('Are you certain you want to remove this role? By doing so you will be taking away the permissions currently assigned to any users and groups associated with this role.');
108        pluralMessage = trans('Are you certain you want to remove these [_1] roles? By doing so you will be taking away the permissions currently assigned to any users and groups associated with these roles.');
109    }
110    if (confirm(count == 1 ? trans(singularMessage, singular, verb) : trans(pluralMessage, count, plural, verb))) {
111        return doForMarkedInThisWindow(f, singular, plural, nameRestrict, mode, args);
112    }
113}
114
115/* Widget support functions */
116// function addWidget(el, f) {
117//     if (!TC.Client) return;
118//     // Add a new widget to the top of the 'el' element
119//     var args = DOM.getFormData( f );
120//     args['json'] = '1';
121//     TC.Client.call({
122//         'load': function(c) { addWidgetToPage(el, c); },
123//         'error': function() { showMsg("Error adding widget.", "widget-updated", "alert"); },
124//         'method': 'POST',
125//         'uri': ScriptURI,
126//         'arguments': args
127//     });
128//     return false;
129// }
130//
131// function addWidgetToPage(el, c) {
132//     el = TC.elementOrId(el);
133//     var result;
134//     try {
135//         result = eval('(' + c.responseText + ')');
136//     } catch(e) {
137//         showMsg("Error adding widget.", "widget-updated", "alert");
138//         return;
139//     }
140//     var new_node = document.createElement('div');
141//     new_node.innerHTML = result.result.html;
142//     var next;
143//     if (el.hasChildNodes()) {
144//         if (el.firstChild.nodeType != Node.ELEMENT_NODE)
145//             next = DOM.getNextElement(el.firstChild);
146//         else
147//             next = el.firstChild;
148//     }
149//     if (next) {
150//         el.insertBefore(new_node, next);
151//     } else {
152//         el.appendChild(new_node);
153//     }
154// }
155
156function removeWidget(id) {
157    var f = getByID(id + '-form');
158    f['widget_action'].value = 'remove';
159    if ((f['widget_singular'].value == '1') || (!TC.Client)) {
160        f.submit();
161        return;
162    }
163    var args = DOM.getFormData(f);
164    args['json'] = '1';
165    TC.Client.call({
166        'load': function(c) { removedWidget(id, c); },
167        'error': function() { showMsg("Error removing widget.", "widget-updated", "alert"); },
168        'method': 'POST',
169        'uri': ScriptURI,
170        'arguments': args
171    });
172}
173
174function removedWidget(id, c) {
175    var el = getByID(id);
176    var parent = el.parentNode;
177    parent.removeChild(el);
178}
179
180function updateWidget(id) {
181    var f = getByID(id + "-form");
182    if (!f) return false;
183    f['widget_action'].value = 'save';
184    if (!TC.Client) return true;
185    // if (f['widget_refresh'] && f['widget_refresh'].value) {
186    //     return true;
187    // }
188
189    var args = DOM.getFormData( f );
190    args['json'] = '1';
191    TC.Client.call({
192        'load': function(c, responseText) { updatedWidget(id, responseText); },
193        'error': function() { showMsg("Error updating widget.", "widget-updated", "alert"); },
194        'method': 'POST',
195        'uri': ScriptURI,
196        'arguments': args
197    });
198    return false;
199}
200
201function updatedWidget(id, responseText) {
202    var el = TC.elementOrId(id);
203    var result;
204    try {
205        result = eval('(' + responseText + ')');
206    } catch(e) {
207        showMsg("Error updating widget.", "widget-updated", "alert");
208        return;
209    }
210    if (result.result.html) {
211        // updatePrefs has returned a new widget
212        el.innerHTML = result.result.html;
213    }
214    if (result.result.message) {
215        showMsg(result.result.message, "widget-updated", "info");
216    }
217}
218
219function setObjectStatus (f, singular, plural, new_status, nameRestrict, args) {
220    var count = countMarked(f, nameRestrict);
221    var status_mode = 'enable';
222    var named_status = trans('enable');
223    if (new_status == 0) {
224        status_mode = 'disable';
225        named_status = trans('disable');
226    }
227    if (!count) {
228        alert(trans('You did not select any [_1] to [_2].', plural, named_status));
229        return false;
230    }
231    var toSet = "";
232    for (var i = 0; i < f.childNodes.length; i++) {
233        if (f.childNodes[i].name == '_type') {
234            toSet = f.childNodes[i].value;
235            break;
236        }
237    }
238    if (toSet) {
239        singularMessage = trans('Are you sure you want to [_2] this [_1]?');
240        pluralMessage = trans('Are you sure you want to [_3] the [_1] selected [_2]?');
241        if (confirm(count == 1 ? trans(singularMessage, singular, named_status) : trans(pluralMessage, count, plural, named_status))) {
242            return doForMarkedInThisWindow(f, singular, plural, nameRestrict, status_mode + '_object', args);
243        }
244    } 
245}
246
247function doForMarkedInThisWindow (f, singular, plural, nameRestrict, 
248                                  mode, args, phrase) {
249    var count = countMarked(f, nameRestrict);
250    if (!count) {
251        alert(trans('You did not select any [_1] [_2].', plural, phrase));
252        return false;
253    }
254    f.target = "_top";
255    if (f.elements['itemset_action_input'])
256        f.elements['itemset_action_input'].value = '';
257    if (args) {
258        var opt;
259        var input;
260        if (opt = itemset_options[args['action_name']]) {
261            if (opt['min'] && (count < opt['min'])) {
262                alert(trans('You can only act upon a minimum of [_1] [_2].', opt['min'], plural));
263                return false;
264            } else if (opt['max'] && (count > opt['max'])) {
265                alert(trans('You can only act upon a maximum of [_1] [_2].', opt['max'], plural));
266                return false;
267            } else if (opt['input']) {
268                if (input = prompt(opt['input'])) {
269                    f.elements['itemset_action_input'].value = input;
270                } else {
271                    return false;
272                }
273            } else if (opt['continue_prompt']) {
274                if (!confirm(opt['continue_prompt'])) {
275                    return false;
276                }
277            }
278            if (opt['dialog']) {
279                f.target = "dialog_iframe";
280                show("dialog-container");
281                DOM.addEventListener( document.body, "keypress", dialogKeyPress, true );
282            }
283        }
284        for (var arg in args) {
285            if (f.elements[arg]) f.elements[arg].value = args[arg];
286        }
287    }
288    f.elements["__mode"].value = mode;
289    f.submit();
290}
291
292function submitFormConfirm(f, mode, message) {
293    log.warn('submitFormConfirm() deprecated');
294    if (confirm(message)) {
295        if (f.elements["__mode"] && mode)
296            f.elements["__mode"].value = mode;
297        f.submit();
298    }
299}
300
301function submitForm(f, mode) {
302    log.warn('submitForm() deprecated');
303    if (f.elements["__mode"] && mode)
304        f.elements["__mode"].value = mode;
305    f.submit();
306}
307
308function doPluginAction(f, plural, phrase) {
309    if (!f) {
310        var forms = document.getElementsByTagName( "form" ); 
311        for ( var i = 0; i < forms.length; i++ ) { 
312            var pas = truth( forms[ i ][ 'plugin_action_selector' ] );
313            if (pas) {
314                f = forms[ i ];
315                break;
316            }
317        }
318    }
319    if (!f)
320        return;
321    var sel = f['plugin_action_selector'];
322    if (sel.length && sel[0].options) sel = sel[0];
323    var action = sel.options[sel.selectedIndex].value;
324    if (action == '0' || action == '') {
325        alert(trans('You must select an action.'));
326        return;
327    }
328    if (itemset_options[action]) {
329        if (itemset_options[action]['js']) {
330            return eval(itemset_options[action]['js'] + '(f,action);');
331        }
332    }
333    return doForMarkedInThisWindow(f, '', plural, 'id', 'itemset_action', {'action_name': action}, phrase);
334}
335
336function updatePluginAction(s) {
337    var frm = s.form;
338    frm.elements['plugin_action_selector'].value = s[s.selectedIndex].value;
339    // synchronize top and bottom plugin action selection
340    var el = frm[s.name];
341    for (var i = 0; i < el.length; i++)
342        if (el[i].selectedIndex != s.selectedIndex)
343            el[i].selectedIndex = s.selectedIndex;
344}
345
346function doItemsAreJunk (f, type, plural, nameRestrict) {
347    doForMarkedInThisWindow(f, type, plural, nameRestrict,
348        'handle_junk', {}, trans('to mark as spam'));
349}
350
351function doItemsAreNotJunk (f, type, plural, nameRestrict) {
352    doForMarkedInThisWindow(f, type, plural, nameRestrict,
353        'not_junk', {}, trans('to remove spam status'));
354}
355
356function dialogKeyPress(e) {
357    if (e.keyCode == 27) {
358        // escape key...
359        DOM.removeEventListener( document.body, "keypress", dialogKeyPress, true );
360        closeDialog();
361    }
362}
363
364function openDialog(f, mode, params) {
365    var url = ScriptURI;
366    url += '?__mode=' + mode;
367    if (params) url += '&' + params;
368    url += '&__type=dialog';
369    if (app) app.closeFlyouts();
370    show("dialog-container");
371    // handle escape key for closing modal dialog
372    DOM.addEventListener( document.body, "keypress", dialogKeyPress, true );
373    openDialogUrl(url);
374    if ( document.all && DOM.getElement( "dialog-container" ) ) {
375        DOM.addClassName( "dialog-container", "hidden" );
376        new Timer(function() {
377            DOM.removeClassName( "dialog-container", "hidden" );
378        }, 500, 1 );
379    }
380    return false;
381}
382
383function openDialogUrl(url) {
384    var iframe = getByID("dialog-iframe");
385    var frame_d = iframe.contentDocument;
386    if (!frame_d) {
387        // Sometimes the contentWindow is unavailable because we've just
388        // unhidden the container div that holds the iframe. If this happens
389        // we have to wait for the contentWindow object to be created
390        // before we can access the document within. This may take an extra
391        // try using a setTimeout on this window.
392        if (iframe.contentWindow)
393            frame_d = iframe.contentWindow.document || iframe.document;
394    }
395    if (frame_d) {
396        frame_d.open();
397        frame_d.write("<html><head><style type=\"text/css\">\n"
398            + "#dialog-indicator {\nposition: relative;\ntop: 200px;\n"
399            + "background: url(" + StaticURI + "images/indicator.gif) "
400            + "no-repeat;\nwidth: 66px;\nheight: 66px;\nmargin: 0 auto;"
401            + "\n}\n</style><script type=\"text/javascript\">\n"
402            + "function init() {\ndocument.location = \"" + url + "\";\n}\n"
403            + "if (window.navigator.userAgent.match(/ AppleWebKit\\//))\n"
404            + "window.setTimeout(\"init()\", 1500);\n"
405            + "else window.onload = init;\n</scr"+"ipt></head><body>"
406            + "<div align=\"center\"><div id=\"dialog-indicator\"></div>"
407            + "</div></body></html>");
408        frame_d.close();
409    } else {
410        window.setTimeout("openDialogUrl('" + url + "')", 100);
411    }
412}
413
414function closeDialog(url) {
415    var w = window;
416    while (w.parent && (w.parent != w))
417        w = w.parent;
418    if (url)
419        w.location = url;
420    else
421        hide("dialog-container", w.document);
422    return false;
423}
424
425function getByID(n, d) {
426    if (!d) d = document;
427    if (d.getElementById)
428        return d.getElementById(n);
429    else if (d.all)
430        return d.all[n];
431}
432
433var canFormat = 0;
434if (document.selection ||
435    (typeof(document.createElement("textarea")["setSelectionRange"]) != "undefined"))
436    canFormat = 1;
437
438function getSelected(e) {
439    if (document.selection) {
440        e.focus();
441        var range = document.selection.createRange();
442        return range.text;
443    } else {
444        var length = e.textLength;
445        var start = e.selectionStart;
446        var end = e.selectionEnd;
447        if (end == 1 || end == 2 && length != undefined) end = length;
448        return e.value.substring(start, end);
449    }
450}
451
452function setSelection(e, v) {
453    if (document.selection) {
454        e.focus();
455        var range = document.selection.createRange();
456        range.text = v;
457    } else {
458        var scrollTop = e.scrollTop;
459        var length = e.textLength;
460        var start = e.selectionStart;
461        var end = e.selectionEnd;
462        if (end == 1 || end == 2 && length != undefined) end = length;
463        e.value = e.value.substring(0, start) + v + e.value.substr(end, length);
464        e.selectionStart = start + v.length;
465        e.selectionEnd = start + v.length;
466        e.scrollTop = scrollTop;
467    }
468    e.focus();
469}
470
471function formatStr(e, v) {
472    if (!canFormat) return;
473    var str = getSelected(e);
474    if (str) setSelection(e, '<' + v + '>' + str + '</' + v + '>');
475    return false;
476}
477
478function mtShortCuts(e) {
479    e = e || event;
480    var code;
481    if (e.keyCode) code = e.keyCode;
482    else if (e.which) code = e.which;
483    el = e.target || e.srcElement;
484    if (el.nodeType == 3) el = el.parentNode; // Safari bug
485    if (e.ctrlKey) {
486        switch(e.keyCode) {
487            case 66: // b
488            case 73: // i
489            case 85: // u
490            disableCtrlDefault(e);
491            if (code == '66') formatStr(el, 'strong');
492            if (code == '73') formatStr(el, 'em');
493            if (code == '85') formatStr(el, 'u');
494        }
495    }
496}
497
498function disableCtrlDefault(e) {
499    if(e.preventDefault) {
500        e.preventDefault();
501    } else {
502        e.returnValue = false;
503    }
504    return;
505}
506
507function insertLink(e, isMail) {
508    if (!canFormat) return;
509    var str = getSelected(e);
510    var link = '';
511    if (!isMail) {
512        if (str.match(/^https?:/)) {
513            link = str;
514        } else if (str.match(/^(\w+\.)+\w{2,5}\/?/)) {
515            link = 'http://' + str;
516        } else if (str.match(/ /)) {
517            link = 'http://';
518        } else {
519            link = 'http://' + str;
520        }
521    } else {
522        if (str.match(/@/)) {
523            link = str;
524        }
525    }
526    var my_link = prompt(isMail ? trans('Enter email address:') : trans('Enter URL:'), link);
527    if (my_link != null) {
528         if (str == '') str = my_link;
529         if (isMail) my_link = 'mailto:' + my_link;
530        setSelection(e, '<a href="' + my_link + '">' + str + '</a>');
531    }
532    return false;
533}
534
535function execFilter(f) {
536    var filter_col = f['filter-col'].options[f['filter-col'].selectedIndex].value;
537    var opts = f[filter_col+'-val'].options;
538    var filter_val = '';
539    if (opts) {
540        filter_val = opts[f[filter_col+'-val'].selectedIndex].value;
541    } else if (f[filter_col+'-val'].value) {
542        filter_val = f[filter_col+'-val'].value;
543    }
544    getByID('filter').value = filter_col;
545    getByID('filter_val').value = filter_val;
546    getByID('filter-form').submit();
547    return false;
548}
549
550function setFilterVal(value) {
551    var f = getByID('filter-select-form');
552    if (value == '') return;
553    var filter_col = f['filter-col'].options[f['filter-col'].selectedIndex].value;
554    var val_span = getByID("filter-text-val");
555    if (filter_col) {
556        var filter_fld = f[filter_col+'-val'];
557        if (filter_fld.options) {
558            for (var i = 0; i < filter_fld.options.length; i++) {
559                if (filter_fld.options[i].value == value) {
560                    value = filter_fld.options[i].text;
561                    // strip off any leading spacing found on category lists
562                    value = value.replace(/^(\xA0 )+/, '');
563                    filter_fld.selectedIndex = i;
564                    if (val_span)
565                        val_span.innerHTML = '<strong>' + value + '</strong>';
566                    break;
567                }
568            }
569        } else if (filter_fld.value) {
570            filter_fld.value = value;
571            if (val_span)
572                val_span.innerHTML = '<strong>' + value + '</strong>';
573        }
574    }
575}
576
577function toggleDisplayOptions() {
578    return toggleActive('display-options');
579}
580
581function toggleEntryDisplayOptions() {
582    return toggleActive('display-options-widget');
583}
584
585function toggleActive( id ) {
586    var div = DOM.getElement( id );
587    if ( !div )
588        return false;
589    if ( DOM.hasClassName( div, 'active' ) )
590        DOM.removeClassName( div, 'active' );
591    else
592        DOM.addClassName( div, 'active' );
593    return false;
594}
595
596function toggleHidden( id ) {
597    var div = DOM.getElement( id );
598    if ( !div )
599        return false;
600    if ( DOM.hasClassName( div, 'hidden' ) )
601        DOM.removeClassName( div, 'hidden' );
602    else
603        DOM.addClassName( div, 'hidden' );
604    return false;
605}
606
607function tabToggle(selectedTab, tabs) {
608    log.warn('tabToggle is deprecated. use mt tab delegate');
609    for (var i = 0; i < tabs.length; i++) {
610        var tabObject = getByID(tabs[i] + '-tab');
611        var contentObject = getByID(tabs[i] + '-panel');
612           
613        if (tabObject && contentObject) {
614            if (tabs[i] == selectedTab) {
615                DOM.addClassName( tabObject, 'selected-tab' );
616                DOM.addClassName( contentObject, 'selected-tab-panel' );
617            } else {
618                DOM.removeClassName( tabObject, 'selected-tab' );
619                DOM.removeClassName( contentObject, 'selected-tab-panel' );
620            }
621        }
622    }
623    return false;
624}
625
626function show(id, d, style) {
627    var el = getByID(id, d);
628    if (!el) return;
629    if ( DOM.hasClassName( el, "hidden" ) ) {
630        DOM.removeClassName ( el, "hidden");
631    } else {
632        el.style.display = style ? style : 'block';
633    }
634    /* hack */
635    if ( DOM.hasClassName( el, "autolayout-height-parent" ) )
636        DOM.setHeight( el, finiteInt( el.parentNode.clientHeight ) );
637}
638
639function hide(id, d) {
640    var el = getByID(id, d);
641    if (!el) return;
642    if ( !DOM.hasClassName( el, "hidden" ) ) {
643        DOM.addClassName ( el, "hidden");
644    } else {
645        el.style.display = 'none';
646    }
647}
648
649function showReply(id, d, style) {
650    var el = getByID(id, d);
651    if (!el) return;
652    el.style.visibility = style ? style : 'visible';
653}
654
655function hideReply(id, d) {
656    var el = getByID(id, d);
657    if (!el) return;
658    el.style.visibility = 'hidden';
659}
660
661function toggleSubPrefs(c) {
662    var div = TC.elementOrId((c.name || c.id)+"-prefs") || TC.elementOrId((c.name || c.id)+'_prefs');
663    if (div) {
664        if (c.type) {
665            var on = c.type == 'checkbox' ? c.checked : c.value != 0;
666            if (on) {
667                TC.removeClassName(div, "hidden");
668            } else {
669                TC.addClassName(div, "hidden");
670            }
671            // div.style.display = on ? "block" : "none";
672        } else {
673            var on = div.style.display && div.style.display != "none";
674            if (on) {
675                TC.addClassName(div, "hidden");
676            } else {
677                TC.removeClassName(div, "hidden");
678            }
679            // div.style.display = on ? "none" : "block";
680        }
681    }
682    return false;
683}
684
685function toggleAdvancedPrefs(evt, c) {
686    evt = evt || window.event;
687    var id;
688    var obj;
689    if (!c || (typeof c != 'string')) {
690        c = c || evt.target || evt.srcElement;
691        id = c.id || c.name;
692        obj = c;
693    } else {
694        id = c;
695    }
696    var div = getByID( id + '-advanced');
697    if (div) {
698        if (obj) {
699            var shiftKey = evt ? evt.shiftKey : undefined;
700                if (evt && shiftKey && obj.type == 'checkbox')
701                obj.checked = true;
702            var on = obj.type == 'checkbox' ? obj.checked : obj.value != 0;
703            if (on && shiftKey) {
704                if (div.style.display == "block")
705                    div.style.display = "none";
706                else
707                    div.style.display = "block";
708            } else {
709                div.style.display = "none";
710            }
711        } else {
712            if (div.style.display == "block")
713                div.style.display = "none";
714            else
715                div.style.display = "block";
716        }
717    }
718    return false;
719}
720
721function trans(str) {
722    if (Lexicon && Lexicon[str])
723        str = Lexicon[str];
724    if (arguments.length > 1)
725        for (var i = 1; i <= arguments.length; i++) {
726            /* This matches [_#] or [_#:comment] */
727            str = str.replace(new RegExp('\\[_' + i + '(?:\:[^\\]]+)?\\]', 'g'), arguments[i]);
728            var re = new RegExp('\\[quant,_' + i + ',(.+?)(?:,(.+?))?(?:\:[^\\]]+)?\\]');
729            var matches;
730            while (matches = str.match(re)) {
731                if (arguments[i] != 1)
732                    str = str.replace(re, arguments[i] + ' ' +
733                        ((typeof(matches[2]) != 'undefined') ? matches[2]
734                                                               : matches[1]
735                                                                 + 's'));
736                else
737                    str = str.replace(re, arguments[i] + ' ' + matches[1]);
738            }
739        }
740    return str;
741}
742
743function junkScoreNudge(amount, id, max) {
744    if (max == undefined) max = 10;
745    var fld = getByID(id);
746    score = fld.value;
747    score.replace(/\+/, '');
748    score = parseFloat(score) + amount;
749    if (isNaN(score)) score = amount;
750    if (score > max) score = max;
751    if (score < 0) score = 0;
752    fld.value = score;
753    return false;
754}
755
756var dirify_table = {
757    "\u00C0": 'A',    // A`
758    "\u00E0": 'a',    // a`
759    "\u00C1": 'A',    // A'
760    "\u00E1": 'a',    // a'
761    "\u00C2": 'A',    // A^
762    "\u00E2": 'a',    // a^
763    "\u0102": 'A',    // latin capital letter a with breve
764    "\u0103": 'a',    // latin small letter a with breve
765    "\u00C6": 'AE',   // latin capital letter AE
766    "\u00E6": 'ae',   // latin small letter ae
767    "\u00C5": 'A',    // latin capital letter a with ring above
768    "\u00E5": 'a',    // latin small letter a with ring above
769    "\u0100": 'A',    // latin capital letter a with macron
770    "\u0101": 'a',    // latin small letter a with macron
771    "\u0104": 'A',    // latin capital letter a with ogonek
772    "\u0105": 'a',    // latin small letter a with ogonek
773    "\u00C4": 'A',    // A:
774    "\u00E4": 'a',    // a:
775    "\u00C3": 'A',    // A~
776    "\u00E3": 'a',    // a~
777    "\u00C8": 'E',    // E`
778    "\u00E8": 'e',    // e`
779    "\u00C9": 'E',    // E'
780    "\u00E9": 'e',    // e'
781    "\u00CA": 'E',    // E^
782    "\u00EA": 'e',    // e^
783    "\u00CB": 'E',    // E:
784    "\u00EB": 'e',    // e:
785    "\u0112": 'E',    // latin capital letter e with macron
786    "\u0113": 'e',    // latin small letter e with macron
787    "\u0118": 'E',    // latin capital letter e with ogonek
788    "\u0119": 'e',    // latin small letter e with ogonek
789    "\u011A": 'E',    // latin capital letter e with caron
790    "\u011B": 'e',    // latin small letter e with caron
791    "\u0114": 'E',    // latin capital letter e with breve
792    "\u0115": 'e',    // latin small letter e with breve
793    "\u0116": 'E',    // latin capital letter e with dot above
794    "\u0117": 'e',    // latin small letter e with dot above
795    "\u00CC": 'I',    // I`
796    "\u00EC": 'i',    // i`
797    "\u00CD": 'I',    // I'
798    "\u00ED": 'i',    // i'
799    "\u00CE": 'I',    // I^
800    "\u00EE": 'i',    // i^
801    "\u00CF": 'I',    // I:
802    "\u00EF": 'i',    // i:
803    "\u012A": 'I',    // latin capital letter i with macron
804    "\u012B": 'i',    // latin small letter i with macron
805    "\u0128": 'I',    // latin capital letter i with tilde
806    "\u0129": 'i',    // latin small letter i with tilde
807    "\u012C": 'I',    // latin capital letter i with breve
808    "\u012D": 'i',    // latin small letter i with breve
809    "\u012E": 'I',    // latin capital letter i with ogonek
810    "\u012F": 'i',    // latin small letter i with ogonek
811    "\u0130": 'I',    // latin capital letter with dot above
812    "\u0131": 'i',    // latin small letter dotless i
813    "\u0132": 'IJ',   // latin capital ligature ij
814    "\u0133": 'ij',   // latin small ligature ij
815    "\u0134": 'J',    // latin capital letter j with circumflex
816    "\u0135": 'j',    // latin small letter j with circumflex
817    "\u0136": 'K',    // latin capital letter k with cedilla
818    "\u0137": 'k',    // latin small letter k with cedilla
819    "\u0138": 'k',    // latin small letter kra
820    "\u0141": 'L',    // latin capital letter l with stroke
821    "\u0142": 'l',    // latin small letter l with stroke
822    "\u013D": 'L',    // latin capital letter l with caron
823    "\u013E": 'l',    // latin small letter l with caron
824    "\u0139": 'L',    // latin capital letter l with acute
825    "\u013A": 'l',    // latin small letter l with acute
826    "\u013B": 'L',    // latin capital letter l with cedilla
827    "\u013C": 'l',    // latin small letter l with cedilla
828    "\u013F": 'l',    // latin capital letter l with middle dot
829    "\u0140": 'l',    // latin small letter l with middle dot
830    "\u00D2": 'O',    // O`
831    "\u00F2": 'o',    // o`
832    "\u00D3": 'O',    // O'
833    "\u00F3": 'o',    // o'
834    "\u00D4": 'O',    // O^
835    "\u00F4": 'o',    // o^
836    "\u00D6": 'O',    // O:
837    "\u00F6": 'o',    // o:
838    "\u00D5": 'O',    // O~
839    "\u00F5": 'o',    // o~
840    "\u00D8": 'O',    // O/
841    "\u00F8": 'o',    // o/
842    "\u014C": 'O',    // latin capital letter o with macron
843    "\u014D": 'o',    // latin small letter o with macron
844    "\u0150": 'O',    // latin capital letter o with double acute
845    "\u0151": 'o',    // latin small letter o with double acute
846    "\u014E": 'O',    // latin capital letter o with breve
847    "\u014F": 'o',    // latin small letter o with breve
848    "\u0152": 'OE',   // latin capital ligature oe
849    "\u0153": 'oe',   // latin small ligature oe
850    "\u0154": 'R',    // latin capital letter r with acute
851    "\u0155": 'r',    // latin small letter r with acute
852    "\u0158": 'R',    // latin capital letter r with caron
853    "\u0159": 'r',    // latin small letter r with caron
854    "\u0156": 'R',    // latin capital letter r with cedilla
855    "\u0157": 'r',    // latin small letter r with cedilla
856    "\u00D9": 'U',    // U`
857    "\u00F9": 'u',    // u`
858    "\u00DA": 'U',    // U'
859    "\u00FA": 'u',    // u'
860    "\u00DB": 'U',    // U^
861    "\u00FB": 'u',    // u^
862    "\u00DC": 'U',    // U:
863    "\u00FC": 'u',    // u:
864    "\u016A": 'U',    // latin capital letter u with macron
865    "\u016B": 'u',    // latin small letter u with macron
866    "\u016E": 'U',    // latin capital letter u with ring above
867    "\u016F": 'u',    // latin small letter u with ring above
868    "\u0170": 'U',    // latin capital letter u with double acute
869    "\u0171": 'u',    // latin small letter u with double acute
870    "\u016C": 'U',    // latin capital letter u with breve
871    "\u016D": 'u',    // latin small letter u with breve
872    "\u0168": 'U',    // latin capital letter u with tilde
873    "\u0169": 'u',    // latin small letter u with tilde
874    "\u0172": 'U',    // latin capital letter u with ogonek
875    "\u0173": 'u',    // latin small letter u with ogonek
876    "\u00C7": 'C',    // ,C
877    "\u00E7": 'c',    // ,c
878    "\u0106": 'C',    // latin capital letter c with acute
879    "\u0107": 'c',    // latin small letter c with acute
880    "\u010C": 'C',    // latin capital letter c with caron
881    "\u010D": 'c',    // latin small letter c with caron
882    "\u0108": 'C',    // latin capital letter c with circumflex
883    "\u0109": 'c',    // latin small letter c with circumflex
884    "\u010A": 'C',    // latin capital letter c with dot above
885    "\u010B": 'c',    // latin small letter c with dot above
886    "\u010E": 'D',    // latin capital letter d with caron
887    "\u010F": 'd',    // latin small letter d with caron
888    "\u0110": 'D',    // latin capital letter d with stroke
889    "\u0111": 'd',    // latin small letter d with stroke
890    "\u00D1": 'N',    // N~
891    "\u00F1": 'n',    // n~
892    "\u0143": 'N',    // latin capital letter n with acute
893    "\u0144": 'n',    // latin small letter n with acute
894    "\u0147": 'N',    // latin capital letter n with caron
895    "\u0148": 'n',    // latin small letter n with caron
896    "\u0145": 'N',    // latin capital letter n with cedilla
897    "\u0146": 'n',    // latin small letter n with cedilla
898    "\u0149": 'n',    // latin small letter n preceded by apostrophe
899    "\u014A": 'N',    // latin capital letter eng
900    "\u014B": 'n',    // latin small letter eng
901    "\u00DF": 'ss',   // double-s
902    "\u015A": 'S',    // latin capital letter s with acute
903    "\u015B": 's',    // latin small letter s with acute
904    "\u0160": 'S',    // latin capital letter s with caron
905    "\u0161": 's',    // latin small letter s with caron
906    "\u015E": 'S',    // latin capital letter s with cedilla
907    "\u015F": 's',    // latin small letter s with cedilla
908    "\u015C": 'S',    // latin capital letter s with circumflex
909    "\u015D": 's',    // latin small letter s with circumflex
910    "\u0218": 'S',    // latin capital letter s with comma below
911    "\u0219": 's',    // latin small letter s with comma below
912    "\u0164": 'T',    // latin capital letter t with caron
913    "\u0165": 't',    // latin small letter t with caron
914    "\u0162": 'T',    // latin capital letter t with cedilla
915    "\u0163": 't',    // latin small letter t with cedilla
916    "\u0166": 'T',    // latin capital letter t with stroke
917    "\u0167": 't',    // latin small letter t with stroke
918    "\u021A": 'T',    // latin capital letter t with comma below
919    "\u021B": 't',    // latin small letter t with comma below
920    "\u0192": 'f',    // latin small letter f with hook
921    "\u011C": 'G',    // latin capital letter g with circumflex
922    "\u011D": 'g',    // latin small letter g with circumflex
923    "\u011E": 'G',    // latin capital letter g with breve
924    "\u011F": 'g',    // latin small letter g with breve
925    "\u0120": 'G',    // latin capital letter g with dot above
926    "\u0121": 'g',    // latin small letter g with dot above
927    "\u0122": 'G',    // latin capital letter g with cedilla
928    "\u0123": 'g',    // latin small letter g with cedilla
929    "\u0124": 'H',    // latin capital letter h with circumflex
930    "\u0125": 'h',    // latin small letter h with circumflex
931    "\u0126": 'H',    // latin capital letter h with stroke
932    "\u0127": 'h',    // latin small letter h with stroke
933    "\u0174": 'W',    // latin capital letter w with circumflex
934    "\u0175": 'w',    // latin small letter w with circumflex
935    "\u00DD": 'Y',    // latin capital letter y with acute
936    "\u00FD": 'y',    // latin small letter y with acute
937    "\u0178": 'Y',    // latin capital letter y with diaeresis
938    "\u00FF": 'y',    // latin small letter y with diaeresis
939    "\u0176": 'Y',    // latin capital letter y with circumflex
940    "\u0177": 'y',    // latin small letter y with circumflex
941    "\u017D": 'Z',    // latin capital letter z with caron
942    "\u017E": 'z',    // latin small letter z with caron
943    "\u017B": 'Z',    // latin capital letter z with dot above
944    "\u017C": 'z',    // latin small letter z with dot above
945    "\u0179": 'Z',    // latin capital letter z with acute
946    "\u017A": 'z'     // latin small letter z with acute
947};
948
949function dirify (s) {
950    s = s.replace(/<[^>]+>/g, '');
951    for (var p in dirify_table)
952        if (s.indexOf(p) != -1)
953            s = s.replace(new RegExp(p, "g"), dirify_table[p]);
954    s = s.toLowerCase();
955    s = s.replace(/&[^;\s]+;/g, '');
956    s = s.replace(/[^-a-z0-9_ ]/g, '');
957    s = s.replace(/\s+/g, '_');
958    s = s.replace(/_+$/, '');
959    s = s.replace(/_+/g, '_');
960    return s;
961}
962
963function setElementValue(domID, newVal) {
964    getByID(domID).value = newVal;
965}
966
967/* pager and datasource */
968
969/***
970 * Datasource class
971 * A class for navigating and displaying data from an AJAX datasource.
972 * Methods:
973 *   constructor(el, datatype): Creates a new datasource using DOM
974 *     element 'el' as a container for the data (table rows typically)
975 *     and datatype is used to communicate the '_type' parameter to
976 *     the server.
977 *   setPager(pager): Sets a Pager class object which is refreshed
978 *     upon receiving new data.
979 *   search(string): Invokes a search on the datasource.
980 *   navigate(offset): Used to navigate to a particular offset within
981 *     the dataset.
982 */
983Datasource = new Class(Object, {
984    init: function(el, datatype) {
985        // this.id = id;
986        // this.document = doc || document;
987        this.element = TC.elementOrId(el);
988        this.searching = false;
989        this.navigating = false;
990        this.type = datatype;
991        this.onUpdate = null;
992    },
993    setPager: function(pager, pager2) {
994        this.pager = pager;
995        if (pager2) this.pager2 = pager2
996        if (pager) pager.datasource = this;
997        if (pager2) pager2.datasource = this;
998        if (pager) pager.render();
999        if (pager2) pager2.render();
1000    },
1001    search: function(str) {
1002        if (this.searching) return;
1003
1004        var doc = TC.getOwnerDocument(this.element);
1005        var args = doc.location.search;
1006        args = args.replace(/^\?/, '');
1007        args = args.replace(/&?offset=\d+/, '');
1008        args = 'search=' + escape(str) + (args ? '&' + args : '') + '&json=1';
1009        if (this.type) {
1010            args = args.replace(/&?_type=\w+/, '');
1011            args += '&_type=' + this.type;
1012        }
1013
1014        this.searching = true;
1015        if (this.pager)
1016            this.pager.render();
1017        if (this.pager2)
1018            this.pager2.render();
1019        var self = this;
1020        TC.Client.call({
1021            'load': function(c,r) { self.searched(r); },
1022            'error': function() { alert("Error during search."); self.searched(null); },
1023            'method': 'POST',
1024            'uri': ScriptURI,
1025            'arguments': args
1026        });
1027    },
1028    searched: function(c) {
1029        this.searching = false;
1030        if (c) {
1031            try {
1032                data = eval('(' + c + ')');
1033                this.update(data['html']);
1034                if (this.pager)
1035                    this.pager.setState({});
1036                if (this.pager2)
1037                    this.pager2.setState({});
1038            } catch (e) {
1039                alert("Error in response: " + e);
1040                if (this.pager)
1041                    this.pager.render();
1042                if (this.pager2)
1043                    this.pager2.render();
1044            }
1045        } else {
1046            if (this.pager)
1047                this.pager.render();
1048            if (this.pager2)
1049                this.pager2.render();
1050        }
1051    },
1052    update: function(html) {
1053        if (!this.element) return;
1054        this.element.innerHTML = html;
1055        this.updated();
1056    },
1057    updated: function() {
1058        if (this.onUpdate) this.onUpdate(this);
1059    },
1060    navigate: function(offset) {
1061        if (offset == null) return;
1062        if (this.navigating) return;
1063
1064        var doc = TC.getOwnerDocument(this.element);
1065        var args = doc.location.search;
1066        args = args.replace(/^\?/, '');
1067        //args = args.replace(/&?search=[^&]+/, '');
1068        //args = args.replace(/&?do_search=1/, '');
1069        args = args.replace(/&?offset=\d+/, '');
1070        args = 'offset=' + offset + (args ? '&' + args : '') + '&json=1';
1071        if (this.type) {
1072            args = args.replace(/&?_type=\w+/, '');
1073            args = args + '&_type=' + this.type;
1074        }
1075
1076        this.navigating = true;
1077        if (this.pager)
1078            this.pager.render();
1079        if (this.pager2)
1080            this.pager2.render();
1081        var self = this;
1082        TC.Client.call({
1083            'load': function(c,r) { self.navigated(r); },
1084            'error': function() { alert("Error in request."); self.navigated(null); },
1085            'method': 'POST',
1086            'uri': ScriptURI,
1087            'arguments': args
1088        });
1089        return false;
1090    },
1091    navigated: function(c) {
1092        var data;
1093        this.navigating = false;
1094        if (c) {
1095            try {
1096                data = eval('(' + c + ')');
1097                this.update(data['html']);
1098                if (this.pager)
1099                    this.pager.setState(data['pager']);
1100                if (this.pager2)
1101                    this.pager2.setState(data['pager']);
1102            } catch (e) {
1103                alert("Error in response: " + e);
1104                if (this.pager)
1105                    this.pager.render();
1106                if (this.pager2)
1107                    this.pager2.render();
1108            }
1109        } else {
1110            if (this.pager) this.pager.render();
1111            if (this.pager2) this.pager2.render();
1112        }
1113    }
1114});
1115//These two lines are to translate phrases in list_tags.tmpl
1116//trans("The tag '[_2]' already exists. Are you sure you want to merge '[_1]' with '[_2]'?");
1117//trans("The tag '[_2]' already exists. Are you sure you want to merge '[_1]' with '[_2]' across all weblogs?");
1118
1119/***
1120 * Pager class
1121 * Expects a 'state' object containing:
1122 *   offset: offset into listing (10, means first row displayed is 11)
1123 *   listTotal: total number of rows in dataset
1124 *   rows: number of rows being displayed
1125 *   chronological: boolean, whether listing is reverse-chronological
1126 *     or not.
1127 *  Methods:
1128 *    constructor(el): constructs using DOM element el as a container
1129 *    setDatasource(ds): used to assign a datasource object
1130 *    setState(state): used to update state settings
1131 *    previous: navigates datasource to previous page
1132 *    next: navigates datasource to next page
1133 *    first: navigates datasource to first page
1134 *    last: navigates datasource to last page
1135 *    previousOffset: calculates and returns offset for previous page
1136 *    nextOffset: calculates and returns offset for next page
1137 *    lastOffset: calculates and returns offset for 'last' page
1138 *    render: refreshes the pagination controls
1139 */
1140Pager = new Class(Object, {
1141    init: function(el) {
1142        this.element = TC.elementOrId(el);
1143        this.state = {};
1144    },
1145    setDatasource: function(ds) {
1146        this.datasource = ds;
1147        this.render();
1148    },
1149    setState: function(state) {
1150        this.state = state;
1151        this.render();
1152    },
1153    previous: function(e) {
1154        this.navigate(this.previousOffset());
1155        return TC.stopEvent(e || window.event);
1156    },
1157    navigate: function(offset) {
1158        if (offset == null) return;
1159        if (this.datasource)
1160            return this.datasource.navigate(offset);
1161        // traditional navigation...
1162        var doc = TC.getOwnerDocument(this.element);
1163        new_loc = doc.location.href;
1164        if (this.state.method == 'POST') {
1165            new_loc += '?' + this.state.return_args;
1166        }
1167        new_loc = new_loc.replace(/&?offset=\d+/, '');
1168        new_loc += '&offset=' + offset;
1169        window.location = new_loc;
1170        return false;
1171    },
1172    previousOffset: function() {
1173        if (this.state.offset > 0) {
1174            var offset = this.state.offset - this.state.limit;
1175            if (offset < 0)
1176                offset = 0;
1177            return offset;
1178        }
1179        return null;
1180    },
1181    nextOffset: function() {
1182        if (this.state.listTotal) {
1183            var listStart = (this.state.offset ? this.state.offset : 0) + 1;
1184            var offset = (this.state.offset ? this.state.offset : 0) + this.state.rows;
1185            if (offset >= this.state.listTotal) {
1186                offset = null;
1187            }
1188            return offset;
1189        }
1190        return null;
1191    },
1192    lastOffset: function() {
1193        var offset = 0;
1194        if (this.state.listTotal) {
1195            var listStart = (this.state.offset ? this.state.offset : 0) + 1;
1196            var listEnd = (this.state.offset ? this.state.offset : 0) + this.state.rows;
1197            if (listEnd >= this.state.listTotal) {
1198                offset = null;
1199            } else {
1200                offset = this.state.listTotal - this.state.rows;
1201                if (offset < listStart)
1202                    offset = null;
1203            }
1204            return offset;
1205        }
1206        return null;
1207    },
1208    next: function(e) {
1209        this.navigate(this.nextOffset());
1210        return TC.stopEvent(e || window.event);
1211    },
1212    first: function(e) {
1213        this.navigate(0);
1214        return TC.stopEvent(e || window.event);
1215    },
1216    last: function(e) {
1217        this.navigate(this.lastOffset());
1218        return TC.stopEvent(e || window.event);
1219    },
1220    render: function() {
1221        if (!this.element) return;
1222
1223        /*
1224        This long method is concerned with creating the elements of
1225        the pagination control. It refreshes the controls based on
1226        the 'state' member of the Pager object. This control is
1227        typically tied to a Datasource object. So the navigation
1228        links of the control will influence the Datasource.
1229        Likewise, upon navigating the Datasource, it will invoke
1230        the pager to refresh when the data has been updated.
1231
1232        pager.rows (number of rows shown)
1233        pager.listTotal (total number of rows in datasource)
1234        pager.offset (offset currently used)
1235        pager.chronological (boolean, whether the listing is chronological or not)
1236        */
1237        var html = '';
1238        /* TODO - this can all be replaced with a js template */
1239        if (this.datasource && this.datasource.navigating) {
1240            // TODO: change this to use a CSS class instead.
1241            html = "<div>" + trans('Loading...') + " <img src=\"" + StaticURI + "images/indicator.white.gif\" height=\"10\" width=\"10\" alt=\"...\" /></div>";
1242            this.element.innerHTML = html;
1243        } else if ((this.state.rows != null) && (this.state.rows > 0)) {
1244            this.element.innerHTML = '';
1245            var listStart = (this.state.offset ? this.state.offset : 0) + 1;
1246            var listEnd = (this.state.offset ? this.state.offset : 0) + this.state.rows;
1247
1248            var doc = TC.getOwnerDocument(this.element);
1249            var self = this;
1250            // pagination control structure
1251            if (this.state.offset > 0) {
1252                var link = doc.createElement('a');
1253                link.href = 'javascript:void(0)';
1254                link.onclick = function(e) { return self.first(e) };
1255                link.className = 'start';
1256                link.innerHTML = '<em>&lt;&lt;</em>&nbsp;';
1257                this.element.appendChild(link);
1258            } else {
1259                var txt = doc.createElement('span');
1260                txt.className = 'start-disabled';
1261                txt.innerHTML = '<em>&lt;&lt;</em>&nbsp;';
1262                this.element.appendChild(txt);
1263            }
1264            if (this.previousOffset() != null) {
1265                var link = doc.createElement('a');
1266                link.href = 'javascript:void(0)';
1267                link.onclick = function(e) { return self.previous(e) };
1268                link.className = 'to-start';
1269                link.innerHTML = '<em>&lt;</em>&nbsp;';
1270                this.element.appendChild(link);
1271            } else {
1272                var txt = doc.createElement('span');
1273                txt.className = 'to-start-disabled';
1274                txt.innerHTML = '<em>&lt;</em>&nbsp;';
1275                this.element.appendChild(txt);
1276            }
1277            var showing = doc.createElement('span');
1278            showing.className = 'current-rows';
1279            if (this.state.listTotal)
1280                showing.innerHTML = trans('[_1] &ndash; [_2] of [_3]', listStart, listEnd, this.state.listTotal);
1281            else
1282                showing.innerHTML = trans('[_1] &ndash; [_2]', listStart, listEnd);
1283            this.element.appendChild(showing);
1284            if (this.nextOffset() != null) {
1285                var link = doc.createElement('a');
1286                link.href = 'javascript:void(0)';
1287                link.onclick = function(e) { return self.next(e) };
1288                link.className = 'to-end';
1289                link.innerHTML = '&nbsp;<em>&gt;</em>';
1290                this.element.appendChild(link);
1291            } else {
1292                var txt = doc.createElement('span');
1293                txt.className = 'to-end-disabled';
1294                txt.innerHTML = '&nbsp;<em>&gt;</em>';
1295                this.element.appendChild(txt);
1296            }
1297            if (this.lastOffset() != null) {
1298                var link = doc.createElement('a');
1299                link.href = 'javascript:void(0)';
1300                link.onclick = function(e) { return self.last(e) };
1301                link.className = 'end';
1302                link.innerHTML = '&nbsp;<em>&gt;&gt;</em>';
1303                this.element.appendChild(link);
1304            } else {
1305                var txt = doc.createElement('span');
1306                txt.className = 'end-disabled';
1307                txt.innerHTML = '&nbsp;<em>&gt;&gt;</em>';
1308                this.element.appendChild(txt);
1309            }
1310        } else {
1311            this.element.innerHTML = '';
1312        }
1313    }
1314});
1315
1316
1317MT = {};
1318
1319
1320if ( window.App ) {
1321
1322App.singletonConstructor =
1323MT.App = new Class( App, {
1324 
1325
1326    NAMESPACE: "mt",
1327    changed: false,
1328    autoSaveDelay: 15000, /* ms */
1329
1330
1331    initComponents: function() {
1332        arguments.callee.applySuper( this, arguments );
1333        this.openFlyouts = [];
1334
1335        this.setDelegate( "navMenu", new this.constructor.NavMenu() );
1336
1337        this.initFormElements();
1338       
1339        if ( this.constructor.Resizer ) {
1340            this.setDelegate( "resizer", new this.constructor.Resizer( this.getIndirectMethod( "resizeComplete" ) ) );
1341            this.setDelegateListener( "eventMouseUp", "resizer" );
1342            this.setDelegateListener( "eventMouseMove", "resizer" );
1343        }
1344
1345        if ( this.constructor.DefaultValue )
1346            this.setDelegate( "defaultValue", new this.constructor.DefaultValue() );
1347       
1348        if ( this.constructor.TabContainer )
1349            this.setDelegate( "tabContainer", new this.constructor.TabContainer() );
1350           
1351        var forms = DOM.getElementsByTagAndAttribute( this.document, "form", "mt:auto-save" );
1352        if ( forms.length )
1353            window.onbeforeunload = this.getIndirectEventListener( "eventBeforeUnload" );
1354
1355        for ( var i = 0; i < forms.length; i++ ) {
1356            var autosave = truth( forms[ i ].getAttribute( "mt:auto-save" ) );
1357            if ( !autosave )
1358                continue;
1359
1360            this.form = forms[ i ];
1361
1362            var ad = forms[ i ].getAttribute( "mt:auto-save-delay" );
1363            var autoSaveDelay;
1364            if ( ad !== null ) {
1365                autoSaveDelay = parseInt( ad ) || 0;
1366                this.autoSaveDelay = autoSaveDelay;
1367            } else
1368                log.warn("auto-save-delay not defined on this form. Defaulting to "+this.autoSaveDelay);
1369
1370            log('using auto save delay: '+this.autoSaveDelay);
1371
1372            var es = Array.fromPseudo(
1373                forms[ i ].getElementsByTagName( "input" ),
1374                forms[ i ].getElementsByTagName( "textarea" )
1375            );
1376            for ( var j = 0; j < es.length; j++ ) {
1377                if ( es[ j ].getAttribute && es[ j ].getAttribute( "mt:watch-change" ) ) {
1378                    log('adding watcher to '+es[ j ].name);
1379                    DOM.addEventListener( es[ j ], "change", this.getIndirectEventListener( "setDirty" ) );
1380                }
1381                if ( autosave && es[ j ].nodeName == "TEXTAREA" ) {
1382                    /* don't attach to the editor textarea in this form */
1383                    if ( this.editor && es[ j ].id == this.editor.textarea.element.id )
1384                        continue;
1385                    DOM.addEventListener( es[ j ], "keydown", this.getIndirectEventListener( "setDirtyKeyDown" ) );
1386                }
1387            }
1388        }
1389
1390        if ( MT.App.dirty )
1391            this.changed = true;   
1392    },
1393
1394
1395    destroyObject: function() {
1396        this.autoSaveReq = null;
1397        this.autoSaveTimer = null;
1398        this.form = null;
1399        this.cpeList = null;
1400        arguments.callee.applySuper( this, arguments );
1401    },
1402
1403
1404    initFormElements: function() {
1405        var forms = document.getElementsByTagName( "form" );
1406        for( var i = 0; i < forms.length; i++ ) {
1407            forms[ i ].submitted = false;
1408            DOM.addEventListener( forms[ i ], "submit", this.getIndirectEventListener( "eventSubmit" ) );
1409            var tareas = forms[ i ].getElementsByTagName( "textarea" );
1410            var tabs = 0;
1411            for ( var j = 0; j < tareas.length; j++ ) {
1412                if ( ( tabs = tareas[ j ].getAttribute( "mt:allow-tabs" ) ) )
1413                    if ( truth ( tabs ) )
1414                        this.attachTabsToTextarea( tareas[ j ] );
1415
1416                if ( tareas[ j ].getAttribute( "mt:editor" ) == "codepress" ) {
1417                    if ( this.constructor.CodePress.isSupported() ) {
1418                        var ed = new this.constructor.CodePress( tareas[ j ] );
1419                        if ( ed ) {
1420                            if ( !this.cpeList )
1421                                this.cpeList = [];
1422                            this.cpeList.push( ed );
1423                        }
1424                    }
1425                }
1426            }
1427        }
1428    },
1429
1430
1431    eventSubmit: function( event ) {
1432        var form = DOM.getFirstAncestorByTagName( event.target, "form", true );
1433        if ( !form )
1434            return;
1435           
1436        if ( form.getAttribute( "mt:once" ) ) {
1437       
1438            if ( form.submitted )
1439                return event.stop();
1440       
1441            this.toggleSubmit( form, true );
1442        }
1443
1444        if ( this.cpeList )
1445            this.cpeList.forEach( function( cpe ) { cpe.onSubmit() } );
1446
1447        form.submitted = true;
1448    },
1449
1450
1451    eventBeforeUnload: function( event ) {
1452        if ( this.changed ) {
1453            if ( this.constructor.Editor )
1454                return event.returnValue = Editor.strings.unsavedChanges;
1455            else if ( window.Editor )
1456                return event.returnValue = window.Editor.strings.unsavedChanges;
1457        }
1458       
1459        return undefined;
1460    },
1461
1462
1463    toggleSubmit: function( form, disable ) {
1464        /* sane default */
1465        if ( !disable )
1466            disable = false;
1467        var elements = form.getElementsByTagName( "*" );
1468        for( var i = 0; i < elements.length; i++ ) {
1469            var element = elements[ i ];
1470            var tagName = element.tagName.toLowerCase();
1471            var type = element.getAttribute( "type" );
1472            type = type ? type.toLowerCase() : "";
1473            if ( tagName == "button" || 
1474                (tagName == "input" && (type == "button" || type == "submit" || type == "image")) )
1475                element.disabled = disable;
1476        }
1477    },
1478
1479
1480    closeFlyouts: function( target ) {
1481        var flyout;
1482        var es = Array.fromPseudo( this.openFlyouts );
1483        for ( var i = 0, len = es.length; i < len; i++ ) {
1484            if ( ( flyout = DOM.getElement( es[ i ] ) ) ) {
1485                if ( target && DOM.hasAncestor( target, flyout ) )
1486                    continue;
1487                DOM.addClassName( flyout, "hidden" );
1488                this.openFlyouts.remove( es[ i ] );
1489                showAllDropDown();
1490            }
1491        }
1492    },
1493
1494
1495    eventClick: function( event ) {
1496        var command = this.getMouseEventCommand( event );
1497
1498        switch( command ) {
1499           
1500            case "openSelectBlog":
1501                app.openDialog( '__mode=dialog_select_weblog&amp;select_favorites=1&return_args='
1502                    + escape( event.commandElement.getAttribute( "mt:href" ) ) );
1503                break;
1504
1505            case "goToLocation":
1506                this.gotoLocation( event.commandElement.getAttribute( "href" ) );
1507                break;
1508           
1509            case "autoSave":
1510                this.autoSave();
1511                break;
1512
1513            case "setModeCodepressOn":
1514                this.cpeList.forEach( function( cpe ) { cpe.toggleOn( true ); } );
1515                break;
1516
1517            case "setModeCodepressOff":
1518                this.cpeList.forEach( function( cpe ) { cpe.toggleOff( true ); } );
1519                break;
1520
1521            case "openFlyout":
1522                var name = event.commandElement.getAttribute( "mt:flyout" );
1523                var el = DOM.getElement( name );
1524                if ( !defined( el ) )
1525                    return;
1526
1527                this.closeFlyouts( event.target );
1528
1529                DOM.removeClassName( el, "hidden" );
1530                this.targetElement = event.target;
1531                this.applyAutolayouts( el );
1532                this.targetElement = null;
1533
1534                hideAllDropDown();
1535                showDropDown( el );
1536                this.openFlyouts.add( name );
1537
1538                break;
1539               
1540            case "closeFlyout":
1541                this.closeFlyouts();
1542               
1543                break;
1544
1545            default:
1546                this.closeFlyouts( event.target );
1547
1548                var form = DOM.getFirstAncestorByTagName( event.target, "form", true );
1549                if ( !form )
1550                    return;
1551
1552                var mode = event.target.getAttribute( "mt:mode" );
1553                if ( !mode && event.commandElement )
1554                    mode = event.commandElement.getAttribute( "mt:mode" );
1555
1556                if ( mode ) {
1557                    log('setting __mode in this form: '+mode);
1558                    var elements = form.getElementsByTagName( "input" );
1559                    for( var i = 0; i < elements.length; i++ ) {
1560                        if ( elements[ i ].name == "__mode" ) {
1561                            log('found __mode element');
1562                            elements[ i ].value = mode;
1563                            break;
1564                        }
1565                    }
1566                }
1567
1568                if ( command == "submit" ) {
1569                    event.stop();
1570                    var msg;
1571                    if ( event.commandElement && ( msg = event.commandElement.getAttribute( "mt:confirm-msg" ) ) )
1572                        if ( !confirm( msg ) )
1573                            return;
1574                    form.submit();
1575                }
1576
1577                return;
1578
1579        }
1580        return event.stop();
1581    },
1582   
1583
1584    /* from blog selector transient */
1585    gotoUrl: function( url ) {
1586        if ( url )
1587            this.gotoLocation( url );
1588    },
1589
1590
1591    toggleActive: function( id ) {
1592        log('toggleactive:'+id);
1593        var div = DOM.getElement( id );
1594        if ( DOM.hasClassName( div, 'active' ) )
1595            DOM.removeClassName( div, 'active' );
1596        else
1597            DOM.addClassName( div, 'active' );
1598    },
1599
1600
1601    openDialog: function( params ) {
1602        this.closeFlyouts();
1603        show("dialog-container");
1604        /* TODO remove this cruft */
1605        /*  handle escape key for closing modal dialog */
1606        DOM.addEventListener( document.body, "keypress", dialogKeyPress, true );
1607        openDialogUrl( ScriptURI + "?" + params );
1608        /* IE hack to get the dialog modal to reflow */
1609        if ( document.all && DOM.getElement( "dialog-container" ) ) {
1610            DOM.addClassName( "dialog-container", "hidden" );
1611            new Timer(function() {
1612                DOM.removeClassName( "dialog-container", "hidden" );
1613            }, 500, 1 );
1614        }
1615    },
1616
1617
1618    attachTabsToTextarea: function( element ) {
1619        DOM.addEventListener( element, "keypress", this.getIndirectMethod( "eventKeyPressAllowTabs" ) );
1620        DOM.addEventListener( element, "keydown", this.getIndirectMethod( "eventKeyDownAllowTabs" ) );
1621    },
1622
1623
1624    eventKeyPressAllowTabs: function( event ) {
1625        if ( event.keyCode == 9 )
1626            return event.stop();
1627    },
1628   
1629   
1630    eventKeyDownAllowTabs: function( event ) {
1631        if ( event.keyCode == 9 ) {
1632                    TC.setSelectionValue( ( event.target || event.srcElement ) , "\t" );
1633            return false;
1634        }
1635    },
1636
1637
1638    resizeComplete: function( target, xStart, yStart, x, y, width, height ) {
1639       
1640        switch ( target.id ) {
1641            case "textarea-enclosure":
1642                var es = [ "text", "text_cpe" ];
1643                for ( var i = 0; i < es.length; i++ ) {
1644                    es[ i ] = DOM.getElement( es[ i ] );
1645                    if ( es[ i ] )
1646                        DOM.setHeight( es[ i ], height );
1647                }
1648                break;
1649
1650            /* expand here */
1651        }
1652
1653    },
1654   
1655   
1656    autoSave: function() {
1657        var data = DOM.getFormData( this.form );
1658        data["_autosave"] = 1;
1659
1660        if ( this.cpeList )
1661            this.cpeList.forEach( function( cpe ) { cpe.autoSave( data ) } );
1662
1663        /* don't cancel a pending save */
1664        if ( defined( this.autoSaveReq ) )
1665            return;
1666       
1667        var areas = [
1668            DOM.getElement( "autosave-notification" ),
1669            DOM.getElement( "autosave-notification-top" ),
1670            DOM.getElement( "autosave-notification-bottom" )
1671        ];
1672        if ( areas )
1673            for ( var i = 0; i < areas.length; i++ )
1674                if ( areas[ i ] )
1675                    areas[ i ].innerHTML = Template.process( "autoSave", { saving: true } );
1676
1677        this.autoSaveReq = TC.Client.call({
1678            load: this.getIndirectMethod( "autoSaveComplete" ),
1679            error: this.getIndirectMethod( "autoSaveError" ),
1680            method: 'POST',
1681            uri: this.form.action,
1682            arguments: data
1683        });
1684    },
1685
1686
1687    autoSaveComplete: function( c, r ) {
1688        this.autoSaveTimer = this.autoSaveReq = undefined;
1689
1690        log('auto save complete '+r);
1691        if ( r != "true" )
1692            return log.error( "Error auto-saving post: "+r );
1693       
1694        var areas = [
1695            DOM.getElement( "autosave-notification" ),
1696            DOM.getElement( "autosave-notification-top" ),
1697            DOM.getElement( "autosave-notification-bottom" )
1698        ];
1699        var d = new Date();
1700        if ( areas )
1701            for ( var i = 0; i < areas.length; i++ )
1702                if ( areas[ i ] )
1703                    areas[ i ].innerHTML = Template.process( "autoSave", {
1704                        saving: false,
1705                        hh: d.getHours().toString().pad( 2, "0" ),
1706                        mm: d.getMinutes().toString().pad( 2, "0" ),
1707                        ss: d.getSeconds().toString().pad( 2, "0" )
1708                    } );
1709    },
1710
1711   
1712    autoSaveError: function( c, r ) {
1713        this.autoSaveTimer = this.autoSaveReq = undefined;
1714       
1715        log.error( "Error auto-saving post" );
1716        var areas = [
1717            DOM.getElement( "autosave-notification" ),
1718            DOM.getElement( "autosave-notification-top" ),
1719            DOM.getElement( "autosave-notification-bottom" )
1720        ];
1721        if ( areas )
1722            for ( var i = 0; i < areas.length; i++ )
1723                if ( areas[ i ] )
1724                    areas[ i ].innerHTML = ''
1725    },
1726
1727
1728    setDirtyKeyDown: function( event ) {
1729        if ( this.dirtyKeyDownTimer )
1730            this.dirtyKeyDownTimer.stop();
1731        this.dirtyKeyDownTimer = new Timer( this.getIndirectMethod( "setDirty" ), 5000, 1 );
1732    },
1733
1734
1735    setDirty: function( event ) {
1736        var autoSaveDelay = this.autoSaveDelay;
1737        if ( event && event.target ) {
1738            var form = DOM.getFirstAncestorByTagName( event.target, "form", true );
1739            if ( form ) {
1740                log('found dirty form: '+form);
1741                this.form = form;
1742                if ( autoSaveDelay = parseInt( form.getAttribute( "mt:auto-save-delay" ) ) || 0 ) {
1743                    this.autoSaveDelay = autoSaveDelay;
1744                    log('using auto save delay: '+this.autoSaveDelay);
1745                }
1746            }
1747        }
1748           
1749        this.changed = true;
1750        if ( autoSaveDelay < 1 )
1751            return;
1752
1753        if ( defined( this.autoSaveTimer ) )
1754            return this.autoSaveTimer.reset();
1755        this.autoSaveTimer = new Timer( this.getIndirectMethod( "autoSave" ), autoSaveDelay, 1 );
1756    },
1757
1758
1759    clearDirty: function( event ) {
1760        this.changed = false;
1761    },
1762
1763   
1764    insertCode: function( code ) {
1765        if ( this.cpeList )
1766            this.cpeList[ 0 ].insertCode( code );
1767        else if ( this.editor )
1768            this.editor.insertHTML( code );
1769        else {
1770            var txt = DOM.getElement( "text" );
1771            setSelection( txt, code );
1772            DOM.focus( txt );
1773        }
1774    }
1775   
1776
1777} );
1778
1779if ( window.Calendar ) {
1780
1781MT.App.Calendar = new Class( Calendar, {
1782
1783
1784    open: function( data, callback ) {
1785        if ( data.date && data.date.length )
1786            data.date = data.date.replace( /^(\S+).*/, "$1" );
1787        arguments.callee.applySuper( this, arguments );
1788       
1789        /* reset invalid dates to the current date */
1790        if ( !this.dateObject )
1791            this.dateObject = new Date();
1792    },
1793
1794
1795    eventClick: function() {
1796        arguments.callee.applySuper( this, arguments );
1797        if ( this.callback )
1798            this.callback( this.dateObject );
1799    }
1800
1801
1802} );
1803
1804}
1805
1806
1807
1808
1809MT.App.Resizer = new Class( Object, {
1810
1811
1812    dragging: false,
1813    element: null,
1814   
1815    xLock: false,
1816    yLock: false,
1817
1818    xStart: null,
1819    yStart: null,
1820
1821
1822    init: function( callback ) {
1823        if ( callback )
1824            this.callback = callback;
1825    },
1826
1827
1828    destroy: function() {
1829        this.callback = null;
1830    },
1831
1832
1833    eventMouseDown: function( event ) {
1834        this.dragging = true;
1835       
1836        this.reset();
1837       
1838        this.target = event.attributeElement.getAttribute( "mt:target" );
1839
1840        /* x or y locking */
1841        var lock = event.attributeElement.getAttribute( "mt:lock" );
1842        if ( lock ) {
1843            if ( lock == "x" || lock == "X" )
1844                this.xLock = true;
1845            else if ( lock == "y" || lock == "Y" )
1846                this.yLock = true;
1847        }
1848       
1849        /* clone the drag node */
1850        this.element = event.attributeElement.cloneNode( true );
1851        /* using the current mouse position, set the positon of the drag obj */
1852        var d = DOM.getAbsoluteCursorPosition( event );
1853        this.yStart = d.y;
1854        this.xStart = d.x;
1855       
1856        var dm = DOM.getAbsoluteDimensions( event.attributeElement );
1857        var adm = DOM.getAbsoluteDimensions( event.attributeElement );
1858       
1859        if ( !this.yLock )
1860            DOM.setTop( this.element,  d.y );
1861        else
1862            DOM.setTop( this.element, adm.absoluteTop );
1863
1864        if ( !this.xLock )
1865            DOM.setLeft( this.element,  d.x );
1866        else
1867            DOM.setLeft( this.element, adm.absoluteLeft );
1868
1869        DOM.setWidth( this.element, dm.offsetWidth );
1870        DOM.setHeight( this.element, dm.offsetHeight );
1871       
1872        var mask = DOM.getElement( "resize-mask" );
1873        mask.insertBefore( this.element, mask.firstChild );
1874        DOM.addClassName( this.element, "moving" );
1875        DOM.removeClassName( mask, "hidden" );
1876        /* TODO autolayout this */
1877        DOM.setHeight( mask, finiteInt( mask.parentNode.clientHeight ) );
1878
1879        return event.stop();
1880    },
1881
1882
1883    eventMouseMove: function( event ) {
1884        if ( !this.dragging )
1885            return;
1886       
1887        var d = DOM.getAbsoluteCursorPosition( event );
1888       
1889        if ( !this.yLock )
1890            DOM.setTop( this.element, d.y );
1891
1892        if ( !this.xLock )
1893            DOM.setLeft( this.element, d.x );
1894
1895        return event.stop();
1896    },
1897
1898
1899    eventMouseUp: function( event ) {
1900        if ( !this.dragging )
1901            return;
1902       
1903        this.dragging = false;
1904        var d = DOM.getAbsoluteCursorPosition( event );
1905           
1906        DOM.addClassName( "resize-mask", "hidden" );
1907       
1908        /* cleanup */
1909        if ( this.element && this.element.parentNode )
1910            this.element.parentNode.removeChild( this.element );
1911
1912        var target = DOM.getElement( this.target );
1913        if ( !target )
1914            return this.reset();
1915
1916        var targetDim = DOM.getDimensions( target );
1917       
1918        var height = d.y - targetDim.offsetTop;
1919        if ( !this.yLock ) {
1920            var hMin = target.getAttribute( "mt:min-height" );
1921            if ( hMin )
1922                if ( height < parseInt( hMin ) )
1923                    height = parseInt( hMin );
1924       
1925            var hMax = target.getAttribute( "mt:max-height" );
1926            if ( hMax )
1927                if ( height > parseInt( hMax ) )
1928                    height = parseInt( hMax );
1929
1930            log('new height: '+height);
1931        }
1932
1933        var width = d.x - targetDim.offsetLeft;
1934        if ( !this.xLock ) {
1935            var wMin = target.getAttribute( "mt:min-width" );
1936            if ( wMin )
1937                if ( width < parseInt( wMin ) )
1938                    width = parseInt( wMin );
1939       
1940            var wMax = target.getAttribute( "mt:max-width" );
1941            if ( wMax )
1942                if ( width > parseInt( wMax ) )
1943                    width = parseInt( wMax );
1944
1945            log('new width: '+width);
1946        }
1947       
1948        /* give the callback a chance to stop us from setting this height and width */
1949        if ( this.callback && ( this.callback( target, this.xStart, this.yStart, d.x, d.y, width, height ) ) )
1950            return this.reset();
1951       
1952        if ( !this.yLock )
1953            DOM.setHeight( target, height );
1954
1955        if ( !this.xLock )
1956            DOM.setWidth( target, width );
1957
1958        var hUpdate = target.getAttribute( "mt:update-field-height" );
1959        if ( hUpdate && ( hUpdate = DOM.getElement( hUpdate ) ) )
1960            hUpdate.value = height;
1961       
1962        var wUpdate = target.getAttribute( "mt:update-field-width" );
1963        if ( wUpdate && ( wUpdate = DOM.getElement( wUpdate ) ) )
1964            wUpdate.value = width;
1965
1966        this.reset();
1967    },
1968
1969
1970    reset: function() {
1971        /* remove left over drag obj, if any */
1972        if ( this.element && this.element.parentNode )
1973            this.element.parentNode.removeChild( this.element );
1974       
1975        this.xStart = this.yStart = this.element = this.target = null;
1976        this.xLock = this.yLock = false;
1977    }
1978
1979
1980} );
1981
1982
1983MT.App.DefaultValue = new Class( Object, {
1984
1985
1986    init: function() {
1987        var es = DOM.getElementsByAttributeAndValue( document, "mt:delegate", "default-value" );
1988        for ( var i = 0; i < es.length; i++ ) {
1989            var val = es[ i ].getAttribute( "mt:default" );
1990            if ( !val )
1991                continue;
1992           
1993            if ( es[ i ].value != val )
1994                DOM.removeClassName( es[ i ], "input-hint" );
1995        }
1996    },
1997
1998
1999    eventFocus: function( event ) {
2000        var element = event.attributeElement;
2001        var val = element.getAttribute( "mt:default" );
2002        if ( !val )
2003            return;
2004
2005        DOM.removeClassName( element, "input-hint" );
2006       
2007        if ( element.value == val )
2008            element.value = "";
2009    },
2010
2011
2012    eventBlur: function( event ) {
2013        var element = event.attributeElement;
2014        var val = element.getAttribute( "mt:default" );
2015        if ( !val )
2016            return;
2017       
2018        var opts = {};
2019        /* simple options for now */
2020        var opt = element.getAttribute( "mt:delegate-options" );
2021        if ( opt && opt == "-class" ) {
2022            opts.noclassChange = true;
2023        }
2024       
2025        if ( element.value != "" )
2026            return;
2027       
2028        element.value = val;
2029        if ( opts.noclassChange )
2030            return;
2031
2032        DOM.addClassName( element, "input-hint" );
2033    },
2034   
2035   
2036    /* hate on IE */
2037    eventFocusIn: function( event ) {
2038        return this.eventFocus( event );
2039    },
2040   
2041
2042    eventFocusOut: function( event ) {
2043        this.eventBlur( event );
2044    },
2045
2046
2047    eventSubmit: function( event ) {
2048        return event.stop();
2049    }
2050   
2051   
2052} );
2053
2054
2055MT.App.TabContainer = new Class( Object, {
2056
2057    init: function() {
2058        var es = DOM.getElementsByAttributeAndValue( document, "mt:delegate", "tab-container" );
2059        var t;
2060        for ( var i = 0; i < es.length; i++ ) {
2061            if ( t = es[ i ].getAttribute( "mt:selected-tab" ) ) {
2062                this.selectTab( es[ i ], t );
2063                continue;
2064            }
2065
2066            if ( t = es[ i ].getAttribute( "mt:persist-tab-cookie" ) ) {
2067                log( 'found persisted tab setting: '+t);
2068                t = Cookie.fetch( t );
2069                if ( t && t.value && t.value != "" ) {
2070                    log( 'cookie: '+t.value);
2071                    this.selectTab( es[ i ], t.value );
2072                }
2073            }
2074        }
2075    },
2076
2077
2078    eventClick: function( event ) {
2079        var command = app.getMouseEventCommand( event );
2080        if (!event.commandElement) return;
2081        var tab = event.commandElement.getAttribute( "mt:tab" );
2082        if ( tab && command != "selectTab" )
2083            this.selectTab( event.attributeElement, tab );
2084
2085        switch( command ) {
2086           
2087            case "setEditorContent":
2088                event.stop();
2089                app.setEditor( "content" );
2090                break;
2091
2092            case "setEditorExtended":
2093                event.stop();
2094                app.setEditor( "extended" );
2095                break;
2096           
2097            case "selectTab":
2098                if ( !tab )
2099                    tab = event.commandElement.getAttribute( "mt:select-tab" );
2100
2101                if ( tab ) {
2102                    this.selectTab( event.attributeElement, tab );
2103                    var cookie = event.attributeElement.getAttribute( "mt:persist-tab-cookie" );
2104                    if ( cookie ) {
2105                        var d = new Date();
2106                        d.setYear( d.getYear() + 1902 ); /* two years */
2107                        Cookie.bake( cookie, tab, undefined, undefined, d );
2108                    }
2109                }
2110               
2111                event.stop();
2112                break;
2113
2114        }
2115    },
2116
2117
2118    selectTab: function( element, name ) {
2119        log('select tab '+name);
2120        var es = DOM.getElementsByAttribute( element, "mt:tab" );
2121        for ( var i = 0; i < es.length; i++ ) {
2122            if ( es[ i ].getAttribute( "mt:tab" ) == name )
2123                DOM.addClassName( es[ i ], "selected-tab" );
2124            else
2125                DOM.removeClassName( es[ i ], "selected-tab" );
2126        }
2127
2128        /* look for tab contents elements matching 'name' */
2129        es = DOM.getElementsByAttribute( element, "mt:tab-content" );
2130        for ( var i = 0; i < es.length; i++ ) {
2131            /* then hide everything except the tab content we want to show */
2132            if ( es[ i ].getAttribute( "mt:tab-content" ) == name )
2133                DOM.removeClassName( es[ i ], "hidden" );
2134            else
2135                DOM.addClassName( es[ i ], "hidden" );
2136        }
2137    }
2138
2139
2140} );
2141
2142
2143MT.App.NavMenu = new Class( Object, {
2144
2145    opened: false,
2146    outTimer: null,
2147    inTimer: null,
2148    el: null,
2149    al: null,
2150
2151
2152    eventMouseOver: function( event ) {
2153        var el = DOM.getFirstAncestorByClassName( event.target, "nav-menu", true );
2154        if ( !el )
2155            return;
2156       
2157        /* if they moused in, but moved to a new menu, reset the in timer */
2158        if ( this.inTimer && this.el && this.el !== el )
2159            this.inTimer.stop();
2160       
2161        this.al = event.attributeElement;
2162        this.el = el;
2163
2164        if ( this.outTimer )
2165            this.outTimer.stop();
2166
2167        if ( this.al.getAttribute( "mt:is-opened" ) == "1" )
2168            return this.openMenu();
2169       
2170        var delay = event.attributeElement.getAttribute( "mt:nav-delayed-open" ); // ms
2171
2172        if ( delay ) {
2173            delay = parseInt( delay );
2174            /* no hover in? */
2175            if ( delay < 0 )
2176                return;
2177            if ( this.inTimer )
2178                this.inTimer.stop();
2179            this.inTimer = new Timer( this.getIndirectMethod( "openMenu" ), delay, 1 );
2180            return;
2181        } else
2182            this.openMenu();
2183    },
2184
2185
2186    eventMouseOut: function( event ) {
2187        var el = DOM.getFirstAncestorByClassName( event.target, "nav-menu", true );
2188        if ( !el && defined( event.relatedTarget ) )
2189            el = DOM.getFirstAncestorByClassName( event.relatedTarget, "nav-menu", true );
2190        if ( !el )
2191            return;
2192
2193        this.al = event.attributeElement;
2194        this.el = el;
2195
2196        var delay = event.attributeElement.getAttribute( "mt:nav-delayed-close" ); // ms
2197        if ( delay ) {
2198            delay = parseInt( delay );
2199            /* no hover out? */
2200            if ( delay < 0 )
2201                return;
2202            if ( this.outTimer )
2203                this.outTimer.stop();
2204            this.outTimer = new Timer( this.getIndirectMethod( "closeMenu" ), delay, 1 );
2205        } else
2206            this.closeMenu();
2207    },
2208
2209
2210    eventClick: function( event ) {
2211        var command = app.getMouseEventCommand( event );
2212        if ( !command ) {
2213            if ( this.inTimer )
2214                this.inTimer.stop();
2215            return;
2216        }
2217
2218        var el = DOM.getFirstAncestorByClassName( event.target, "nav-menu", true );
2219        if ( !el )
2220            return;
2221        this.al = event.attributeElement;
2222
2223        if ( command == "openMenu" ) {
2224            event.stop();
2225            this.openMenu( el );
2226        }
2227    },
2228
2229
2230    openMenu: function() {
2231        if ( !this.el )
2232            return;
2233
2234        if ( this.outTimer )
2235