root/branches/release-36/default_templates/javascript.mtml @ 2062

Revision 2062, 20.4 kB (checked in by bchoate, 19 months ago)

Updates to blog-side javascript regarding user state and permissions. BugId:79077,69644,67754,69814,79258,62643. Fixed declarations for conditional tags. BugId:79476. Display auth'd user nickname rather than name from comment object. BugId:79475

  • Property svn:keywords set to Id Revision
Line 
1<mt:ignore>
2/* The following functions are here to support legacy MT templates.
3   If you have refreshed your JavaScript template but still use older
4   MT comment templates, you may need to uncomment this block in order
5   for those templates to work properly. Simply remove the wrapping
6   'mt:ignore' tag to do so. */
7function hideDocumentElement(id) { return mtHide(id) }
8function showDocumentElement(id) { return mtShow(id) }
9function individualArchivesOnLoad() { return mtEntryOnLoad() }
10function writeCommenterGreeting() { return mtShowGreeting() }
11function rememberMe(f) { return mtRememberMe(f) }
12function forgetMe(f) { return mtForgetMe(f) }
13</mt:ignore>
14
15// The cookie name to use for storing the blog-side comment session cookie.
16var cookie_name = "mt_blog<$MTBlogID$>_user";
17// The cookie path to use for storing the blog-side comment session cookie.
18var blog_path = "<$MTBlogURL$>".replace(/^.*?\/\/[^\/]+?\//, '/');
19
20<mt:ignore>
21/***
22 * Simple routine for showing a DOM element (applying a CSS display
23 * attribute of 'none').
24 */
25</mt:ignore>
26function mtHide(id) {
27    var el = (typeof id == "string") ? document.getElementById(id) : id;
28    if (el) el.style.display = 'none';
29}
30
31<mt:ignore>
32/***
33 * Simple routine for showing a DOM element (applying a CSS display
34 * attribute of 'block').
35 */
36</mt:ignore>
37function mtShow(id) {
38    var el = (typeof id == "string") ? document.getElementById(id) : id;
39    if (el) el.style.display = 'block';
40}
41
42var captcha_timer;
43<mt:ignore>
44/***
45 * Used to display the comment form and captcha field.
46 */
47</mt:ignore>
48function mtShowAnonymousForm() {
49    mtShow('comments-form');
50    captcha_timer = setInterval('mtShowCaptcha()', 1000);
51}
52
53<mt:ignore>
54/***
55 * Displays a relative date.
56 * 'ts' is a Date object, 'fds' is a string of the date which
57 * will be displayed if the given date is older than 1 week.
58 */
59</mt:ignore>
60function mtRelativeDate(ts, fds) {
61    var now = new Date();
62    var ref = ts;
63    var delta = Math.floor((now.getTime() - ref.getTime()) / 1000);
64
65    var str;
66    if (delta < 60) {
67        str = '<__trans phrase="moments ago">';
68    } else if (delta <= 86400) {
69        // less than 1 day
70        var hours = Math.floor(delta / 3600);
71        var min = Math.floor((delta % 3600) / 60);
72        if (hours == 1)
73            str = '<__trans phrase="[quant,_1,hour,hours] ago" params="1">';
74        else if (hours > 1)
75            str = '<__trans phrase="[quant,_1,hour,hours] ago" params="2">'.replace(/2/, hours);
76        else if (min == 1)
77            str = '<__trans phrase="[quant,_1,minute,minutes] ago" params="1">';
78        else
79            str = '<__trans phrase="[quant,_1,minute,minutes] ago" params="2">'.replace(/2/, min);
80    } else if (delta <= 604800) {
81        // less than 1 week
82        var days = Math.floor(delta / 86400);
83        var hours = Math.floor((delta % 86400) / 3600);
84        if (days == 1)
85            str = '<__trans phrase="[quant,_1,day,days] ago" params="1">';
86        else if (days > 1)
87            str = '<__trans phrase="[quant,_1,day,days] ago" params="2">'.replace(/2/, days);
88        else if (hours == 1)
89            str = '<__trans phrase="[quant,_1,hour,hours] ago" params="1">';
90        else
91            str = '<__trans phrase="[quant,_1,hour,hours] ago" params="2">'.replace(/2/, hours);
92    }
93    return str ? str : fds;
94}
95
96<mt:ignore>
97/***
98 * Used to display an edit link for the given entry.
99 */
100</mt:ignore>
101function mtEditLink(entry_id, author_id) {
102    var u = mtGetUser();
103    if (! u) return;
104    if (! entry_id) return;
105    if (! author_id) return;
106    if (u.id != author_id) return;
107    var link = '<__trans phrase='<a href="[_1]">Edit</a>' params="<$MTAdminScript$>?__mode=view&amp;_type=entry&amp;id=' + entry_id + '">';
108    document.write(link);
109}
110
111<mt:ignore>
112/***
113 * Displays a captcha field for anonymous commenters.
114 */
115</mt:ignore>
116function mtShowCaptcha() {
117    if (captcha_timer) clearInterval(captcha_timer);
118    var div = document.getElementById('comments-open-captcha');
119    if (div)
120        div.innerHTML = '<$MTCaptchaFields$>';
121}
122
123<mt:ignore>
124/* user object
125    -- saved in user cookie --
126    u.name (display name)
127    u.url (link to home page)
128    u.email (for anonymous only)
129    u.userpic (url for commenter/author)
130    u.profile (link to profile)
131    u.is_trusted (boolean)
132    u.is_author (user has posting rights)
133    u.is_banned (banned status; neither post/comment perms)
134    u.can_post (has permission to post)
135    u.can_comment (has permission to comment)
136
137    -- status fields --
138    u.is_authenticated (boolean)
139    u.is_anonymous (user is anonymous)
140*/
141</mt:ignore>
142
143var is_preview;
144var user;
145<mt:ignore>
146/***
147 * Assigns a user object as the actively logged in user; also saves the
148 * user information in a browser cookie.
149 */
150</mt:ignore>
151function mtSetUser(u) {
152    if (u) {
153        // persist this
154        user = u;
155        mtSaveUser();
156    }
157}
158
159<mt:ignore>
160/***
161 * Simple function that escapes single quote characters for storing
162 * in a cookie.
163 */
164</mt:ignore>
165function mtEscapeJS(s) {
166    s = s.replace(/'/g, "&apos;");
167    return s;
168}
169
170<mt:ignore>
171/***
172 * Simple function that unescapes single quote characters that were
173 * stored in a cookie.
174 */
175</mt:ignore>
176function mtUnescapeJS(s) {
177    s = s.replace(/&apos;/g, "'");
178    return s;
179}
180
181<mt:ignore>
182/***
183 * Serializes a user object into a string, suitable for storing as a cookie.
184 */
185</mt:ignore>
186function mtBakeUserCookie(u) {
187    var str = "";
188    if (u.name) str += "name:'" + mtEscapeJS(u.name) + "';";
189    if (u.url) str += "url:'" + mtEscapeJS(u.url) + "';";
190    if (u.email) str += "email:'" + mtEscapeJS(u.email) + "';";
191    if (u.is_authenticated) str += "is_authenticated:'1';";
192    if (u.profile) str += "profile:'" + mtEscapeJS(u.profile) + "';";
193    if (u.userpic) str += "userpic:'" + mtEscapeJS(u.userpic) + "';";
194    str += "is_trusted:'" + (u.is_trusted ? "1" : "0") + "';";
195    str += "is_author:'" + (u.is_author ? "1" : "0") + "';";
196    str += "is_banned:'" + (u.is_banned ? "1" : "0") + "';";
197    str += "can_post:'" + (u.can_post ? "1" : "0") + "';";
198    str += "can_comment:'" + (u.can_comment ? "1" : "0") + "';";
199    str = str.replace(/;$/, '');
200    return str;
201}
202
203<mt:ignore>
204/***
205 * Unserializes a user cookie and returns a user object with the restored
206 * state.
207 */
208</mt:ignore>
209function mtUnbakeUserCookie(s) {
210    if (!s) return;
211
212    var u = {};
213    var m;
214    while (m = s.match(/^((name|url|email|is_authenticated|profile|userpic|is_trusted|is_author|is_banned|can_post|can_comment):'([^']+?)';?)/)) {
215        s = s.substring(m[1].length);
216        if (m[2].match(/^(is|can)_/)) // boolean fields
217            u[m[2]] = m[3] == '1' ? true : false;
218        else
219            u[m[2]] = mtUnescapeJS(m[3]);
220    }
221    if (u.is_authenticated) {
222        u.is_anonymous = false;
223    } else {
224        u.is_anonymous = true;
225        u.can_post = false;
226        u.is_author = false;
227        u.is_banned = false;
228        u.is_trusted = false;
229    }
230    return u;
231}
232
233<mt:ignore>
234/***
235 * Retrieves an object of the currently logged in user's state.
236 * If no user is logged in or cookied, this will return null.
237 */
238</mt:ignore>
239function mtGetUser() {
240    if (!user) {
241        var cookie = mtGetCookie(cookie_name);
242        if (!cookie) return;
243        user = mtUnbakeUserCookie(cookie);
244        if (! user) {
245            user = {};
246            user.is_anonymous = true;
247            user.can_post = false;
248            user.is_author = false;
249            user.is_banned = false;
250            user.is_trusted = false;
251        }
252    }
253    return user;
254}
255
256<mt:ignore>
257/***
258 * Issues a request to the MT comment script to retrieve the currently
259 * logged-in user (if any).
260 */
261</mt:ignore>
262function mtFetchUser() {
263    document.write('<scr' + 'ipt src="<$MTCGIPath$><$MTCommentScript$>?__mode=session_js&blog_id=<$MTBlogID$>&jsonp=mtSetUser"></scr' + 'ipt>');
264}
265
266<mt:ignore>
267/***
268 * Called when the 'Remember me' checkbox is changed. If the checkbox
269 * is cleared, the cached user cookie is immediately cleared.
270 */
271</mt:ignore>
272function mtRememberMeOnClick(b) {
273    if (!b.checked)
274        mtClearUser(b.form);
275    return true;
276}
277
278<mt:ignore>
279/***
280 * Called when comment form is sent.
281 * Required parameter: Form DOM object of comment form.
282 * If form has a 'bakecookie' member, it will be used to signal
283 * storing the anonymous commenter information to a cookie.
284 * If form has a 'armor' member, it will be used to store
285 * a token that is checked by the comment script.
286 */
287</mt:ignore>
288var mtRequestSubmitted = false;
289function mtCommentOnSubmit(f) {
290    if (!mtRequestSubmitted) {
291        mtRequestSubmitted = true;
292
293        if (f.armor)
294            f.armor.value = '<$MTBlogSitePath encode_sha1="1"$>';
295        if (f.bakecookie && f.bakecookie.checked)
296            mtSaveUser(f);
297
298        // disable submit buttons
299        if (f.preview_button) f.preview_button.disabled = true;
300        if (f.post) f.post.disabled = true;
301        if (f.preview.value == '1')
302            f.preview_button.value = '<__trans phrase="Posting...">';
303        else
304            f.post.value = '<__trans phrase="Posting...">';
305
306        return true;
307    }
308    return false;
309}
310
311<mt:ignore>
312/***
313 * Called when an entry archive page is loaded.
314 * This routine controls which elements of the comment form are shown
315 * or hidden, depending on commenter type and blog configuration.
316 */
317</mt:ignore>
318function mtEntryOnLoad() {
319    var u = mtGetUser();
320
321<mt:unless tag="IfCommentsAccepted">
322    mtHide('comments-open');
323</mt:unless>
324<mt:unless tag="IfPingsAccepted">
325    mtHide('trackbacks-info');
326</mt:unless>
327
328<mt:IfRegistrationRequired>
329    if ( !u || u.is_anonymous ) {
330        mtHide('comments-open-data');
331        mtHide('comments-open-text');
332        mtHide('comments-open-footer');
333    } else {
334        mtHide('comments-open-data');
335        mtShow('comments-open-text');
336        mtShow('comments-open-footer');
337    }
338<mt:else>
339<mt:IfRegistrationAllowed>
340    if (is_preview && u && u.is_anonymous) {
341        mtShowAnonymousForm();
342    } else {
343        // comments are allowed but registration not required
344        if ( !u || u.is_anonymous )
345            mtHide('comments-form');
346        else
347            mtHide('comments-open-data');
348    }
349<mt:else>
350    mtShowAnonymousForm();
351</mt:IfRegistrationAllowed>
352</mt:IfRegistrationRequired>
353
354    mtShowGreeting();
355
356    // populate anonymous comment fields if
357    // user is cookied as anonymous
358    var cf = document.comments_form;
359    if (cf) {
360        if (u && u.is_anonymous) {
361            if (u.email) cf.email.value = u.email;
362            if (u.name) cf.author.value = u.name;
363            if (u.url) cf.url.value = u.url;
364            if (cf.bakecookie)
365                cf.bakecookie.checked = u.name || u.email;
366        }
367        if (cf.post.disabled) {
368            cf.post.disabled = false;
369            cf.post.value = '<__trans phrase="Submit">';
370        }
371        if (cf.preview_button.disabled) {
372            cf.preview_button.disabled = false;
373            cf.preview_button.value = '<__trans phrase="Preview">';
374        }
375    }
376}
377
378<mt:ignore>
379/***
380 * Handles the action of the "Sign in" link. First clears any existing
381 * user cookie, then directs to the MT comment script to sign the user in.
382 */
383</mt:ignore>
384function mtSignIn(entry_id) {
385    var doc_url = document.URL;
386    doc_url = doc_url.replace(/#.+/, '');
387    var url = '<$MTSignInLink$>&entry_id=' + entry_id +
388        '&return_to=' + encodeURIComponent(doc_url);
389    mtClearUser();
390    location.href = url;
391}
392
393<mt:ignore>
394/***
395 * Handles the action of the "Sign out" link. First clears any existing
396 * user cookie, then direts to the MT comment script to sign the user out.
397 */
398</mt:ignore>
399function mtSignOut(entry_id) {
400    var url = '<$MTSignOutLink$>&entry_id=' + entry_id;
401    mtClearUser();
402    location.href = url;
403}
404
405<mt:ignore>
406/***
407 * Handles the display of the greeting message, depending on what kind of
408 * user is logged in and blog comment policy.
409 */
410</mt:ignore>
411function mtShowGreeting() {
412<mt:IfRegistrationAllowed>
413    var reg_reqd = <mt:IfRegistrationRequired>true<mt:else>false</mt:IfRegistrationRequired>;
414
415    var cf = document.comments_form;
416    if (!cf) return;
417
418    var el = document.getElementById('comment-greeting');
419    if (!el)  // legacy MT 4.x element id
420        el = document.getElementById('comment-form-external-auth');
421    if (!el) return;
422
423    var eid = cf.entry_id;
424    var entry_id;
425    if (eid) entry_id = eid.value;
426
427    var phrase;
428    var u = mtGetUser();
429
430    if ( u && u.is_authenticated ) {
431        if ( u.is_banned ) {
432            phrase = '<__trans phrase="You do not have permission to comment on this blog. ([_1]sign out[_2])" params="<a href="javascript:void(0);" onclick="mtSignOut(' + entry_id + ')">%%</a>">';
433        } else {
434            var user_link;
435            if ( u.is_author ) {
436                user_link = '<a href="<$MTCGIPath$><$MTCommentScript$>?__mode=edit_profile&blog_id=<$MTBlogID$>';
437                if (entry_id)
438                    user_link += '&entry_id=' + entry_id;
439                user_link += '">' + u.name + '</a>';
440            } else {
441                // registered user, but not a user with posting rights
442                if (u.url)
443                    user_link = '<a href="' + u.url + '">' + u.name + '</a>';
444                else
445                    user_link = u.name;
446            }
447            // TBD: supplement phrase with userpic if one is available.
448            phrase = '<__trans phrase="Thanks for signing in, [_1]. ([_2]sign out[_3])" params="' + user_link + '%%<a href="javascript:void(0)" onclick="mtSignOut(' + entry_id + ')">%%</a>">';
449        }
450    } else {
451        if (reg_reqd) {
452            phrase = '<__trans phrase="[_1]Sign in[_2] to comment." params="<a href="javascript:void(0)" onclick="mtSignIn()">%%</a>">';
453        } else {
454            phrase = '<__trans phrase="[_1]Sign in[_2] to comment, or [_3]comment anonymously[_2]." params="<a href="javascript:void(0)" onclick="mtSignIn(' + entry_id + ')">%%</a>%%<a href="javascript:void(0);" onclick="mtShowAnonymousForm();">">';
455        }
456    }
457    el.innerHTML = phrase;
458<mt:else>
459    mtShowCaptcha();
460</mt:IfRegistrationAllowed>
461}
462
463<mt:ignore>
464/***
465 * Handles the action of the 'Reply' links.
466 */
467</mt:ignore>
468function mtReplyCommentOnClick(parent_id, author) {
469    mtShow('comment-form-reply');
470
471    var checkbox = document.getElementById('comment-reply');
472    var label = document.getElementById('comment-reply-label');
473    var text = document.getElementById('comment-text');
474
475    // Populate label with new values
476    var reply_text = '<__trans phrase="Replying to <a href="#comment-[_1]">comment from [_2]</a>" params="'+ parent_id +'%%'+ author +'">';
477    label.innerHTML = reply_text;
478
479    checkbox.value = parent_id;
480    checkbox.checked = true;
481    text.focus();
482
483    mtSetCommentParentID();
484}
485
486<mt:ignore>
487/***
488 * Sets the parent comment ID when replying to a comment.
489 */
490</mt:ignore>
491function mtSetCommentParentID() {
492    var checkbox = document.getElementById('comment-reply');
493    var parent_id_field = document.getElementById('comment-parent-id');
494    if (!checkbox || !parent_id_field) return;
495
496    var pid = 0;
497    if (checkbox.checked == true)
498        pid = checkbox.value;
499    parent_id_field.value = pid;
500}
501
502<mt:ignore>
503/***
504 * Persists a copy of the current user cookie into the browser cookie stash.
505 */
506</mt:ignore>
507function mtSaveUser(f) {
508    // We can't reliably store the user cookie during a preview.
509    if (is_preview) return;
510
511    var u = mtGetUser();
512
513    if (f && (!u || u.is_anonymous)) {
514        if ( !u ) {
515            u = {};
516            u.is_authenticated = false;
517            u.can_comment = true;
518            u.is_author = false;
519            u.is_banned = false;
520            u.is_anonymous = true;
521            u.is_trusted = false;
522        }
523        if (f.author != undefined) u.name = f.author.value;
524        if (f.email != undefined) u.email = f.email.value;
525        if (f.url != undefined) u.url = f.url.value;
526    }
527
528    if (!u) return;
529
530    var cache_period = 60 * 60 * 1000; // 1 hour
531
532    // cache anonymous user info for a long period if the
533    // user has requested to be remembered
534    if (u.is_anonymous && f && f.bakecookie && f.bakecookie.checked)
535        cache_period = 365 * 24 * 60 * 60 * 1000;
536
537    var now = new Date();
538    mtFixDate(now);
539    now.setTime(now.getTime() + cache_period);
540
541    var cmtcookie = mtBakeUserCookie(u);
542    mtSetCookie(cookie_name, cmtcookie, now, blog_path, null,
543        location.protocol == 'https:');
544}
545
546<mt:ignore>
547/***
548 * Clears the blog-side user cookie.
549 */
550</mt:ignore>
551function mtClearUser() {
552    mtDeleteCookie(cookie_name, blog_path);
553}
554
555<mt:ignore>
556/***
557 * Sets a browser cookie.
558 */
559</mt:ignore>
560function mtSetCookie(name, value, expires, path, domain, secure) {
561    var curCookie = name + "=" + escape(value) +
562        (expires ? "; expires=" + expires.toGMTString() : "") +
563        (path ? "; path=" + path : "") +
564        (domain ? "; domain=" + domain : "") +
565        (secure ? "; secure" : "");
566    document.cookie = curCookie;
567}
568
569<mt:ignore>
570/***
571 * Retrieves a browser cookie.
572 */
573</mt:ignore>
574function mtGetCookie (name) {
575    var prefix = name + '=';
576    var c = document.cookie;
577    var cookieStartIndex = c.indexOf(prefix);
578    if (cookieStartIndex == -1)
579        return '';
580    var cookieEndIndex = c.indexOf(";", cookieStartIndex + prefix.length);
581    if (cookieEndIndex == -1)
582        cookieEndIndex = c.length;
583    return unescape(c.substring(cookieStartIndex + prefix.length, cookieEndIndex));
584}
585
586<mt:ignore>
587/***
588 * Deletes a browser cookie.
589 */
590</mt:ignore>
591function mtDeleteCookie (name, path, domain, secure) {
592    if (mtGetCookie(name))
593        document.cookie = name + "=" +
594            (path ? "; path=" + path : "") +
595            (domain ? "; domain=" + domain : "") +
596            (secure ? "; secure" : "") +
597            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
598}
599
600function mtFixDate(date) {
601    var skew = (new Date(0)).getTime();
602    if (skew > 0)
603        date.setTime(date.getTime() - skew);
604}
605
606<mt:ignore>
607/***
608 * Returns a XMLHttpRequest object (for Ajax operations).
609 */
610</mt:ignore>
611function mtGetXmlHttp() {
612    if ( !window.XMLHttpRequest ) {
613        window.XMLHttpRequest = function() {
614            var types = [
615                "Microsoft.XMLHTTP",
616                "MSXML2.XMLHTTP.5.0",
617                "MSXML2.XMLHTTP.4.0",
618                "MSXML2.XMLHTTP.3.0",
619                "MSXML2.XMLHTTP"
620            ];
621
622            for ( var i = 0; i < types.length; i++ ) {
623                try {
624                    return new ActiveXObject( types[ i ] );
625                } catch( e ) {}
626            }
627
628            return undefined;
629        };
630    }
631    if ( window.XMLHttpRequest )
632        return new XMLHttpRequest();
633}
634
635// BEGIN: fast browser onload init
636// Modifications by David Davis, DWD
637// Dean Edwards/Matthias Miller/John Resig
638// http://dean.edwards.name/weblog/2006/06/again/?full#comment5338
639
640function mtInit() {
641    // quit if this function has already been called
642    if (arguments.callee.done) return;
643
644    // flag this function so we don't do the same thing twice
645    arguments.callee.done = true;
646
647    // kill the timer
648    // DWD - check against window
649    if ( window._timer ) clearInterval(window._timer);
650
651    // DWD - fire the window onload now, and replace it
652    if ( window.onload && ( window.onload !== window.mtInit ) ) {
653        window.onload();
654        window.onload = function() {};
655    }
656}
657
658/* for Mozilla/Opera9 */
659if (document.addEventListener) {
660    document.addEventListener("DOMContentLoaded", mtInit, false);
661}
662
663/* for Internet Explorer */
664/*@cc_on @*/
665/*@if (@_win32)
666document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
667var script = document.getElementById("__ie_onload");
668script.onreadystatechange = function() {
669    if (this.readyState == "complete") {
670        mtInit(); // call the onload handler
671    }
672};
673/*@end @*/
674
675/* for Safari */
676if (/WebKit/i.test(navigator.userAgent)) { // sniff
677    _timer = setInterval(function() {
678        if (/loaded|complete/.test(document.readyState)) {
679            mtInit(); // call the onload handler
680        }
681    }, 10);
682}
683
684/* for other browsers */
685window.onload = mtInit;
686
687// END: fast browser onload init
688
689<mt:IfRegistrationAllowed>
690/***
691 * If request contains a '#_login' or '#_logout' hash, use this to
692 * also delete the blog-side user cookie, since we're coming back from
693 * a login, logout or edit profile operation.
694 */
695var clearCookie = ( window.location.hash && window.location.hash.match( /^#_log(in|out)/ ) ) ? true : false;
696if (clearCookie) {
697    // clear any logged in state
698    mtClearUser();
699    if (RegExp.$1 == 'in')
700        mtFetchUser();
701} else if (! mtGetUser()) {
702    // gather user info
703    mtFetchUser();
704}
705</mt:IfRegistrationAllowed>
Note: See TracBrowser for help on using the browser.